如何在macOS上获取Command+Shift+4截屏的自定义边界?
问题:获取macOS自定义区域截屏的边界(图片保存前)
我正在尝试获取macOS上截屏操作产生的缩略图。目前通过遍历系统所有打开窗口,当检测到Screen capture打开时,便知晓缩略图已显示在屏幕上。但问题是,当用户使用Command + Shift + 4进行自定义区域截屏时,我无法获取该自定义边界,只能截取全屏范围。因此想请教:如何在截屏图片保存到桌面之前,获取该自定义截屏的边界?
当前代码
@objc func checkStatusBarForRecordingIndicator() -> Bool { //Get all windows list let windowList = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID) as! [[String: Any]] //Check each window name, application name and bounds of window for window in windowList { let boundsDict = window[kCGWindowBounds as String] as! CFDictionary let applicationName = window[kCGWindowOwnerName as String] as! String //let windowName = window[kCGWindowName as String] as? String //check if it's on menubar or not if let bounds = CGRect(dictionaryRepresentation: boundsDict), bounds.origin.y == 0 { print(applicationName, bounds) //Check if screen recording is on menubar if applicationName == screenShootAppName && bounds.origin.x == .zero { print("Screen shoot!") // Create an image from the window let imageView = NSImageView(frame: NSRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)) imageView.image = getSSImage(_bounds: bounds) return true } } } print("No Screen recording") return false } //Get screen shoot image func getSSImage (_bounds:CGRect) -> NSImage { let image = CGWindowListCreateImage(_bounds, .optionOnScreenOnly, kCGNullWindowID, .bestResolution) return NSImage(cgImage: image!, size: NSSize(width: _bounds.width, height: _bounds.height)) }
解决方案
1. 监听Screen Capture的临时选区窗口
当用户用Command+Shift+4进行自定义截屏时,系统Screen Capture进程会生成一个临时预览窗口,这个窗口的边界就是用户选择的截屏区域。你可以修改窗口遍历逻辑,筛选出这个窗口:
调整后的代码片段:
for window in windowList { let boundsDict = window[kCGWindowBounds as String] as! CFDictionary let applicationName = window[kCGWindowOwnerName as String] as! String let windowName = window[kCGWindowName as String] as? String // 匹配ScreenCapture的选区预览窗口 if applicationName == "ScreenCapture", let windowName = windowName, windowName.contains("Selection") { if let bounds = CGRect(dictionaryRepresentation: boundsDict) { print("自定义截屏边界:\(bounds)") // 用这个边界生成缩略图 let imageView = NSImageView(frame: NSRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)) imageView.image = getSSImage(_bounds: bounds) return true } } // 保留原有的状态栏检测逻辑 if let bounds = CGRect(dictionaryRepresentation: boundsDict), bounds.origin.y == 0 { if applicationName == screenShootAppName && bounds.origin.x == .zero { print("Screen shoot!") let imageView = NSImageView(frame: NSRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)) imageView.image = getSSImage(_bounds: bounds) return true } } }
2. 用CGEventTap监听截屏事件与鼠标选区
通过CGEventTap监听Command+Shift+4的触发事件,再跟踪鼠标拖拽的起始/结束点,直接计算选区边界。这种方式需要申请辅助功能权限(用户需在系统偏好设置中授权):
示例代码片段:
var isSelectingRegion = false var selectionStartPoint: CGPoint = .zero func setupEventTap() { // 监听键盘按下、鼠标按下/抬起事件 let eventMask = (1 << CGEventType.keyDown.rawValue) | (1 << CGEventType.leftMouseDown.rawValue) | (1 << CGEventType.leftMouseUp.rawValue) guard let eventTap = CGEventTapCreate( .cghidEventTap, .headInsertEventTap, .defaultTap, eventMask, eventTapCallback, nil ) else { print("无法创建事件监听,请开启辅助功能权限") return } let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0) CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes) CGEventTapEnable(eventTap, true) } func eventTapCallback(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent, refcon: UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? { switch type { case .keyDown: let keyCode = event.getIntegerValueField(.keyboardEventKeycode) let isCmdPressed = event.flags.contains(.maskCommand) let isShiftPressed = event.flags.contains(.maskShift) // Command+Shift+4的键码为3(数字4) if isCmdPressed && isShiftPressed && keyCode == 3 { isSelectingRegion = true } case .leftMouseDown: if isSelectingRegion { selectionStartPoint = event.location } case .leftMouseUp: if isSelectingRegion { let endPoint = event.location // 计算选区边界 let selectionBounds = CGRect( x: min(selectionStartPoint.x, endPoint.x), y: min(selectionStartPoint.y, endPoint.y), width: abs(selectionStartPoint.x - endPoint.x), height: abs(selectionStartPoint.y - endPoint.y) ) print("自定义截屏边界:\(selectionBounds)") // 调用截图方法生成缩略图 let imageView = NSImageView(frame: NSRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)) imageView.image = getSSImage(_bounds: selectionBounds) isSelectingRegion = false } default: break } return Unmanaged.passRetained(event) }
注意事项
- 第一种方法无需额外权限,但依赖系统Screen Capture窗口的命名规则,可能随macOS版本变化;第二种方法更可靠,但需要用户授权辅助功能。
- 处理多屏幕场景时,需用
NSScreen.screens转换全局坐标,确保边界位置准确。
内容的提问来源于stack exchange,提问作者Avi Rok
相关产品推荐
相关产品推荐

