通过OSX辅助功能API获取窗口编号 [英] Getting Window Number through OSX Accessibility API

查看:2786
本文介绍了通过OSX辅助功能API获取窗口编号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



要查看所有当前打开的窗口的概述, p>

  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,& ;点); 
AXValueGetValue(sizeValue,kAXValueCGSizeType,& size);

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

循环通过所有打开的窗口的开销在OSX上可以忽略不计。有多少窗口同时打开。



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


I am working on an application that moves windows of third party applications around on the screen.

To get an overview of all currently open windows, I use

CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);

This returns an array of dictionaries defining every open window. Here's an exemplary dictionary returned:

{
    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;
},

The dictionary is full of good information used elsewhere but lacks an accessibility object that could be used to modify the windows' positions. Windows are clearly identified by the Window Number.

I am now using the PID (kCGWindowOwnerPID) to create an accessibility object for the window's application:

AXUIElementRef app = AXUIElementCreateApplication(pid);

Followed by retrieving a list of all windows the application has opened using AXUIElementCopyAttributeValues:

NSArray *result;

AXUIElementCopyAttributeValues(
                               (AXUIElementRef) app, 
                               kAXWindowsAttribute,
                               0,
                               99999,
                               (CFArrayRef *) &result
                               );

This works and returns an array of AXUIElements. This is where I am stuck. There seems to be no API call to retrieve the Window Number of an accessibility object. Is there any way to either

a) Find the accessibility object's Window Number (to ultimately iterate over the array and find the right window)

or

b) Otherwise clearly match a window described in the array returned by CGWindowListCopyWindowInfo to the Accessibility Objects returned by AXUIElementCopyAttributeValues?

解决方案

We ended up hiring a dedicated Accessibility Developer for this task.

It turns out there is no way to do this without using undocumented APIs (a no go in our case).

Luckily, there is a practical workaround:

Loop over all open windows of the app. Get their position, size and title:

AXUIElementCopyAttributeValue(target, kAXPositionAttribute, CFTypeRef*)&posValue);
AXUIElementCopyAttributeValue(target, kAXSizeAttribute, (CFTypeRef*)&sizeValue);
AXUIElementCopyAttributeValue(target, kAXTitleAttribute, (CFTypeRef*)&titleValue);

Next, convert the position and size into actual CGPoint and CGSize values:

AXValueGetValue(posValue, kAXValueCGPointType, &point);
AXValueGetValue(sizeValue, kAXValueCGSizeType, &size);

Compare the size, position and title against the values returned by the object in CGWindowListCopyWindowInfo(). If they match, you can safely assume it's the window you were looking for and use the already open AXUIElement (target in our case) to work it.

The overhead for looping through all open windows turns out to be negligible on OSX. There is a pretty low cap on how many windows are open at the same time.

Also, while this is not 100% accurate (it is possible that 2 windows have the same position, size and title), we haven't encountered any situation in real usage where this happens so far.

这篇关于通过OSX辅助功能API获取窗口编号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆