KMScreenShotMaskView.swift 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. //
  2. // KMScreenShotMaskView.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by liujiajie on 2024/1/24.
  6. //
  7. import Foundation
  8. typealias captureScreenCallBack = (_ ima: NSImage?) -> ()
  9. typealias updateFrameCallBack = (_ rect: NSRect) -> ()
  10. typealias detachEventInEditViewCallBack = (_ event: NSEvent) -> ()
  11. @objc enum KMScreenShotRectEditViewPositionType: Int {
  12. case None = 0
  13. case Top
  14. case Left
  15. case Bottom
  16. case Right
  17. case LeftUp
  18. case LeftLower
  19. case RightUp
  20. case RightLower
  21. }
  22. let KMScreenLineLength: CGFloat = 4//线长
  23. let KMScreenSpaceLength: CGFloat = 1//空格长
  24. let KMScreenLineWidth: CGFloat = 2//线宽
  25. let KMScreenSizeLableFont: CGFloat = 12//尺寸字体大小
  26. let KMScreenDetectLength: CGFloat = 4//选取rect之后边界线探测区域
  27. let KMScreenHoleMinWidthAndHeight: CGFloat = 40
  28. class KMScreenShotMaskView: NSView{
  29. var callBack: captureScreenCallBack?
  30. var frameCallBack: updateFrameCallBack?
  31. var detachCallBack: detachEventInEditViewCallBack?
  32. var holeDragMode = false
  33. var borderFrame: NSRect = .zero
  34. var iswindowCapture = false
  35. var topView: NSView!
  36. var leftView: NSView!
  37. var bottomView: NSView!
  38. var rightView: NSView!
  39. var windowMaskView: NSView!
  40. var sizeLabel: NSTextField!
  41. var localMonitor: Any?
  42. var globalMonitor: Any?
  43. var dragStartPoint: CGPoint = .zero
  44. var dragLastPoint: CGPoint = .zero
  45. var editingRect = false
  46. var positionType: KMScreenShotRectEditViewPositionType = .None
  47. var needborderFlag = false
  48. var pullXGap: Float = 0
  49. var pullYGap: Float = 0
  50. override func awakeFromNib() {
  51. super.awakeFromNib()
  52. topView = NSView(frame: CGRect.zero)
  53. leftView = NSView(frame: CGRect.zero)
  54. bottomView = NSView(frame: CGRect.zero)
  55. rightView = NSView(frame: CGRect.zero)
  56. windowMaskView = NSView(frame: CGRect.zero)
  57. sizeLabel = NSTextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
  58. sizeLabel.font = NSFont.systemFont(ofSize: CGFloat(KMScreenSizeLableFont))
  59. sizeLabel.textColor = NSColor.black
  60. sizeLabel.backgroundColor = NSColor.clear
  61. sizeLabel.isEnabled = false
  62. sizeLabel.isSelectable = false
  63. sizeLabel.isBordered = false
  64. sizeLabel.alignment = .right
  65. addSubview(topView)
  66. addSubview(leftView)
  67. addSubview(bottomView)
  68. addSubview(rightView)
  69. addSubview(sizeLabel)
  70. addSubview(windowMaskView)
  71. topView.wantsLayer = true
  72. leftView.wantsLayer = true
  73. bottomView.wantsLayer = true
  74. rightView.wantsLayer = true
  75. windowMaskView.wantsLayer = true
  76. topView.layer?.backgroundColor = NSColor.black.cgColor
  77. leftView.layer?.backgroundColor = NSColor.black.cgColor
  78. bottomView.layer?.backgroundColor = NSColor.black.cgColor
  79. rightView.layer?.backgroundColor = NSColor.black.cgColor
  80. windowMaskView.layer?.backgroundColor = NSColor.clear.cgColor
  81. topView.alphaValue = 0.3
  82. leftView.alphaValue = 0.3
  83. bottomView.alphaValue = 0.3
  84. rightView.alphaValue = 0.3
  85. needborderFlag = true
  86. }
  87. override func draw(_ dirtyRect: NSRect) {
  88. super.draw(dirtyRect)
  89. if !needborderFlag {
  90. return
  91. }
  92. if !editingRect {
  93. return
  94. }
  95. guard let myContext = NSGraphicsContext.current?.cgContext else {
  96. return
  97. }
  98. if iswindowCapture {
  99. return
  100. }
  101. myContext.setFillColor(NSColor.red.cgColor)
  102. myContext.addArc(center: CGPoint(x: borderFrame.minX, y: borderFrame.minY),
  103. radius: CGFloat(KMScreenDetectLength),
  104. startAngle: CGFloat(0),
  105. endAngle: CGFloat(Double.pi * 2),
  106. clockwise: true)
  107. myContext.drawPath(using: .fill)
  108. myContext.addArc(center: CGPoint(x: borderFrame.midX, y: borderFrame.minY),
  109. radius: CGFloat(KMScreenDetectLength),
  110. startAngle: CGFloat(0),
  111. endAngle: CGFloat(Double.pi * 2),
  112. clockwise: true)
  113. myContext.drawPath(using: .fill)
  114. myContext.addArc(center: CGPoint(x: borderFrame.maxX, y: borderFrame.minY),
  115. radius: CGFloat(KMScreenDetectLength),
  116. startAngle: CGFloat(0),
  117. endAngle: CGFloat(Double.pi * 2),
  118. clockwise: true)
  119. myContext.drawPath(using: .fill)
  120. myContext.addArc(center: CGPoint(x: borderFrame.maxX, y: borderFrame.midY),
  121. radius: CGFloat(KMScreenDetectLength),
  122. startAngle: CGFloat(0),
  123. endAngle: CGFloat(Double.pi * 2),
  124. clockwise: true)
  125. myContext.drawPath(using: .fill)
  126. myContext.addArc(center: CGPoint(x: borderFrame.maxX, y: borderFrame.maxY),
  127. radius: CGFloat(KMScreenDetectLength),
  128. startAngle: CGFloat(0),
  129. endAngle: CGFloat(Double.pi * 2),
  130. clockwise: true)
  131. myContext.drawPath(using: .fill)
  132. myContext.addArc(center: CGPoint(x: borderFrame.midX, y: borderFrame.maxY),
  133. radius: CGFloat(KMScreenDetectLength),
  134. startAngle: CGFloat(0),
  135. endAngle: CGFloat(Double.pi * 2),
  136. clockwise: true)
  137. myContext.drawPath(using: .fill)
  138. myContext.addArc(center: CGPoint(x: borderFrame.minX, y: borderFrame.maxY),
  139. radius: CGFloat(KMScreenDetectLength),
  140. startAngle: CGFloat(0),
  141. endAngle: CGFloat(Double.pi * 2),
  142. clockwise: true)
  143. myContext.drawPath(using: .fill)
  144. myContext.addArc(center: CGPoint(x: borderFrame.minX, y: borderFrame.midY),
  145. radius: CGFloat(KMScreenDetectLength),
  146. startAngle: CGFloat(0),
  147. endAngle: CGFloat(Double.pi * 2),
  148. clockwise: true)
  149. myContext.drawPath(using: .fill)
  150. }
  151. func updateSubViewFrame(withHoleRect holeRect: NSRect) {
  152. let topViewOriginalX: CGFloat = 0
  153. let topViewOriginalY: CGFloat = min(holeRect.maxY, frame.maxY)
  154. let topViewWidth = frame.size.width
  155. let topViewHeight = holeRect.maxY > frame.maxY ? 0 : frame.maxY - holeRect.maxY
  156. topView.frame = CGRect(x: topViewOriginalX, y: topViewOriginalY, width: topViewWidth, height: topViewHeight)
  157. let originalY = holeRect.origin.y
  158. var leftRightHeight: CGFloat
  159. if originalY > 0 {
  160. leftRightHeight = holeRect.size.height
  161. } else {
  162. leftRightHeight = holeRect.size.height - abs(holeRect.origin.y)
  163. }
  164. let leftViewOriginalX: CGFloat = 0
  165. let leftViewOriginalY: CGFloat = max(holeRect.minY, 0)
  166. let leftViewWidth = max(0, holeRect.minX)
  167. let leftViewHeight = leftRightHeight
  168. leftView.frame = CGRect(x: leftViewOriginalX, y: leftViewOriginalY, width: leftViewWidth, height: leftViewHeight)
  169. let bottomViewOriginalX: CGFloat = 0
  170. let bottomViewOriginalY: CGFloat = 0
  171. let bottomViewWidth = frame.size.width
  172. let bottomViewHeight = max(holeRect.minY, 0)
  173. bottomView.frame = CGRect(x: bottomViewOriginalX, y: bottomViewOriginalY, width: bottomViewWidth, height: bottomViewHeight)
  174. let rightViewOriginalX = min(holeRect.maxX, frame.maxX)
  175. let rightViewOriginalY = max(holeRect.minY, 0)
  176. let rightViewWidth = holeRect.maxX > frame.maxX ? 0 : frame.maxX - holeRect.maxX
  177. let rightViewHeight = leftRightHeight
  178. rightView.frame = CGRect(x: rightViewOriginalX, y: rightViewOriginalY, width: rightViewWidth, height: rightViewHeight)
  179. }
  180. func windowForEvent(_ event: NSEvent) -> CGWindowID {
  181. return CGWindowID(NSWindow.windowNumber(at: KMScreenShotHandler.screenPosition(for: event), belowWindowWithWindowNumber: self.window!.windowNumber))
  182. }
  183. func beginEditSelectArea(_ editFrame: NSRect) {
  184. self.editingRect = true
  185. }
  186. func changeCursorTypeWithEvent(_ result: NSEvent) {
  187. let point = KMScreenShotHandler.screenPosition(for: result)
  188. self.positionType = self.calulateCurrentPositionType(point)
  189. switch self.positionType {
  190. case .None:
  191. NSCursor.arrow.set()
  192. case .Top:
  193. NSCursor.resizeUpDown.set()
  194. case .Left:
  195. NSCursor.resizeLeftRight.set()
  196. case .Bottom:
  197. NSCursor.resizeUpDown.set()
  198. case .Right:
  199. NSCursor.resizeLeftRight.set()
  200. case .LeftUp:
  201. NSCursor.crosshair.set()
  202. case .LeftLower:
  203. NSCursor.crosshair.set()
  204. case .RightUp:
  205. NSCursor.crosshair.set()
  206. case .RightLower:
  207. NSCursor.crosshair.set()
  208. default:
  209. break
  210. }
  211. }
  212. func calulateCurrentPositionType(_ point: NSPoint) -> KMScreenShotRectEditViewPositionType {
  213. var type: KMScreenShotRectEditViewPositionType = .None
  214. let topYMin = NSMaxY(self.borderFrame) - CGFloat(KMScreenDetectLength)
  215. let topYMax = NSMaxY(self.borderFrame) + CGFloat(KMScreenDetectLength)
  216. let leftXMin = NSMinX(self.borderFrame) - CGFloat(KMScreenDetectLength)
  217. let leftXMax = NSMinX(self.borderFrame) + CGFloat(KMScreenDetectLength)
  218. let bottomYMin = NSMinY(self.borderFrame) - CGFloat(KMScreenDetectLength)
  219. let bottomYMax = NSMinY(self.borderFrame) + CGFloat(KMScreenDetectLength)
  220. let rightXMin = NSMaxX(self.borderFrame) - CGFloat(KMScreenDetectLength)
  221. let rightXMax = NSMaxX(self.borderFrame) + CGFloat(KMScreenDetectLength)
  222. if point.x <= leftXMax && point.x >= leftXMin {
  223. if point.y <= topYMax && point.y >= topYMin {
  224. type = .LeftUp
  225. } else if point.y <= bottomYMax && point.y >= bottomYMin {
  226. type = .LeftLower
  227. } else if point.y < topYMin && point.y > bottomYMax {
  228. type = .Left
  229. }
  230. } else if point.x <= rightXMax && point.x >= rightXMin {
  231. if point.y <= topYMax && point.y >= topYMin {
  232. type = .RightUp
  233. } else if point.y <= bottomYMax && point.y >= bottomYMin {
  234. type = .RightLower
  235. } else if point.y > bottomYMax && point.y < topYMin {
  236. type = .Right
  237. }
  238. } else if point.x > leftXMax && point.x < rightXMin {
  239. if point.y > bottomYMin && point.y < bottomYMax {
  240. type = .Bottom
  241. } else if point.y > topYMin && point.y < topYMax {
  242. type = .Top
  243. } else {
  244. type = .None
  245. }
  246. } else {
  247. type = .None
  248. }
  249. return type
  250. }
  251. func rectEditDrag(event: NSEvent) {
  252. let newPoint = KMScreenShotHandler.screenPosition(for: event)
  253. switch self.positionType {
  254. case .None:
  255. break
  256. case .Top:
  257. let changeTop = newPoint.y - self.borderFrame.maxY
  258. self.borderFrame = CGRect(x: self.borderFrame.origin.x, y: self.borderFrame.origin.y, width: self.borderFrame.size.width, height: CGFloat(self.borderFrame.size.height + CGFloat(changeTop) > CGFloat(KMScreenHoleMinWidthAndHeight) ? self.borderFrame.size.height + CGFloat(changeTop) : CGFloat(KMScreenHoleMinWidthAndHeight)))
  259. case .Left:
  260. let changeLeft = newPoint.x - self.borderFrame.minX
  261. self.borderFrame = CGRect(x: self.borderFrame.origin.x + changeLeft < self.borderFrame.maxX - CGFloat(KMScreenHoleMinWidthAndHeight) ? self.borderFrame.origin.x + changeLeft : self.borderFrame.maxX - CGFloat(KMScreenHoleMinWidthAndHeight), y: self.borderFrame.origin.y, width: self.borderFrame.size.width - changeLeft > CGFloat(KMScreenHoleMinWidthAndHeight) ? self.borderFrame.size.width - changeLeft : KMScreenHoleMinWidthAndHeight, height: self.borderFrame.size.height)
  262. case .Bottom:
  263. let changeBottom = newPoint.y - self.borderFrame.minY
  264. self.borderFrame = CGRect(x: self.borderFrame.origin.x, y: self.borderFrame.origin.y + changeBottom <= self.borderFrame.maxY - KMScreenHoleMinWidthAndHeight ? self.borderFrame.origin.y + changeBottom : self.borderFrame.maxY - KMScreenHoleMinWidthAndHeight, width: self.borderFrame.size.width, height: self.borderFrame.size.height - changeBottom > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.height - changeBottom : KMScreenHoleMinWidthAndHeight)
  265. case .Right:
  266. let changeRight = newPoint.x - self.borderFrame.maxX
  267. self.borderFrame = CGRect(x: self.borderFrame.origin.x, y: self.borderFrame.origin.y, width: self.borderFrame.size.width + changeRight > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.width + changeRight : KMScreenHoleMinWidthAndHeight, height: self.borderFrame.size.height)
  268. case .LeftUp:
  269. let changeX = newPoint.x - self.borderFrame.minX
  270. let changeY = newPoint.y - self.borderFrame.maxY
  271. self.borderFrame = CGRect(x: self.borderFrame.origin.x + changeX <= self.borderFrame.maxX - KMScreenHoleMinWidthAndHeight ? self.borderFrame.origin.x + changeX : self.borderFrame.maxX - KMScreenHoleMinWidthAndHeight, y: self.borderFrame.origin.y, width: self.borderFrame.size.width - changeX > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.width - changeX : KMScreenHoleMinWidthAndHeight, height: self.borderFrame.size.height + changeY > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.height + changeY : KMScreenHoleMinWidthAndHeight)
  272. case .LeftLower:
  273. let changeX = newPoint.x - self.borderFrame.minX
  274. let changeY = newPoint.y - self.borderFrame.minY
  275. self.borderFrame = CGRect(x: self.borderFrame.origin.x + changeX <= self.borderFrame.maxX - KMScreenHoleMinWidthAndHeight ? self.borderFrame.origin.x + changeX : self.borderFrame.maxX - KMScreenHoleMinWidthAndHeight, y: self.borderFrame.origin.y + changeY <= self.borderFrame.maxY - KMScreenHoleMinWidthAndHeight ? self.borderFrame.origin.y + changeY : self.borderFrame.maxY - KMScreenHoleMinWidthAndHeight, width: self.borderFrame.size.width - changeX > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.width - changeX : KMScreenHoleMinWidthAndHeight, height: self.borderFrame.size.height - changeY > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.height - changeY : KMScreenHoleMinWidthAndHeight)
  276. case .RightUp:
  277. let changeX = newPoint.x - self.borderFrame.maxX
  278. let changeY = newPoint.y - self.borderFrame.maxY
  279. self.borderFrame = CGRect(x: self.borderFrame.origin.x, y: self.borderFrame.origin.y, width: self.borderFrame.size.width + changeX > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.width + changeX : KMScreenHoleMinWidthAndHeight, height: self.borderFrame.size.height + changeY > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.height + changeY : KMScreenHoleMinWidthAndHeight)
  280. case .RightLower:
  281. let changeX = newPoint.x - self.borderFrame.maxX
  282. let changeY = newPoint.y - self.borderFrame.minY
  283. self.borderFrame = CGRect(x: self.borderFrame.origin.x, y: self.borderFrame.origin.y + changeY <= self.borderFrame.maxY - KMScreenHoleMinWidthAndHeight ? self.borderFrame.origin.y + changeY : self.borderFrame.maxY - KMScreenHoleMinWidthAndHeight, width: self.borderFrame.size.width + changeX > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.width + changeX : KMScreenHoleMinWidthAndHeight , height: self.borderFrame.size.height - changeY > KMScreenHoleMinWidthAndHeight ? self.borderFrame.size.height - changeY : KMScreenHoleMinWidthAndHeight)
  284. default:
  285. break
  286. }
  287. self.updateHoleWithRect(holeRect: self.borderFrame)
  288. self.updateSizeLabelWithRect(rect: self.borderFrame, dragPoint: CGPoint(x: self.borderFrame.maxX, y: self.borderFrame.minY))
  289. if let frameCallBack = self.frameCallBack {
  290. frameCallBack(self.borderFrame)
  291. }
  292. }
  293. func updateHoleWithRect(holeRect: CGRect) {
  294. self.borderFrame = holeRect
  295. self.updateSubViewFrameWithHoleRect(holeRect: holeRect)
  296. // self.setNeedsDisplay(true)
  297. self.needsDisplay = true
  298. }
  299. func updateSizeLabelWithRect(rect: CGRect, dragPoint: CGPoint) {
  300. let labelString = "\(Int(rect.size.width)) * \(Int(rect.size.height))"
  301. self.sizeLabel.stringValue = labelString
  302. self.sizeLabel.sizeToFit()
  303. if dragPoint.x == rect.maxX {
  304. self.sizeLabel.frame = CGRect(x: dragPoint.x, y: dragPoint.y - self.sizeLabel.frame.size.height, width: self.sizeLabel.frame.size.width, height: self.sizeLabel.frame.size.height)
  305. } else if dragPoint.x == rect.minX {
  306. self.sizeLabel.frame = CGRect(x: dragPoint.x - self.sizeLabel.frame.size.width, y: dragPoint.y - self.sizeLabel.frame.size.height, width: self.sizeLabel.frame.size.width, height: self.sizeLabel.frame.size.height)
  307. }
  308. }
  309. func updateSubViewFrameWithHoleRect(holeRect: NSRect) {
  310. let topViewOriginalX: CGFloat = 0
  311. let topViewOriginalY: CGFloat = min(holeRect.maxY, self.frame.maxY)
  312. let topViewWidth = self.frame.size.width
  313. let topViewHeight = holeRect.maxY > self.frame.maxY ? 0 : self.frame.maxY - holeRect.maxY
  314. self.topView.frame = CGRect(x: topViewOriginalX, y: topViewOriginalY, width: topViewWidth, height: topViewHeight)
  315. let originalY = holeRect.origin.y
  316. var leftRightHeight: CGFloat
  317. if originalY > 0 {
  318. leftRightHeight = holeRect.size.height
  319. } else {
  320. leftRightHeight = holeRect.size.height - abs(holeRect.origin.y)
  321. }
  322. let leftViewOriginalX: CGFloat = 0
  323. let leftViewOriginalY: CGFloat = max(holeRect.minY, 0)
  324. let leftViewWidth = max(0, holeRect.minX)
  325. let leftViewHeight = leftRightHeight
  326. self.leftView.frame = CGRect(x: leftViewOriginalX, y: leftViewOriginalY, width: leftViewWidth, height: leftViewHeight)
  327. let bottomViewOriginalX: CGFloat = 0
  328. let bottomViewOriginalY: CGFloat = 0
  329. let bottomViewWidth = self.frame.size.width
  330. let bottomViewHeight = max(holeRect.minY, 0)
  331. self.bottomView.frame = CGRect(x: bottomViewOriginalX, y: bottomViewOriginalY, width: bottomViewWidth, height: bottomViewHeight)
  332. let rightViewOriginalX = min(holeRect.maxX, self.frame.maxX)
  333. let rightViewOriginalY = max(holeRect.minY, 0)
  334. let rightViewWidth = holeRect.maxX > self.frame.maxX ? 0 : self.frame.maxX - holeRect.maxX
  335. let rightViewHeight = leftRightHeight
  336. self.rightView.frame = CGRect(x: rightViewOriginalX, y: rightViewOriginalY, width: rightViewWidth, height: rightViewHeight)
  337. }
  338. func updateholeSize(newSize: CGSize) {
  339. updateHoleWithRect(holeRect: NSRect(x: self.borderFrame.origin.x, y: self.borderFrame.origin.y, width: newSize.width, height: newSize.height))
  340. updateSizeLabelWithRect(rect: NSRect(x: self.borderFrame.origin.x, y: self.borderFrame.origin.y, width: newSize.width, height: newSize.height), dragPoint: CGPoint(x: self.borderFrame.maxX, y: self.borderFrame.minY))
  341. }
  342. func beginImageCapture(isCaptureWindow: Bool) {
  343. self.window?.setIsVisible(true)
  344. self.sizeLabel.isHidden = isCaptureWindow
  345. initMonitor(isCaptureWindow: isCaptureWindow)
  346. }
  347. func setUIPrepare(isWindowCapture: Bool) {
  348. if isWindowCapture {
  349. topView.layer?.backgroundColor = NSColor.clear.cgColor
  350. leftView.layer?.backgroundColor = NSColor.clear.cgColor
  351. bottomView.layer?.backgroundColor = NSColor.clear.cgColor
  352. rightView.layer?.backgroundColor = NSColor.clear.cgColor
  353. windowMaskView.layer?.backgroundColor = NSColor.black.cgColor
  354. windowMaskView.alphaValue = 0.3
  355. } else {
  356. topView.layer?.backgroundColor = NSColor.black.cgColor
  357. topView.alphaValue = 0.3
  358. leftView.layer?.backgroundColor = NSColor.black.cgColor
  359. leftView.alphaValue = 0.3
  360. bottomView.layer?.backgroundColor = NSColor.black.cgColor
  361. bottomView.alphaValue = 0.3
  362. rightView.layer?.backgroundColor = NSColor.black.cgColor
  363. rightView.alphaValue = 0.3
  364. }
  365. }
  366. func endImageCapture() {
  367. resignMonitor()
  368. borderFrame = CGRect.zero
  369. updateHoleWithRect(holeRect: CGRect.zero)
  370. self.needsDisplay = true
  371. editingRect = false
  372. holeDragMode = false
  373. if NSApp.windows.contains(self.window!) {
  374. self.window?.setIsVisible(false)
  375. }
  376. sizeLabel.isHidden = true
  377. needborderFlag = true
  378. NSCursor.arrow.set()
  379. }
  380. func resignMonitor() {
  381. NSEvent.removeMonitor(localMonitor as Any)
  382. NSEvent.removeMonitor(globalMonitor as Any)
  383. localMonitor = nil
  384. globalMonitor = nil
  385. }
  386. func initMonitor(isCaptureWindow: Bool) {
  387. self.iswindowCapture = isCaptureWindow
  388. var mask: NSEvent.EventTypeMask
  389. if isCaptureWindow {
  390. mask = [NSEvent.EventTypeMask.mouseMoved, NSEvent.EventTypeMask.leftMouseDown, NSEvent.EventTypeMask.keyDown]
  391. } else {
  392. mask = [NSEvent.EventTypeMask.mouseMoved, NSEvent.EventTypeMask.leftMouseDown, NSEvent.EventTypeMask.leftMouseDragged, NSEvent.EventTypeMask.leftMouseUp, NSEvent.EventTypeMask.keyDown]
  393. self.updateHoleWithRect(holeRect: .zero)
  394. }
  395. self.setUIPrepare(isWindowCapture: isCaptureWindow)
  396. if self.localMonitor == nil {
  397. self.localMonitor = NSEvent.addLocalMonitorForEvents(matching: mask) { (result) -> NSEvent? in
  398. if isCaptureWindow {
  399. let windowID: CGWindowID = self.windowForEvent(result)
  400. if result.type == .leftMouseDown {
  401. let image = KMScreenShotHandler.appointWindowScreenShot(withWindowID: windowID)
  402. self.callBack?(image ?? NSImage())
  403. self.endImageCapture()
  404. } else if result.type == .mouseMoved {
  405. let rect = KMOCTool.localCropRect(forWindow: windowID, withBounds: self.bounds)
  406. self.updateWindowSelectUI(withWindowRect: rect)
  407. let cursor = NSCursor(image: NSImage(named: "cameraCursor") ?? NSImage(), hotSpot: NSPoint(x: 0, y: 0))
  408. cursor.set()
  409. } else if result.type == .keyDown {
  410. if result.keyCode == 53 {
  411. self.endImageCapture()
  412. }
  413. }
  414. return nil
  415. } else {
  416. var newFrame = CGRect.zero
  417. if result.type == .leftMouseDown {
  418. if self.editingRect {
  419. if self.holeDragMode {
  420. let downPoint = KMScreenShotHandler.screenPosition(for: result)
  421. self.pullXGap = Float(downPoint.x - self.borderFrame.origin.x)
  422. self.pullYGap = Float(downPoint.y - self.borderFrame.origin.y)
  423. }
  424. } else {
  425. self.dragStartPoint = KMScreenShotHandler.screenPosition(for: result)
  426. }
  427. } else if result.type == .leftMouseDragged {
  428. if self.editingRect{
  429. if self.holeDragMode {
  430. self.dragholeImageView(result)
  431. } else {
  432. self.rectEditDrag(event: result)
  433. }
  434. } else {
  435. self.dragLastPoint = KMScreenShotHandler.screenPosition(for: result)
  436. newFrame = NSMakeRect(min(self.dragStartPoint.x, self.dragLastPoint.x), min(self.dragStartPoint.y, self.dragLastPoint.y), abs(self.dragStartPoint.x - self.dragLastPoint.x), abs(self.dragStartPoint.y - self.dragLastPoint.y))
  437. self.updateSizeLabelWithRect(rect: newFrame, dragPoint: self.dragLastPoint)
  438. self.updateHoleWithRect(holeRect: newFrame)
  439. NSCursor.crosshair.set()
  440. }
  441. } else if result.type == .leftMouseUp {
  442. if self.editingRect {
  443. } else {
  444. self.dragLastPoint = KMScreenShotHandler.screenPosition(for: result)
  445. newFrame = NSMakeRect(min(self.dragStartPoint.x, self.dragLastPoint.x), min(self.dragStartPoint.y, self.dragLastPoint.y), abs(self.dragStartPoint.x - self.dragLastPoint.x) <= KMScreenHoleMinWidthAndHeight ? KMScreenHoleMinWidthAndHeight : abs(self.dragStartPoint.x - self.dragLastPoint.x), abs(self.dragStartPoint.y - self.dragLastPoint.y) <= KMScreenHoleMinWidthAndHeight ? KMScreenHoleMinWidthAndHeight : abs(self.dragStartPoint.y - self.dragLastPoint.y))
  446. self.updateHoleWithRect(holeRect: newFrame)
  447. self.beginEditSelectArea(newFrame)
  448. self.frameCallBack?(newFrame)
  449. }
  450. } else if result.type == .keyDown {
  451. if result.keyCode == 53 {
  452. self.endImageCapture()
  453. }
  454. } else if result.type == .mouseMoved {
  455. if self.detachCallBack != nil {
  456. self.detachCallBack?(result)
  457. }
  458. if self.editingRect{
  459. self.changeCursorTypeWithEvent(result)
  460. return nil
  461. } else {
  462. }
  463. }
  464. return result
  465. }
  466. }
  467. }
  468. if self.globalMonitor == nil {
  469. self.globalMonitor = NSEvent.addGlobalMonitorForEvents(matching: mask) { (result) in
  470. if isCaptureWindow {
  471. let windowID = self.windowForEvent(result)
  472. if result.type == .leftMouseDown {
  473. let image = KMScreenShotHandler.appointWindowScreenShot(withWindowID: windowID)
  474. self.callBack?(image ?? NSImage())
  475. self.endImageCapture()
  476. } else if result.type == .mouseMoved {
  477. let rect = KMOCTool.localCropRect(forWindow: windowID, withBounds: self.bounds)
  478. self.updateWindowSelectUI(withWindowRect: rect)
  479. let cursor = NSCursor(image: NSImage(named: "cameraCursor") ?? NSImage(), hotSpot: NSPoint(x: 0, y: 0))
  480. cursor.set()
  481. print("全局移动")
  482. } else if result.type == .keyDown {
  483. if result.keyCode == 53 {
  484. self.endImageCapture()
  485. }
  486. } else if result.type == .rightMouseDown {
  487. self.endImageCapture()
  488. }
  489. } else {
  490. var newFrame = CGRect.zero
  491. if result.type == .leftMouseDown {
  492. if self.editingRect{
  493. if self.holeDragMode {
  494. let downPoint = KMScreenShotHandler.screenPosition(for: result)
  495. self.pullXGap = Float(downPoint.x - self.borderFrame.origin.x)
  496. self.pullYGap = Float(downPoint.y - self.borderFrame.origin.y)
  497. }
  498. } else {
  499. self.dragStartPoint = KMScreenShotHandler.screenPosition(for: result)
  500. }
  501. } else if result.type == .leftMouseDragged {
  502. if self.editingRect{
  503. if self.holeDragMode {
  504. self.dragholeImageView(result)
  505. } else {
  506. self.rectEditDrag(event: result)
  507. }
  508. } else {
  509. self.dragLastPoint = KMScreenShotHandler.screenPosition(for: result)
  510. newFrame = NSMakeRect(min(self.dragStartPoint.x, self.dragLastPoint.x), min(self.dragStartPoint.y, self.dragLastPoint.y), abs(self.dragStartPoint.x - self.dragLastPoint.x), abs(self.dragStartPoint.y - self.dragLastPoint.y))
  511. self.updateHoleWithRect(holeRect: newFrame)
  512. }
  513. } else if result.type == .leftMouseUp {
  514. if self.editingRect{
  515. } else {
  516. self.dragLastPoint = KMScreenShotHandler.screenPosition(for: result)
  517. newFrame = NSMakeRect(min(self.dragStartPoint.x, self.dragLastPoint.x), min(self.dragStartPoint.y, self.dragLastPoint.y), abs(self.dragStartPoint.x - self.dragLastPoint.x) <= KMScreenHoleMinWidthAndHeight ? KMScreenHoleMinWidthAndHeight : abs(self.dragStartPoint.x - self.dragLastPoint.x), abs(self.dragStartPoint.y - self.dragLastPoint.y) <= KMScreenHoleMinWidthAndHeight ? KMScreenHoleMinWidthAndHeight : abs(self.dragStartPoint.y - self.dragLastPoint.y))
  518. self.updateHoleWithRect(holeRect: newFrame)
  519. self.beginEditSelectArea(newFrame)
  520. self.frameCallBack?(newFrame)
  521. }
  522. } else if result.type == .keyDown {
  523. if result.keyCode == 53 {
  524. self.endImageCapture()
  525. }
  526. } else if result.type == .mouseMoved {
  527. if self.detachCallBack != nil {
  528. self.detachCallBack?(result)
  529. }
  530. if self.editingRect {
  531. self.changeCursorTypeWithEvent(result)
  532. } else {
  533. }
  534. }
  535. }
  536. }
  537. }
  538. }
  539. func updateWindowSelectUI(withWindowRect rect: CGRect) {
  540. topView.layer?.backgroundColor = NSColor.clear.cgColor
  541. leftView.layer?.backgroundColor = NSColor.clear.cgColor
  542. bottomView.layer?.backgroundColor = NSColor.clear.cgColor
  543. rightView.layer?.backgroundColor = NSColor.clear.cgColor
  544. windowMaskView.frame = rect
  545. windowMaskView.layer?.backgroundColor = NSColor.black.cgColor
  546. windowMaskView.alphaValue = 0.3
  547. }
  548. func dragholeImageView(_ event: NSEvent) {
  549. guard let screen = NSScreen.screens.first else { return }
  550. let xMax = screen.frame.size.width
  551. let yMax = screen.frame.size.height
  552. let newPoint = KMScreenShotHandler.screenPosition(for: event)
  553. var newOriginalX = newPoint.x - CGFloat(pullXGap)
  554. var newOriginalY = newPoint.y - CGFloat(pullYGap)
  555. if newOriginalX < 0 {
  556. newOriginalX = 0
  557. }
  558. if newOriginalX + borderFrame.size.width > xMax {
  559. newOriginalX = xMax - borderFrame.size.width
  560. }
  561. if newOriginalY < 0 {
  562. newOriginalY = 0
  563. }
  564. if newOriginalY + borderFrame.size.height > yMax {
  565. newOriginalY = yMax - borderFrame.size.height
  566. }
  567. borderFrame = NSMakeRect(newOriginalX, newOriginalY, borderFrame.size.width, borderFrame.size.height)
  568. updateHoleWithRect(holeRect: borderFrame)
  569. updateSizeLabelWithRect(rect: borderFrame, dragPoint: NSMakePoint(NSMaxX(borderFrame), NSMinY(borderFrame)))
  570. if let callback = frameCallBack {
  571. callback(borderFrame)
  572. }
  573. }
  574. func captureImage() {
  575. guard let screen = NSScreen.screens.first else { return }
  576. let screenHeight = screen.frame.size.height
  577. let actualFrame = NSMakeRect(borderFrame.origin.x, screenHeight - borderFrame.origin.y - borderFrame.size.height, borderFrame.size.width, borderFrame.size.height)
  578. needborderFlag = false
  579. self.needsDisplay = true
  580. DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { [weak self] in
  581. guard let self = self else { return }
  582. if let windowImage = CGWindowListCreateImage(actualFrame, .optionOnScreenOnly, kCGNullWindowID, []) {
  583. let image = KMScreenShotHandler.imageFromCGImageRef(windowImage)
  584. self.updateHoleWithRect(holeRect: NSRect.zero)
  585. if let callback = self.callBack {
  586. callback(image ?? NSImage())
  587. }
  588. }
  589. self.endImageCapture()
  590. }
  591. }
  592. }