【问题标题】:Mac / Cocoa - Getting a list of windows using Accessibility APIMac / Cocoa - 使用 Accessibility API 获取窗口列表
【发布时间】:2010-01-21 07:51:57
【问题描述】:

我想使用 Accessibility API 来获取给定应用程序(外部)的所有窗口的列表。

目标是检查某个窗口是否打开。首先我检查应用程序是否正在运行(使用 [NSWorkspace runningApplications] 并检查每一个),然后我想检查为该应用程序打开的每个窗口的标题栏文本。

PS

所以我可以使用 PID 为应用创建一个元素:

AXUIElementRef app = AXUIElementCreateApplication(pid);

但是我该怎么做呢?我是否朝着正确的方向前进?真不敢相信在这方面很难找到例子。

【问题讨论】:

    标签: cocoa accessibility


    【解决方案1】:

    我不知道如何从 Accessibility API 获取窗口 ID 和 PID。
    Laurent 提到的 NSWindow 方法仅提供窗口 ID,但不提供窗口拥有应用程序的 PID。
    我会使用自 10.5 以来可用的 CGWindowList 方法。
    要获取窗口 ID 列表和所有者的 PID,您可以尝试以下操作:

    CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
    for (NSMutableDictionary* entry in (NSArray*)windowList) 
    {
        NSString* ownerName = [entry objectForKey:(id)kCGWindowOwnerName];
        NSInteger ownerPID = [[entry objectForKey:(id)kCGWindowOwnerPID] integerValue];
        NSLog(@"%@:%d", ownerName, ownerPID);
    }
    CFRelease(windowList);  
    

    您可以使用选项参数控制是否需要所有窗口(包括屏幕外...)。
    条目对象还包含更多信息。 Documentation link

    【讨论】:

    • 这也适用于 Swift 吗?似乎在 Swift 中没有等同于 kCGNullWindowID 的东西......
    • @Blaszard 常量以原始形式快速存在 - kCGNullWindowID
    【解决方案2】:

    这在 Swift 5.1 中适用于我:

    let windowList: CFArray? = CGWindowListCopyWindowInfo(.optionOnScreenOnly, kCGNullWindowID)
    
    for entry in windowList! as Array {
    
        let ownerName: String = entry.object(forKey: kCGWindowName) as? String ?? "N/A"
        let ownerPID: Int = entry.object(forKey: kCGWindowOwnerPID) as? Int ?? 0
        print("ownerName: \(ownerName), ownerPID:\(ownerPID)")
    }
    

    【讨论】:

      【解决方案3】:

      使用AXUIElementCopyAttributeValues 复制kAXWindowsAttribute 的值,它应该是代表应用程序窗口的AXUIElement 对象数组。

      你可以从它的函数名中猜到,它跟在the copy rule之后。

      【讨论】:

      • 很好的提示,彼得。但是...它对我不起作用,我终于发现在尝试获取AXUIElementCopyAttributeNames 时我总是有kAXErrorCannotComplete(我得到了AXUIElementRef 就像原来的问题一样,这会是问题吗?!)。
      • @StuFFmc:我建议提出单独的问题和/或提交错误。
      • 另一个为什么我们不只是在答案中删除链接的例子。什么是复制规则?点击链接不知道。
      【解决方案4】:

      您可以使用windowNumbersWithOptions:。它按编号列出所有应用程序的所有窗口。但是我找不到如何从窗口号中获取NSWindow...

      【讨论】:

      • 你不能,即使在原则上,从一个窗口号中获取一个 NSWindow,因为前提是你是从一个外部应用程序,即另一个进程,并且每个 NSWindow * 指针都在拥有窗口的进程的地址空间。窗口编号是窗口服务器使用并提供的索引,以便任何应用程序都可以执行请求屏幕快照等操作。
      【解决方案5】:

      如果你得到kAXErrorCannotComplete,很可能是因为你使用了一个较新的项目,其中 XCode 自动添加了 App SandboxHardened Runtime 功能。从Signing and Capabilities 标签中删除它们,它应该开始工作了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-04
        相关资源
        最近更新 更多