// // KMScreenShotMaskWindowController.swift // PDF Reader Pro // // Created by liujiajie on 2024/1/24. // import Cocoa let ktimeLabelWidthAndHeight: CGFloat = 100 let kdefauletDelaytime: CGFloat = 5 class KMScreenShotMaskWindowController: NSWindowController{ var maskViewController: KMScreenShotMaskViewController! @IBOutlet var timeLabel: NSTextField! var fullScreenCallBack: captureScreenCallBack? var countDownTimer: Timer? var countDownSurplusTime: Int = 0 var localMonitor: Any? var globalMonitor: Any? deinit { NotificationCenter.default.removeObserver(self) if (countDownTimer != nil){ countDownTimer?.invalidate() countDownTimer = nil } } convenience init( handler: @escaping captureScreenCallBack) { self.init(windowNibName: "KMScreenShotMaskWindowController") self.window?.backgroundColor = .clear self.window?.isOpaque = false let screen = NSScreen.screens.first self.window?.setFrame(screen?.frame ?? .zero, display: false) self.window?.level = NSWindow.Level(Int(kCGOverlayWindowLevel)) //NSWindow.Level(rawValue: Int(kCGOverlayWindowLevel)) self.maskViewController = KMScreenShotMaskViewController(callB: handler) self.maskViewController.view.frame = self.window?.frame ?? .zero self.window?.contentView!.addSubview(self.maskViewController.view) self.timeLabel.isHidden = true } convenience init(fullScreenShot delayTime: Int, completeHandler: @escaping captureScreenCallBack) { self.init(windowNibName: "KMScreenShotMaskWindowController") self.countDownSurplusTime = delayTime self.window?.backgroundColor = NSColor.black if let screen = NSScreen.screens.first { self.window?.setFrame(NSRect(x: screen.frame.size.width/2 - ktimeLabelWidthAndHeight/2, y: screen.frame.size.height/2 - ktimeLabelWidthAndHeight/2, width: ktimeLabelWidthAndHeight, height: ktimeLabelWidthAndHeight), display: false) } self.window?.level = NSWindow.Level(Int(kCGOverlayWindowLevel)) self.timeLabel.font = NSFont.systemFont(ofSize: 100) self.timeLabel.textColor = NSColor.white self.window?.alphaValue = 0.3 self.timeLabel.integerValue = self.countDownSurplusTime self.timeLabel.sizeToFit() self.timeLabel.frame = NSRect(x: (ktimeLabelWidthAndHeight - self.timeLabel.frame.size.width)/2, y: (ktimeLabelWidthAndHeight - self.timeLabel.frame.size.height)/2, width: self.timeLabel.frame.size.width, height: self.timeLabel.frame.size.height) if delayTime == 0 { self.window?.setIsVisible(false) DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { let ima = KMScreenShotHandler.fullScreenShot() completeHandler(ima) } } else { self.timeLabel.isHidden = false let sel = NSSelectorFromString("countTimer_Method:") self.countDownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: sel, userInfo: nil, repeats: true) RunLoop.current.add(self.countDownTimer!, forMode: .common) self.fullScreenCallBack = completeHandler if self.localMonitor == nil { let mask: NSEvent.EventTypeMask = [.leftMouseDown, .keyDown] self.localMonitor = NSEvent.addLocalMonitorForEvents(matching: mask, handler: { (event) -> NSEvent? in if event.type == .keyDown { if event.keyCode == 53 { self.endFullScreenShot() self.fullScreenCallBack?(nil) } } return nil }) } if self.globalMonitor == nil { self.globalMonitor = NSEvent.addGlobalMonitorForEvents(matching: .keyDown, handler: { (event) in if event.type == .keyDown { if event.keyCode == 53 { self.endFullScreenShot() self.fullScreenCallBack?(nil) } } }) } } NotificationCenter.default.addObserver(self, selector: #selector(cancelCurrentCapturingAction(notification:)), name: NSNotification.Name(KMCancelCurrentCapturingActionNotification), object: nil) } @objc func cancelCurrentCapturingAction(notification: Notification) { DispatchQueue.main.async { self.endFullScreenShot() } } func endFullScreenShot() { self.countDownTimer?.invalidate() self.window?.setIsVisible(false) NSEvent.removeMonitor(self.localMonitor as Any) self.localMonitor = nil NSEvent.removeMonitor(self.globalMonitor as Any) self.globalMonitor = nil } @objc func countTimer_Method(_ sender: Any) { self.countDownSurplusTime -= 1 self.timeLabel.integerValue = self.countDownSurplusTime if self.countDownSurplusTime == 0 { self.endFullScreenShot() DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { let ima = KMScreenShotHandler.fullScreenShot() self.fullScreenCallBack?(ima) } } } override func windowDidLoad() { super.windowDidLoad() } func beginImageCapture(_ isCaptureWindow: Bool) { self.maskViewController.beginImageCapture(isCaptureWindow) if isCaptureWindow { let cursor = NSCursor(image: NSImage(named: "cameraCursor") ?? NSImage(), hotSpot: NSPoint(x: 0, y: 0)) cursor.set() self.showScreenShotHint(NSLocalizedString("Move the camera over the window you want to capture.", comment: "")) } else { NSCursor.crosshair.set() self.showScreenShotHint(NSLocalizedString("Drag the crosshair over the area you want to capture.", comment: "")) } } func showScreenShotHint(_ hintMsg: String) { let topBottomGap: CGFloat = 10 let texfield = NSTextField() texfield.isBordered = false texfield.font = NSFont.systemFont(ofSize: 20) texfield.textColor = NSColor.white texfield.backgroundColor = NSColor.clear texfield.stringValue = hintMsg texfield.sizeToFit() let hintContainer = NSView() hintContainer.wantsLayer = true hintContainer.layer?.backgroundColor = NSColor.black.cgColor hintContainer.addSubview(texfield) var containerFrame = hintContainer.frame containerFrame.size.height = texfield.frame.size.height + topBottomGap * 2 containerFrame.size.width = texfield.frame.size.width + containerFrame.size.height containerFrame.origin.x = ((self.window?.contentView?.frame.size.width ?? 0) - containerFrame.size.width) / 2 containerFrame.origin.y = ((self.window?.contentView?.frame.size.height ?? 0) - containerFrame.size.height) / 2 hintContainer.frame = containerFrame var textfieldFrame = texfield.frame textfieldFrame.origin.x = (containerFrame.size.width - texfield.frame.size.width) / 2 textfieldFrame.origin.y = topBottomGap texfield.frame = textfieldFrame hintContainer.layer?.cornerRadius = containerFrame.size.height / 2 self.window?.contentView?.addSubview(hintContainer) NSAnimationContext.runAnimationGroup({ (context) in context.duration = 3 hintContainer.animator().alphaValue = 0.0 }, completionHandler: { }) } }