唯一标识OS X上的活动窗口 [英] Uniquely identify active window on OS X

查看:447
本文介绍了唯一标识OS X上的活动窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要尝试修补使用辅助功能API调整窗口大小的应用程序



我需要维护一个具有以前大小的窗口的字典。键需要标识当前活动的窗口。目前,此活动窗口通过

但是,如果按下热键,Apple_ref / doc / c_ref / NSAccessibilityFocusedWindowAttribute> NSAccessibilityFocusedWindowAttribute ,每次调用此方法时,返回标识窗口 AXUIElementRef 不同!这当然意味着我不能使用它作为字典键 - 字典将不会找到相应的条目。



以下代码再现问题:

   - (IBAction)testWindowIdentification:(id)sender {
AXUIElementRef focusedApp;
AXUIElementRef focusedWindow;

AXUIElementCopyAttributeValue(_systemWideElement,
(CFStringRef)kAXFocusedApplicationAttribute,
(CFTypeRef *)& focusedApp);
AXUIElementCopyAttributeValue((AXUIElementRef)focusedApp,
(CFStringRef)NSAccessibilityFocusedWindowAttribute,
(CFTypeRef *)& focusedWindow);
CFShow(focusedWindow);
}

_systemWideElement init 方法中使用 AXUIElementCreateSystemWide()的调用来初始化。

CFShow 语句在每次调用方法时都会清楚地显示不同的ID(即使同一窗口处于活动状态),这对我来说是无用的:

 < AXUIElement 0x47e850> {pid = 42463} 
< AXUIElement 0x47e890> {pid = 42463}
< AXUIElement 0x47e2c0> {pid = 42463}
...

AXUIElement 上的.apple.com / library / mac /#documentation / Accessibility / Reference / AccessibilityLowlevel / AXUIElement_h />文档没有显示检索唯一属性的方法对于UI元素,以及 NSAccessibility 协议
唯一的PID对我来说不够,因为一个进程可以有多个窗口。



如何获取Cocoa中活动窗口的一些唯一标识符



(顺便说一下,真正的代码是检查上述调用中的返回代码;错误,调用成功。)

解决方案

Rob Keniger使用他的答案在这里。从这个答案(和确实,赏金放置的原因)的唯一的事情是一个可行的实现,它采取当前活动窗口,并将其转换为适合在当前工作应用程序的上下文中的索引的唯一键。



Rob的解决方案通过使用 CGWindowID 。当然,强烈暗示这个窗口引用是只对您当前的应用程序有用



获取此窗口引用是棘手的,因为在辅助功能API和Quartz窗口之间没有强大的保证服务。但是,您可以通过以下方式解决此问题:


  1. 使用 externCAXError _AXUIElementGetWindow (AXUIElementRef,CGWindowID * out); ,作为此处记录

    li>

    使用例如 HIWindowGetCGWindowID()直接获取 CGWindowID 。有关选择活动窗口和提取ID的详细信息,请参见


  2. 为您的 CGWindowID 使用类似 CGWindowListCreateDescriptionFromArray code> ,正如Rob建议的。这里的目标是找到用于桥接辅助功能API和Quartz的一些方案,但是这是可以想象的,例如通过使用绑定到当前活动窗口的上下文的回调。

  3. 在这些选项中,我建议您使用 2。为您的当前需要,如果你无法创建一些其他装饰窗口,以唯一标识它们。



    您的应用程式非常幸运。


    I’m trying to patch an application that resizes windows using the accessibility API.

    I need to maintain a dictionary with the previous sizes of windows. The key needs to identify the currently active window. At the moment, this active window is retrieved via NSAccessibilityFocusedWindowAttribute upon the press of a hotkey.

    However, every time this method is called, the returned AXUIElementRef which identifies the window is different! This of course means that I cannot use it as a dictionary key – the dictionary won’t find the corresponding entry.

    The following code reproduces the problem:

    -(IBAction)testWindowIdentification:(id)sender{
        AXUIElementRef focusedApp;
        AXUIElementRef focusedWindow;
    
        AXUIElementCopyAttributeValue(_systemWideElement,
                                      (CFStringRef) kAXFocusedApplicationAttribute,
                                      (CFTypeRef*) &focusedApp);
        AXUIElementCopyAttributeValue((AXUIElementRef) focusedApp,
                                      (CFStringRef) NSAccessibilityFocusedWindowAttribute,
                                      (CFTypeRef*) &focusedWindow);
        CFShow(focusedWindow);
    }
    

    _systemWideElement has been initialised in the init method using a call to AXUIElementCreateSystemWide().

    The CFShow statement clearly shows different IDs every time the method is called (even though the same window is active), which is useless for me:

    <AXUIElement 0x47e850> {pid=42463}
    <AXUIElement 0x47e890> {pid=42463}
    <AXUIElement 0x47e2c0> {pid=42463}
    …
    

    The documentation on AXUIElement shows no method that retrieves a unique attribute for the UI element, and neither does that of the NSAccessibility protocol. The unique PID is not enough for me, since a process can have multiple windows.

    How can I retrieve some unique identifier of the active window in Cocoa?

    (By the way, the real code is checking the return codes in the above calls; there is no error, the calls succeed.)

    解决方案

    Rob Keniger has the right strategy with his answer here. The only thing missing from this answer (and indeed, the reason for the bounty placement) is a workable implementation that takes the current active window and translates it into a unique key suitable for indexing in the context of the current working application.

    Rob's solution sketches this out through use of the CGWindowID given in the context of Quartz Window Services. It is, of course, strongly implied that this window reference is only useful for your current application.

    Getting this window reference is tricky, because no strong guarantees exist between the Accessibility API and Quartz Window Services. However, you can work around this in the following ways:

    1. Use extern "C" AXError _AXUIElementGetWindow(AXUIElementRef, CGWindowID* out);, as documented here. This isn't guaranteed to work, but it works as a ground-floor test to get things started if it works in your version of OSX.

    2. Get the CGWindowID directly, using, for example, HIWindowGetCGWindowID(). More details about selecting the active window and extracting the ID can be found in the reference manual for the Carbon Window Manager (warning: large PDF).

    3. Catalog your CGWindowID set using something like CGWindowListCreateDescriptionFromArray, exactly as Rob suggested. The goal here is then to find some scheme for bridging the Accessibility API and Quartz, but this is conceivable by utilizing, for example, a callback bound to the context of your current active window. I honestly don't know an optimal example of this that's properly future-proofed, however.

    Of the options, I recommend going with 2. for your current needs, if you're unable to create some other decorator for your windows to uniquely identify them. It's currently defined in the legacy code base, but it will do what you desire.

    Best of luck with your application.

    这篇关于唯一标识OS X上的活动窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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