如何编程获取MacOS下打开的Finder窗口的当前文件夹路径
macOS 平台获取鼠标悬停Finder窗口路径实现方案
前置权限要求
- 应用需要申请AppleEvents调用权限:在entitlements配置文件中添加
com.apple.security.automation.apple-events权限项,首次触发调用时系统会自动弹出权限提示,引导用户在「系统设置-隐私与安全性-自动化」中允许应用访问Finder。如果是上架App Store的沙盒应用,还需要额外配置脚本目标白名单,将Finder的bundle IDcom.apple.finder加入允许列表。
实现步骤
- 监听鼠标位置,当鼠标移出自身应用窗口范围后,通过系统公开API
CGWindowListCopyWindowInfo获取当前鼠标坐标下的所有窗口层级信息,过滤出kCGWindowOwnerName字段值为Finder的窗口,记录该窗口的位置、尺寸、窗口ID作为匹配依据。这一步需要提前过滤掉最小化窗口、透明窗口、系统UI弹窗,避免误判。 - 通过AppleScript调用Finder的脚本接口,遍历当前所有打开的Finder窗口,拿到每个窗口的bounds(位置+尺寸)、可见状态、当前打开路径,和第一步拿到的悬停窗口信息做匹配,匹配成功的窗口对应的POSIX路径就是目标结果。不要直接调用
front window属性拿路径,用户鼠标悬停的很可能是后台未激活的Finder窗口,直接取前台窗口会返回错误结果。
注意:
CGWindowListCopyWindowInfo返回的窗口坐标以屏幕左上角为原点,Finder脚本接口返回的窗口bounds以屏幕左下角为原点,比对前需要做y轴坐标换算,否则会出现匹配失败的问题。
参考代码片段
AppleScript 核心获取逻辑
tell application "Finder" set allFinderWindows to every window set matchedPath to "" repeat with win in allFinderWindows -- 跳过不可见、最小化的窗口 if visible of win is true and collapsed of win is false then set currentBounds to bounds of win -- 此处把currentBounds和之前拿到的悬停窗口bounds做坐标换算后比对 if 匹配命中 then set matchedPath to POSIX path of (target of win as alias) exit repeat end if end if end repeat end tell return matchedPath
Swift 调用示例
import Foundation import AppKit func getHoverFinderWindowPath(targetBounds: NSRect, screenHeight: CGFloat) -> String? { // 坐标系换算:Quartz坐标系转Cocoa坐标系 let cocoaY = screenHeight - targetBounds.origin.y - targetBounds.size.height let scriptSource = """ tell application "Finder" set allFinderWindows to every window set matchedPath to "" repeat with win in allFinderWindows if visible of win is true and collapsed of win is false then set b to bounds of win if item 1 of b = \(Int(targetBounds.origin.x)) and item 2 of b = \(Int(cocoaY)) and (item 3 of b - item 1 of b) = \(Int(targetBounds.size.width)) and (item 4 of b - item 2 of b) = \(Int(targetBounds.size.height)) then set matchedPath to POSIX path of (target of win as alias) exit repeat end if end if end repeat end tell return matchedPath """ var error: NSDictionary? guard let script = NSAppleScript(source: scriptSource) else { return nil } let result = script.executeAndReturnError(&error) guard error == nil else { return nil } return result.stringValue }
优化建议
- 不要高频轮询鼠标位置,鼠标移出自身应用窗口后再启动监听,回到自身窗口后立刻停止监听,轮询间隔控制在100ms以上即可保证交互体验,不会产生额外性能消耗。
- 注意过滤Finder的桌面窗口:这个窗口常驻后台,bounds和屏幕尺寸一致,路径默认对应用户的桌面目录,需要加判断排除,避免用户鼠标停在桌面时误返回桌面路径。
- 该方案全部使用系统公开API,兼容MacOS 10.10及以上所有正式版本,不存在私有API调用导致的审核拒审问题。
内容的提问来源于stack exchange,提问作者Display Name
相关产品推荐
相关产品推荐

