You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:52:48