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

如何编程获取MacOS下打开的Finder窗口的当前文件夹路径

macOS 平台获取鼠标悬停Finder窗口路径实现方案

前置权限要求

  • 应用需要申请AppleEvents调用权限:在entitlements配置文件中添加com.apple.security.automation.apple-events权限项,首次触发调用时系统会自动弹出权限提示,引导用户在「系统设置-隐私与安全性-自动化」中允许应用访问Finder。如果是上架App Store的沙盒应用,还需要额外配置脚本目标白名单,将Finder的bundle ID com.apple.finder加入允许列表。

实现步骤

  1. 监听鼠标位置,当鼠标移出自身应用窗口范围后,通过系统公开API CGWindowListCopyWindowInfo 获取当前鼠标坐标下的所有窗口层级信息,过滤出kCGWindowOwnerName字段值为Finder的窗口,记录该窗口的位置、尺寸、窗口ID作为匹配依据。这一步需要提前过滤掉最小化窗口、透明窗口、系统UI弹窗,避免误判。
  2. 通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 00:27:20