// // KMScreenShotMaskView.swift // PDF Reader Pro // // Created by liujiajie on 2024/1/24. // import Foundation typealias captureScreenCallBack = (_ ima: NSImage?) -> () typealias updateFrameCallBack = (_ rect: NSRect) -> () typealias detachEventInEditViewCallBack = (_ event: NSEvent) -> () @objc enum KMScreenShotRectEditViewPositionType: Int { case None = 0 case Top case Left case Bottom case Right case LeftUp case LeftLower case RightUp case RightLower } let KMScreenLineLength: CGFloat = 4//线长 let KMScreenSpaceLength: CGFloat = 1//空格长 let KMScreenLineWidth: CGFloat = 2//线宽 let KMScreenSizeLableFont: CGFloat = 12//尺寸字体大小 let KMScreenDetectLength: CGFloat = 4//选取rect之后边界线探测区域 let KMScreenHoleMinWidthAndHeight: CGFloat = 40 class KMScreenShotMaskView: NSView{ var callBack: captureScreenCallBack? var frameCallBack: updateFrameCallBack? var detachCallBack: detachEventInEditViewCallBack? var holeDragMode = false var borderFrame: NSRect = .zero var iswindowCapture = false var topView: NSView! var leftView: NSView! var bottomView: NSView! var rightView: NSView! var windowMaskView: NSView! var sizeLabel: NSTextField! var localMonitor: Any? var globalMonitor: Any? var dragStartPoint: CGPoint = .zero var dragLastPoint: CGPoint = .zero var editingRect = false var positionType: KMScreenShotRectEditViewPositionType = .None var needborderFlag = false var pullXGap: Float = 0 var pullYGap: Float = 0 override func awakeFromNib() { super.awakeFromNib() topView = NSView(frame: CGRect.zero) leftView = NSView(frame: CGRect.zero) bottomView = NSView(frame: CGRect.zero) rightView = NSView(frame: CGRect.zero) windowMaskView = NSView(frame: CGRect.zero) sizeLabel = NSTextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) sizeLabel.font = NSFont.systemFont(ofSize: CGFloat(KMScreenSizeLableFont)) sizeLabel.textColor = NSColor.black sizeLabel.backgroundColor = NSColor.clear sizeLabel.isEnabled = false sizeLabel.isSelectable = false sizeLabel.isBordered = false sizeLabel.alignment = .right addSubview(topView) addSubview(leftView) addSubview(bottomView) addSubview(rightView) addSubview(sizeLabel) addSubview(windowMaskView) topView.wantsLayer = true leftView.wantsLayer = true bottomView.wantsLayer = true rightView.wantsLayer = true windowMaskView.wantsLayer = true topView.layer?.backgroundColor = NSColor.black.cgColor leftView.layer?.backgroundColor = NSColor.black.cgColor bottomView.layer?.backgroundColor = NSColor.black.cgColor rightView.layer?.backgroundColor = NSColor.black.cgColor windowMaskView.layer?.backgroundColor = NSColor.clear.cgColor topView.alphaValue = 0.3 leftView.alphaValue = 0.3 bottomView.alphaValue = 0.3 rightView.alphaValue = 0.3 needborderFlag = true } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) if !needborderFlag { return } if !editingRect { return } guard let myContext = NSGraphicsContext.current?.cgContext else { return } if iswindowCapture { return } myContext.setFillColor(NSColor.red.cgColor) myContext.addArc(center: CGPoint(x: borderFrame.minX, y: borderFrame.minY), radius: CGFloat(KMScreenDetectLength), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true) myContext.drawPath(using: .fill) myContext.addArc(center: CGPoint(x: borderFrame.midX, y: borderFrame.minY), radius: CGFloat(KMScreenDetectLength), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true) myContext.drawPath(using: .fill) myContext.addArc(center: CGPoint(x: borderFrame.maxX, y: borderFrame.minY), radius: CGFloat(KMScreenDetectLength), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true) myContext.drawPath(using: .fill) myContext.addArc(center: CGPoint(x: borderFrame.maxX, y: borderFrame.midY), radius: CGFloat(KMScreenDetectLength), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true) myContext.drawPath(using: .fill) myContext.addArc(center: CGPoint(x: borderFrame.maxX, y: borderFrame.maxY), radius: CGFloat(KMScreenDetectLength), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true) myContext.drawPath(using: .fill) myContext.addArc(center: CGPoint(x: borderFrame.midX, y: borderFrame.maxY), radius: CGFloat(KMScreenDetectLength), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true) myContext.drawPath(using: .fill) myContext.addArc(center: CGPoint(x: borderFrame.minX, y: borderFrame.maxY), radius: CGFloat(KMScreenDetectLength), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true) myContext.drawPath(using: .fill) myContext.addArc(center: CGPoint(x: borderFrame.minX, y: borderFrame.midY), radius: CGFloat(KMScreenDetectLength), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true) myContext.drawPath(using: .fill) } func updateSubViewFrame(withHoleRect holeRect: NSRect) { let topViewOriginalX: CGFloat = 0 let topViewOriginalY: CGFloat = min(holeRect.maxY, frame.maxY) let topViewWidth = frame.size.width let topViewHeight = holeRect.maxY > frame.maxY ? 0 : frame.maxY - holeRect.maxY topView.frame = CGRect(x: topViewOriginalX, y: topViewOriginalY, width: topViewWidth, height: topViewHeight) let originalY = holeRect.origin.y var leftRightHeight: CGFloat if originalY > 0 { leftRightHeight = holeRect.size.height } else { leftRightHeight = holeRect.size.height - abs(holeRect.origin.y) } let leftViewOriginalX: CGFloat = 0 let leftViewOriginalY: CGFloat = max(holeRect.minY, 0) let leftViewWidth = max(0, holeRect.minX) let leftViewHeight = leftRightHeight leftView.frame = CGRect(x: leftViewOriginalX, y: leftViewOriginalY, width: leftViewWidth, height: leftViewHeight) let bottomViewOriginalX: CGFloat = 0 let bottomViewOriginalY: CGFloat = 0 let bottomViewWidth = frame.size.width let bottomViewHeight = max(holeRect.minY, 0) bottomView.frame = CGRect(x: bottomViewOriginalX, y: bottomViewOriginalY, width: bottomViewWidth, height: bottomViewHeight) let rightViewOriginalX = min(holeRect.maxX, frame.maxX) let rightViewOriginalY = max(holeRect.minY, 0) let rightViewWidth = holeRect.maxX > frame.maxX ? 0 : frame.maxX - holeRect.maxX let rightViewHeight = leftRightHeight rightView.frame = CGRect(x: rightViewOriginalX, y: rightViewOriginalY, width: rightViewWidth, height: rightViewHeight) } func windowForEvent(_ event: NSEvent) -> CGWindowID { return CGWindowID(NSWindow.windowNumber(at: KMScreenShotHandler.screenPosition(for: event), belowWindowWithWindowNumber: self.window!.windowNumber)) } func beginEditSelectArea(_ editFrame: NSRect) { self.editingRect = true } func changeCursorTypeWithEvent(_ result: NSEvent) { let point = KMScreenShotHandler.screenPosition(for: result) self.positionType = self.calulateCurrentPositionType(point) switch self.positionType { case .None: NSCursor.arrow.set() case .Top: NSCursor.resizeUpDown.set() case .Left: NSCursor.resizeLeftRight.set() case .Bottom: NSCursor.resizeUpDown.set() case .Right: NSCursor.resizeLeftRight.set() case .LeftUp: NSCursor.crosshair.set() case .LeftLower: NSCursor.crosshair.set() case .RightUp: NSCursor.crosshair.set() case .RightLower: NSCursor.crosshair.set() default: break } } func calulateCurrentPositionType(_ point: NSPoint) -> KMScreenShotRectEditViewPositionType { var type: KMScreenShotRectEditViewPositionType = .None let topYMin = NSMaxY(self.borderFrame) - CGFloat(KMScreenDetectLength) let topYMax = NSMaxY(self.borderFrame) + CGFloat(KMScreenDetectLength) let leftXMin = NSMinX(self.borderFrame) - CGFloat(KMScreenDetectLength) let leftXMax = NSMinX(self.borderFrame) + CGFloat(KMScreenDetectLength) let bottomYMin = NSMinY(self.borderFrame) - CGFloat(KMScreenDetectLength) let bottomYMax = NSMinY(self.borderFrame) + CGFloat(KMScreenDetectLength) let rightXMin = NSMaxX(self.borderFrame) - CGFloat(KMScreenDetectLength) let rightXMax = NSMaxX(self.borderFrame) + CGFloat(KMScreenDetectLength) if point.x <= leftXMax && point.x >= leftXMin { if point.y <= topYMax && point.y >= topYMin { type = .LeftUp } else if point.y <= bottomYMax && point.y >= bottomYMin { type = .LeftLower } else if point.y < topYMin && point.y > bottomYMax { type = .Left } } else if point.x <= rightXMax && point.x >= rightXMin { if point.y <= topYMax && point.y >= topYMin { type = .RightUp } else if point.y <= bottomYMax && point.y >= bottomYMin { type = .RightLower } else if point.y > bottomYMax && point.y < topYMin { type = .Right } } else if point.x > leftXMax && point.x < rightXMin { if point.y > bottomYMin && point.y < bottomYMax { type = .Bottom } else if point.y > topYMin && point.y < topYMax { type = .Top } else { type = .None } } else { type = .None } return type } func rectEditDrag(event: NSEvent) { let newPoint = KMScreenShotHandler.screenPosition(for: event) switch self.positionType { case .None: break case .Top: let changeTop = newPoint.y - self.borderFrame.maxY 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))) case .Left: let changeLeft = newPoint.x - self.borderFrame.minX 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) case .Bottom: let changeBottom = newPoint.y - self.borderFrame.minY 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) case .Right: let changeRight = newPoint.x - self.borderFrame.maxX 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) case .LeftUp: let changeX = newPoint.x - self.borderFrame.minX let changeY = newPoint.y - self.borderFrame.maxY 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) case .LeftLower: let changeX = newPoint.x - self.borderFrame.minX let changeY = newPoint.y - self.borderFrame.minY 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) case .RightUp: let changeX = newPoint.x - self.borderFrame.maxX let changeY = newPoint.y - self.borderFrame.maxY 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) case .RightLower: let changeX = newPoint.x - self.borderFrame.maxX let changeY = newPoint.y - self.borderFrame.minY 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) default: break } self.updateHoleWithRect(holeRect: self.borderFrame) self.updateSizeLabelWithRect(rect: self.borderFrame, dragPoint: CGPoint(x: self.borderFrame.maxX, y: self.borderFrame.minY)) if let frameCallBack = self.frameCallBack { frameCallBack(self.borderFrame) } } func updateHoleWithRect(holeRect: CGRect) { self.borderFrame = holeRect self.updateSubViewFrameWithHoleRect(holeRect: holeRect) // self.setNeedsDisplay(true) self.needsDisplay = true } func updateSizeLabelWithRect(rect: CGRect, dragPoint: CGPoint) { let labelString = "\(Int(rect.size.width)) * \(Int(rect.size.height))" self.sizeLabel.stringValue = labelString self.sizeLabel.sizeToFit() if dragPoint.x == rect.maxX { 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) } else if dragPoint.x == rect.minX { 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) } } func updateSubViewFrameWithHoleRect(holeRect: NSRect) { let topViewOriginalX: CGFloat = 0 let topViewOriginalY: CGFloat = min(holeRect.maxY, self.frame.maxY) let topViewWidth = self.frame.size.width let topViewHeight = holeRect.maxY > self.frame.maxY ? 0 : self.frame.maxY - holeRect.maxY self.topView.frame = CGRect(x: topViewOriginalX, y: topViewOriginalY, width: topViewWidth, height: topViewHeight) let originalY = holeRect.origin.y var leftRightHeight: CGFloat if originalY > 0 { leftRightHeight = holeRect.size.height } else { leftRightHeight = holeRect.size.height - abs(holeRect.origin.y) } let leftViewOriginalX: CGFloat = 0 let leftViewOriginalY: CGFloat = max(holeRect.minY, 0) let leftViewWidth = max(0, holeRect.minX) let leftViewHeight = leftRightHeight self.leftView.frame = CGRect(x: leftViewOriginalX, y: leftViewOriginalY, width: leftViewWidth, height: leftViewHeight) let bottomViewOriginalX: CGFloat = 0 let bottomViewOriginalY: CGFloat = 0 let bottomViewWidth = self.frame.size.width let bottomViewHeight = max(holeRect.minY, 0) self.bottomView.frame = CGRect(x: bottomViewOriginalX, y: bottomViewOriginalY, width: bottomViewWidth, height: bottomViewHeight) let rightViewOriginalX = min(holeRect.maxX, self.frame.maxX) let rightViewOriginalY = max(holeRect.minY, 0) let rightViewWidth = holeRect.maxX > self.frame.maxX ? 0 : self.frame.maxX - holeRect.maxX let rightViewHeight = leftRightHeight self.rightView.frame = CGRect(x: rightViewOriginalX, y: rightViewOriginalY, width: rightViewWidth, height: rightViewHeight) } func updateholeSize(newSize: CGSize) { updateHoleWithRect(holeRect: NSRect(x: self.borderFrame.origin.x, y: self.borderFrame.origin.y, width: newSize.width, height: newSize.height)) 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)) } func beginImageCapture(isCaptureWindow: Bool) { self.window?.setIsVisible(true) self.sizeLabel.isHidden = isCaptureWindow initMonitor(isCaptureWindow: isCaptureWindow) } func setUIPrepare(isWindowCapture: Bool) { if isWindowCapture { topView.layer?.backgroundColor = NSColor.clear.cgColor leftView.layer?.backgroundColor = NSColor.clear.cgColor bottomView.layer?.backgroundColor = NSColor.clear.cgColor rightView.layer?.backgroundColor = NSColor.clear.cgColor windowMaskView.layer?.backgroundColor = NSColor.black.cgColor windowMaskView.alphaValue = 0.3 } else { topView.layer?.backgroundColor = NSColor.black.cgColor topView.alphaValue = 0.3 leftView.layer?.backgroundColor = NSColor.black.cgColor leftView.alphaValue = 0.3 bottomView.layer?.backgroundColor = NSColor.black.cgColor bottomView.alphaValue = 0.3 rightView.layer?.backgroundColor = NSColor.black.cgColor rightView.alphaValue = 0.3 } } func endImageCapture() { resignMonitor() borderFrame = CGRect.zero updateHoleWithRect(holeRect: CGRect.zero) self.needsDisplay = true editingRect = false holeDragMode = false if NSApp.windows.contains(self.window!) { self.window?.setIsVisible(false) } sizeLabel.isHidden = true needborderFlag = true NSCursor.arrow.set() } func resignMonitor() { NSEvent.removeMonitor(localMonitor as Any) NSEvent.removeMonitor(globalMonitor as Any) localMonitor = nil globalMonitor = nil } func initMonitor(isCaptureWindow: Bool) { self.iswindowCapture = isCaptureWindow var mask: NSEvent.EventTypeMask if isCaptureWindow { mask = [NSEvent.EventTypeMask.mouseMoved, NSEvent.EventTypeMask.leftMouseDown, NSEvent.EventTypeMask.keyDown] } else { mask = [NSEvent.EventTypeMask.mouseMoved, NSEvent.EventTypeMask.leftMouseDown, NSEvent.EventTypeMask.leftMouseDragged, NSEvent.EventTypeMask.leftMouseUp, NSEvent.EventTypeMask.keyDown] self.updateHoleWithRect(holeRect: .zero) } self.setUIPrepare(isWindowCapture: isCaptureWindow) if self.localMonitor == nil { self.localMonitor = NSEvent.addLocalMonitorForEvents(matching: mask) { (result) -> NSEvent? in if isCaptureWindow { let windowID: CGWindowID = self.windowForEvent(result) if result.type == .leftMouseDown { let image = KMScreenShotHandler.appointWindowScreenShot(withWindowID: windowID) self.callBack?(image ?? NSImage()) self.endImageCapture() } else if result.type == .mouseMoved { let rect = KMOCTool.localCropRect(forWindow: windowID, withBounds: self.bounds) self.updateWindowSelectUI(withWindowRect: rect) let cursor = NSCursor(image: NSImage(named: "cameraCursor") ?? NSImage(), hotSpot: NSPoint(x: 0, y: 0)) cursor.set() } else if result.type == .keyDown { if result.keyCode == 53 { self.endImageCapture() } } return nil } else { var newFrame = CGRect.zero if result.type == .leftMouseDown { if self.editingRect { if self.holeDragMode { let downPoint = KMScreenShotHandler.screenPosition(for: result) self.pullXGap = Float(downPoint.x - self.borderFrame.origin.x) self.pullYGap = Float(downPoint.y - self.borderFrame.origin.y) } } else { self.dragStartPoint = KMScreenShotHandler.screenPosition(for: result) } } else if result.type == .leftMouseDragged { if self.editingRect{ if self.holeDragMode { self.dragholeImageView(result) } else { self.rectEditDrag(event: result) } } else { self.dragLastPoint = KMScreenShotHandler.screenPosition(for: result) 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)) self.updateSizeLabelWithRect(rect: newFrame, dragPoint: self.dragLastPoint) self.updateHoleWithRect(holeRect: newFrame) NSCursor.crosshair.set() } } else if result.type == .leftMouseUp { if self.editingRect { } else { self.dragLastPoint = KMScreenShotHandler.screenPosition(for: result) 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)) self.updateHoleWithRect(holeRect: newFrame) self.beginEditSelectArea(newFrame) self.frameCallBack?(newFrame) } } else if result.type == .keyDown { if result.keyCode == 53 { self.endImageCapture() } } else if result.type == .mouseMoved { if self.detachCallBack != nil { self.detachCallBack?(result) } if self.editingRect{ self.changeCursorTypeWithEvent(result) return nil } else { } } return result } } } if self.globalMonitor == nil { self.globalMonitor = NSEvent.addGlobalMonitorForEvents(matching: mask) { (result) in if isCaptureWindow { let windowID = self.windowForEvent(result) if result.type == .leftMouseDown { let image = KMScreenShotHandler.appointWindowScreenShot(withWindowID: windowID) self.callBack?(image ?? NSImage()) self.endImageCapture() } else if result.type == .mouseMoved { let rect = KMOCTool.localCropRect(forWindow: windowID, withBounds: self.bounds) self.updateWindowSelectUI(withWindowRect: rect) let cursor = NSCursor(image: NSImage(named: "cameraCursor") ?? NSImage(), hotSpot: NSPoint(x: 0, y: 0)) cursor.set() print("全局移动") } else if result.type == .keyDown { if result.keyCode == 53 { self.endImageCapture() } } else if result.type == .rightMouseDown { self.endImageCapture() } } else { var newFrame = CGRect.zero if result.type == .leftMouseDown { if self.editingRect{ if self.holeDragMode { let downPoint = KMScreenShotHandler.screenPosition(for: result) self.pullXGap = Float(downPoint.x - self.borderFrame.origin.x) self.pullYGap = Float(downPoint.y - self.borderFrame.origin.y) } } else { self.dragStartPoint = KMScreenShotHandler.screenPosition(for: result) } } else if result.type == .leftMouseDragged { if self.editingRect{ if self.holeDragMode { self.dragholeImageView(result) } else { self.rectEditDrag(event: result) } } else { self.dragLastPoint = KMScreenShotHandler.screenPosition(for: result) 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)) self.updateHoleWithRect(holeRect: newFrame) } } else if result.type == .leftMouseUp { if self.editingRect{ } else { self.dragLastPoint = KMScreenShotHandler.screenPosition(for: result) 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)) self.updateHoleWithRect(holeRect: newFrame) self.beginEditSelectArea(newFrame) self.frameCallBack?(newFrame) } } else if result.type == .keyDown { if result.keyCode == 53 { self.endImageCapture() } } else if result.type == .mouseMoved { if self.detachCallBack != nil { self.detachCallBack?(result) } if self.editingRect { self.changeCursorTypeWithEvent(result) } else { } } } } } } func updateWindowSelectUI(withWindowRect rect: CGRect) { topView.layer?.backgroundColor = NSColor.clear.cgColor leftView.layer?.backgroundColor = NSColor.clear.cgColor bottomView.layer?.backgroundColor = NSColor.clear.cgColor rightView.layer?.backgroundColor = NSColor.clear.cgColor windowMaskView.frame = rect windowMaskView.layer?.backgroundColor = NSColor.black.cgColor windowMaskView.alphaValue = 0.3 } func dragholeImageView(_ event: NSEvent) { guard let screen = NSScreen.screens.first else { return } let xMax = screen.frame.size.width let yMax = screen.frame.size.height let newPoint = KMScreenShotHandler.screenPosition(for: event) var newOriginalX = newPoint.x - CGFloat(pullXGap) var newOriginalY = newPoint.y - CGFloat(pullYGap) if newOriginalX < 0 { newOriginalX = 0 } if newOriginalX + borderFrame.size.width > xMax { newOriginalX = xMax - borderFrame.size.width } if newOriginalY < 0 { newOriginalY = 0 } if newOriginalY + borderFrame.size.height > yMax { newOriginalY = yMax - borderFrame.size.height } borderFrame = NSMakeRect(newOriginalX, newOriginalY, borderFrame.size.width, borderFrame.size.height) updateHoleWithRect(holeRect: borderFrame) updateSizeLabelWithRect(rect: borderFrame, dragPoint: NSMakePoint(NSMaxX(borderFrame), NSMinY(borderFrame))) if let callback = frameCallBack { callback(borderFrame) } } func captureImage() { guard let screen = NSScreen.screens.first else { return } let screenHeight = screen.frame.size.height let actualFrame = NSMakeRect(borderFrame.origin.x, screenHeight - borderFrame.origin.y - borderFrame.size.height, borderFrame.size.width, borderFrame.size.height) needborderFlag = false self.needsDisplay = true DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { [weak self] in guard let self = self else { return } if let windowImage = CGWindowListCreateImage(actualFrame, .optionOnScreenOnly, kCGNullWindowID, []) { let image = KMScreenShotHandler.imageFromCGImageRef(windowImage) self.updateHoleWithRect(holeRect: NSRect.zero) if let callback = self.callBack { callback(image ?? NSImage()) } } self.endImageCapture() } } }