通过OSX Accessibility API获取窗口号
我正在研究一个应用程序,它可以在屏幕上移动第三方应用程序的窗口。
为了获得所有当前打开的窗口的概述,我使用
CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
这将返回一个定义每个打开窗口的字典数组。 以下是返回的示例性字典:
{
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;
},
该字典充满了其他地方使用的良好信息,但缺少可用于修改窗口位置的可访问性对象。 窗口号码清楚地标识了Windows。
我现在使用PID(kCGWindowOwnerPID)为窗口应用程序创建一个辅助功能对象:
AXUIElementRef app = AXUIElementCreateApplication(pid);
接着检索应用程序使用AXUIElementCopyAttributeValues打开的所有窗口的列表:
NSArray *result;
AXUIElementCopyAttributeValues(
(AXUIElementRef) app,
kAXWindowsAttribute,
0,
99999,
(CFArrayRef *) &result
);
这工作并返回一个AXUIElements数组。 这是我卡住的地方。 似乎没有API调用来检索辅助功能对象的窗口号。 有没有办法
a)找到辅助对象的窗口号(最终遍历数组并找到正确的窗口)
要么
b)否则明确地将CGWindowListCopyWindowInfo返回的数组中描述的窗口与AXUIElementCopyAttributeValues返回的辅助功能对象进行匹配?
我们最终聘请了专门的可访问性开发人员来完成这项任务。
事实证明,如果不使用未记录的API(在我们的情况下不行),则无法做到这一点。
幸运的是,有一个实用的解决方法:
在应用的所有打开的窗口中循环。 获取他们的位置,大小和标题:
AXUIElementCopyAttributeValue(target, kAXPositionAttribute, CFTypeRef*)&posValue);
AXUIElementCopyAttributeValue(target, kAXSizeAttribute, (CFTypeRef*)&sizeValue);
AXUIElementCopyAttributeValue(target, kAXTitleAttribute, (CFTypeRef*)&titleValue);
接下来,将位置和大小转换为实际的CGPoint
和CGSize
值:
AXValueGetValue(posValue, kAXValueCGPointType, &point);
AXValueGetValue(sizeValue, kAXValueCGSizeType, &size);
将大小,位置和标题与CGWindowListCopyWindowInfo()
对象返回的值进行比较。 如果它们匹配,则可以安全地假定它是您正在查找的窗口,并使用已打开的AXUIElement(我们的target
)来处理它。
在OSX上循环浏览所有打开的窗口的开销可以忽略不计。 有多少个窗户同时打开的数量相当低。
另外,尽管这不是100%准确的(可能两个窗口具有相同的位置,大小和标题),但在迄今为止发生这种情况时,我们还没有遇到实际使用中的任何情况。
有一个私有函数用于为给定窗口的AX对象获取CG窗口号: _AXUIElementGetWindow
。 SO讨论中的更多细节在OS X上唯一标识活动窗口看起来好像没有公共API以100%的概率完成任务。 通过标题和框架标识窗口(如上面的答案中所述)将适用于99.9%的案例。