如何使用Cocoa的辅助功能API来检测一个窗口是否被置于前台?

16

我正在使用辅助功能API来检测特定应用程序打开窗口、关闭窗口、移动或调整大小的情况,或使窗口成为主要和/或焦点。但是,客户端应用程序似乎将窗口移到前面时,没有触发辅助功能API通知。

我的应用程序如何检测另一个应用程序将窗口移至前台,而不使其成为键盘焦点?

我希望找到在OS X 10.4和10.5上都能运行的解决方案。

更多信息: 目前,我正在使用这些语句。当用户手动选择一个窗口将其移到前面时,它们可以正常工作。但当应用程序本身将窗口移到前面时,它们无法正常工作。

AXObserverAddNotification(observer, element, kAXMainWindowChangedNotification, 0);
AXObserverAddNotification(observer, element, kAXFocusedWindowChangedNotification, 0);
4个回答

9

我一直无法订阅当前窗口的更改,但您可以向辅助功能API请求当前应用程序和当前应用程序中最前面的窗口。

想象一下,您有一个名为CurrentAppData的类,其中包含以下数据:

@interface CurrentAppData : NSObject {
    NSString* _title;
    AXUIElementRef _systemWide;
    AXUIElementRef _app;
    AXUIElementRef _window;
}

查找当前应用程序的代码大致如下:

-(void) updateCurrentApplication {
   // get the currently active application  
   _app = (AXUIElementRef)[CurrentAppData
                           valueOfExistingAttribute:kAXFocusedApplicationAttribute 
                                        ofUIElement:_systemWide];

   // Get the window that has focus for this application
   _window = (AXUIElementRef)[CurrentAppData 
                              valueOfExistingAttribute:kAXFocusedWindowAttribute 
                                           ofUIElement:_app];

   NSString* appName = [CurrentAppData descriptionOfValue:_window
                                             beingVerbose:TRUE];    

   [self setTitle:appName];
}

在这个例子中,_systemWide变量在类的init函数中被初始化,如下所示: _system = AXUIElementCreateSystemWide();
valueOfExistingAttribute类函数看起来像这样:
// -------------------------------------------------------------------------------
//  valueOfExistingAttribute:attribute:element
//
//  Given a uiElement and its attribute, return the value of an accessibility
//  object's attribute.
// -------------------------------------------------------------------------------
+ (id)valueOfExistingAttribute:(CFStringRef)attribute ofUIElement:(AXUIElementRef)element
{
    id result = nil;
    NSArray *attrNames;

    if (AXUIElementCopyAttributeNames(element, (CFArrayRef *)&attrNames) == kAXErrorSuccess) 
    {
        if ( [attrNames indexOfObject:(NSString *)attribute] != NSNotFound
                &&
            AXUIElementCopyAttributeValue(element, attribute, (CFTypeRef *)&result) == kAXErrorSuccess
        ) 
        {
            [result autorelease];
        }
        [attrNames release];
    }
    return result;
}

这个之前的函数是从苹果的UIElementInspector示例中提取的,这也是了解无障碍API的好资源。


5

5
在Mac OS X中,应用程序和窗口是完全独立的,应用程序包含窗口;它们不像Microsoft Windows那样是同一个东西。您需要检测每个应用程序的激活和停用。
您可以通过观察和来实现这一点。这些通知的对象是被激活和停用的应用程序。您还需要检测应用程序的启动和退出;您可以使用Process Manager或NSWorkspace来完成此操作。这两个API都可以为您提供进程ID,您可以使用它来创建AXApplication对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接