Objective c 通过OSX可访问性API获取窗口号
我正在开发一个可以在屏幕上移动第三方应用程序窗口的应用程序 要获得当前打开的所有窗口的概览,我使用Objective c 通过OSX可访问性API获取窗口号,objective-c,cocoa,accessibility,macos-carbon,accessibility-api,Objective C,Cocoa,Accessibility,Macos Carbon,Accessibility Api,我正在开发一个可以在屏幕上移动第三方应用程序窗口的应用程序 要获得当前打开的所有窗口的概览,我使用 CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID); 这将返回定义每个打开窗口的字典数组。 以下是返回的示例词典: { kCGWindowAlpha = 1; kCGWindowBounds =
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;
},
字典中充满了其他地方使用的有用信息,但缺少可用于修改窗口位置的辅助对象。窗户由窗户编号清楚标识
我现在使用PID(KCGWindowerPID)为窗口的应用程序创建可访问性对象:
AXUIElementRef app = AXUIElementCreateApplication(pid);
然后检索应用程序使用AxUIElementCopyAttributeValue打开的所有窗口的列表:
NSArray *result;
AXUIElementCopyAttributeValues(
(AXUIElementRef) app,
kAXWindowsAttribute,
0,
99999,
(CFArrayRef *) &result
);
这将工作并返回AXUIElements数组。
这就是我被困的地方。似乎没有API调用来检索可访问性对象的窗口号。有没有什么办法
a) 找到可访问性对象的窗口号(最终遍历数组并找到正确的窗口)
或
b) 否则,请将CGWindowListCopyWindowInfo返回的数组中描述的窗口与AxuiElementCopyAttributeValue返回的辅助功能对象明确匹配?我们为此任务雇佣了一名专门的辅助功能开发人员 事实证明,如果不使用未记录的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窗口编号:
\u AXUIElementGetWindow
。
更多细节请参见SO讨论
看起来好像没有公共API来以100%的概率完成任务。通过标题和框架识别窗口(如上面的回答所述)将在99.9%的情况下起作用。对于那些可以使用未记录API的窗口,如何做到这一点?