KMScreenShotMaskWindowController.swift 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. //
  2. // KMScreenShotMaskWindowController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by liujiajie on 2024/1/24.
  6. //
  7. import Cocoa
  8. let ktimeLabelWidthAndHeight: CGFloat = 100
  9. let kdefauletDelaytime: CGFloat = 5
  10. class KMScreenShotMaskWindowController: NSWindowController{
  11. var maskViewController: KMScreenShotMaskViewController!
  12. @IBOutlet var timeLabel: NSTextField!
  13. var fullScreenCallBack: captureScreenCallBack?
  14. var countDownTimer: Timer?
  15. var countDownSurplusTime: Int = 0
  16. var localMonitor: Any?
  17. var globalMonitor: Any?
  18. deinit {
  19. NotificationCenter.default.removeObserver(self)
  20. if (countDownTimer != nil){
  21. countDownTimer?.invalidate()
  22. countDownTimer = nil
  23. }
  24. }
  25. convenience init( handler: @escaping captureScreenCallBack) {
  26. self.init(windowNibName: "KMScreenShotMaskWindowController")
  27. self.window?.backgroundColor = .clear
  28. self.window?.isOpaque = false
  29. let screen = NSScreen.screens.first
  30. self.window?.setFrame(screen?.frame ?? .zero, display: false)
  31. self.window?.level = NSWindow.Level(Int(kCGOverlayWindowLevel)) //NSWindow.Level(rawValue: Int(kCGOverlayWindowLevel))
  32. self.maskViewController = KMScreenShotMaskViewController(callB: handler)
  33. self.maskViewController.view.frame = self.window?.frame ?? .zero
  34. self.window?.contentView!.addSubview(self.maskViewController.view)
  35. self.timeLabel.isHidden = true
  36. }
  37. convenience init(fullScreenShot delayTime: Int, completeHandler: @escaping captureScreenCallBack) {
  38. self.init(windowNibName: "KMScreenShotMaskWindowController")
  39. self.countDownSurplusTime = delayTime
  40. self.window?.backgroundColor = NSColor.black
  41. if let screen = NSScreen.screens.first {
  42. 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)
  43. }
  44. self.window?.level = NSWindow.Level(Int(kCGOverlayWindowLevel))
  45. self.timeLabel.font = NSFont.systemFont(ofSize: 100)
  46. self.timeLabel.textColor = NSColor.white
  47. self.window?.alphaValue = 0.3
  48. self.timeLabel.integerValue = self.countDownSurplusTime
  49. self.timeLabel.sizeToFit()
  50. 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)
  51. if delayTime == 0 {
  52. self.window?.setIsVisible(false)
  53. DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
  54. let ima = KMScreenShotHandler.fullScreenShot()
  55. completeHandler(ima)
  56. }
  57. } else {
  58. self.timeLabel.isHidden = false
  59. let sel = NSSelectorFromString("countTimer_Method:")
  60. self.countDownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: sel, userInfo: nil, repeats: true)
  61. RunLoop.current.add(self.countDownTimer!, forMode: .common)
  62. self.fullScreenCallBack = completeHandler
  63. if self.localMonitor == nil {
  64. let mask: NSEvent.EventTypeMask = [.leftMouseDown, .keyDown]
  65. self.localMonitor = NSEvent.addLocalMonitorForEvents(matching: mask, handler: { (event) -> NSEvent? in
  66. if event.type == .keyDown {
  67. if event.keyCode == 53 {
  68. self.endFullScreenShot()
  69. self.fullScreenCallBack?(nil)
  70. }
  71. }
  72. return nil
  73. })
  74. }
  75. if self.globalMonitor == nil {
  76. self.globalMonitor = NSEvent.addGlobalMonitorForEvents(matching: .keyDown, handler: { (event) in
  77. if event.type == .keyDown {
  78. if event.keyCode == 53 {
  79. self.endFullScreenShot()
  80. self.fullScreenCallBack?(nil)
  81. }
  82. }
  83. })
  84. }
  85. }
  86. NotificationCenter.default.addObserver(self, selector: #selector(cancelCurrentCapturingAction(notification:)), name: NSNotification.Name(KMCancelCurrentCapturingActionNotification), object: nil)
  87. }
  88. @objc func cancelCurrentCapturingAction(notification: Notification) {
  89. DispatchQueue.main.async {
  90. self.endFullScreenShot()
  91. }
  92. }
  93. func endFullScreenShot() {
  94. self.countDownTimer?.invalidate()
  95. self.window?.setIsVisible(false)
  96. NSEvent.removeMonitor(self.localMonitor as Any)
  97. self.localMonitor = nil
  98. NSEvent.removeMonitor(self.globalMonitor as Any)
  99. self.globalMonitor = nil
  100. }
  101. @objc func countTimer_Method(_ sender: Any) {
  102. self.countDownSurplusTime -= 1
  103. self.timeLabel.integerValue = self.countDownSurplusTime
  104. if self.countDownSurplusTime == 0 {
  105. self.endFullScreenShot()
  106. DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
  107. let ima = KMScreenShotHandler.fullScreenShot()
  108. self.fullScreenCallBack?(ima)
  109. }
  110. }
  111. }
  112. override func windowDidLoad() {
  113. super.windowDidLoad()
  114. }
  115. func beginImageCapture(_ isCaptureWindow: Bool) { self.maskViewController.beginImageCapture(isCaptureWindow)
  116. if isCaptureWindow {
  117. let cursor = NSCursor(image: NSImage(named: "cameraCursor") ?? NSImage(), hotSpot: NSPoint(x: 0, y: 0))
  118. cursor.set()
  119. self.showScreenShotHint(NSLocalizedString("Move the camera over the window you want to capture.", comment: ""))
  120. } else {
  121. NSCursor.crosshair.set()
  122. self.showScreenShotHint(NSLocalizedString("Drag the crosshair over the area you want to capture.", comment: ""))
  123. }
  124. }
  125. func showScreenShotHint(_ hintMsg: String) {
  126. let topBottomGap: CGFloat = 10
  127. let texfield = NSTextField()
  128. texfield.isBordered = false
  129. texfield.font = NSFont.systemFont(ofSize: 20)
  130. texfield.textColor = NSColor.white
  131. texfield.backgroundColor = NSColor.clear
  132. texfield.stringValue = hintMsg
  133. texfield.sizeToFit()
  134. let hintContainer = NSView()
  135. hintContainer.wantsLayer = true
  136. hintContainer.layer?.backgroundColor = NSColor.black.cgColor
  137. hintContainer.addSubview(texfield)
  138. var containerFrame = hintContainer.frame
  139. containerFrame.size.height = texfield.frame.size.height + topBottomGap * 2
  140. containerFrame.size.width = texfield.frame.size.width + containerFrame.size.height
  141. containerFrame.origin.x = ((self.window?.contentView?.frame.size.width ?? 0) - containerFrame.size.width) / 2
  142. containerFrame.origin.y = ((self.window?.contentView?.frame.size.height ?? 0) - containerFrame.size.height) / 2
  143. hintContainer.frame = containerFrame
  144. var textfieldFrame = texfield.frame
  145. textfieldFrame.origin.x = (containerFrame.size.width - texfield.frame.size.width) / 2
  146. textfieldFrame.origin.y = topBottomGap
  147. texfield.frame = textfieldFrame
  148. hintContainer.layer?.cornerRadius = containerFrame.size.height / 2
  149. self.window?.contentView?.addSubview(hintContainer)
  150. NSAnimationContext.runAnimationGroup({ (context) in
  151. context.duration = 3
  152. hintContainer.animator().alphaValue = 0.0
  153. }, completionHandler: {
  154. })
  155. }
  156. }