通过OSX Accessibility API获取窗口号

0x9*_*x90 22 cocoa accessibility macos-carbon objective-c accessibility-api

我正在开发一个应用程序,可以在屏幕上移动第三方应用程序的窗口.

为了概述所有当前打开的窗口,我使用

CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
Run Code Online (Sandbox Code Playgroud)

这将返回定义每个打开窗口的字典数组.这是一个返回的示例字典:

{
    kCGWindowAlpha = 1;
    kCGWindowBounds =         {
        Height = 442;
        Width = 475;
        X = 3123;
        Y = "-118";
    };
    kCGWindowIsOnscreen = 1;
    kCGWindowLayer = 0;
    kCGWindowMemoryUsage = 907184;
    kCGWindowName = Untitled;
    kCGWindowNumber = 7328;
    kCGWindowOwnerName = TextEdit;
    kCGWindowOwnerPID = 20706;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
    kCGWindowWorkspace = 3;
},
Run Code Online (Sandbox Code Playgroud)

字典中充满了其他地方使用的良好信息,但缺少可用于修改窗口位置的辅助功能对象.窗口编号清楚地标识Windows.

我现在使用PID(kCGWindowOwnerPID)为窗口的应用程序创建一个辅助功能对象:

AXUIElementRef app = AXUIElementCreateApplication(pid);
Run Code Online (Sandbox Code Playgroud)

然后使用AXUIElementCopyAttributeValues检索应用程序已打开的所有窗口的列表:

NSArray *result;

AXUIElementCopyAttributeValues(
                               (AXUIElementRef) app, 
                               kAXWindowsAttribute,
                               0,
                               99999,
                               (CFArrayRef *) &result
                               );
Run Code Online (Sandbox Code Playgroud)

这适用于并返回一组AXUIElements.这是我被困的地方.似乎没有API调用来检索辅助功能对象的窗口号.有没有办法

a)找到辅助功能对象的窗口编号(最终迭代数组并找到正确的窗口)

要么

b)否则,将CGWindowListCopyWindowInfo返回的数组中描述的窗口与AXUIElementCopyAttributeValues返回的辅助功能对象清楚地匹配?

0x9*_*x90 24

我们最终聘请了一位专门的辅助功能开发人员来完成这项任务.

事实证明,如果不使用未记录的API,就无法做到这一点(在我们的案例中不行).

幸运的是,有一个实际的解决方法:

循环遍历应用程序的所有打开窗口.获得他们的位置,大小和头衔:

AXUIElementCopyAttributeValue(target, kAXPositionAttribute, CFTypeRef*)&posValue);
AXUIElementCopyAttributeValue(target, kAXSizeAttribute, (CFTypeRef*)&sizeValue);
AXUIElementCopyAttributeValue(target, kAXTitleAttribute, (CFTypeRef*)&titleValue);
Run Code Online (Sandbox Code Playgroud)

接下来,将位置和大小转换为实际值CGPointCGSize值:

AXValueGetValue(posValue, kAXValueCGPointType, &point);
AXValueGetValue(sizeValue, kAXValueCGSizeType, &size);
Run Code Online (Sandbox Code Playgroud)

将大小,位置和标题与对象返回的值进行比较CGWindowListCopyWindowInfo().如果它们匹配,您可以放心地假设它是您正在寻找的窗口并使用已经打开的AXUIElement(target在我们的例子中)来工作.

在OSX上,循环通过所有打开的窗口的开销几乎可以忽略不计.同时打开多少个窗口的上限相当低.

此外,虽然这不是100%准确(2个窗口可能有相同的位置,大小和标题),但到目前为止,我们还没有遇到任何实际使用情况.

  • 对于那些可以使用未记录的API的人来说,它会怎么做? (13认同)

Ole*_*nov 9

有一个私有函数用于获取窗口的给定AX对象的CG窗口号:_AXUIElementGetWindow.SO讨论中的更多细节在OS X上唯一标识活动窗口 看起来没有公共API以100%的概率执行任务.按标题和框架识别窗口(如上面的答案中所述)将在99.9%的情况下有效.