2009-05-12 132 views

回答

41

您需要使用位于ApplicationServices框架内的可访问性API,它们是plain-C。例如:

首先创建一个应用程序对象:

AXUIElementRef app = AXUIElementCreateApplication(targetApplicationProcessID); 

然后你从这个获取窗口。您可以请求窗口列表并枚举,或者您可以获得最前面的窗口(查看AXAttributeConstants.h中所有您将使用的属性名称)。

AXUIElementRef frontWindow = NULL; 
AXError err = AXUIElementCopyAttributeValue(app, kAXMainWindowAttribute, &frontWindow); 
if (err != kAXErrorSuccess) 
    // it failed -- maybe no main window (yet) 

现在,当此窗口的属性更改时,您可以通过C回调函数请求通知。这是一个四个步骤:

首先你需要一个回调函数来接收通知:

void MyAXObserverCallback(AXObserverRef observer, AXUIElementRef element, 
          CFStringRef notificationName, void * contextData) 
{ 
    // handle the notification appropriately 
    // when using ObjC, your contextData might be an object, therefore you can do: 
    SomeObject * obj = (SomeObject *) contextData; 
    // now do something with obj 
} 

接下来,你需要一个AXObserverRef,管理回调函数。这需要你用来创建上面的“应用”元素相同的进程ID:

AXObserverRef observer = NULL; 
AXError err = AXObserverCreate(applicationProcessID, MyObserverCallback, &observer); 
if (err != kAXErrorSuccess) 
    // handle the error 

已经得到了你的观察,下一步就是要求某些事情的通知。见AXNotificationConstants.h完整的列表,但窗口的变化,你可能只需要两个:

AXObserverAddNotification(observer, frontWindow, kAXMovedNotification, self); 
AXObserverAddNotification(observer, frontWindow, kAXResizedNotification, self); 

注意,最后一个参数有传递一个假设“自我”的对象作为contextData。这不被保留,所以当这个对象消失时重要的是调用AXObserverRemoveNotification

已经得到了你的观察者和补充通知的要求,你现在想观察者附加到您runloop这样你就可以以异步方式来发送这些通知(或者实际上在所有):

CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop], 
        AXObserverGetRunLoopSource(observer), 
        kCFRunLoopDefaultMode); 

AXUIElementRef小号是CoreFoundation样式的对象,因此您需要使用CFRelease()来清除它们。例如,对于这里的清洁,一旦获得frontWindow元素,就会使用CFRelease(app),因为您不再需要该应用程序。

约垃圾收集的说明:为了保持一个AXUIElementRef作为成员变量,声明它像这样:

__strong AXUIElementRef frontWindow; 

这指示垃圾收集器,以保持此引用它的轨道。分配时,为了与GC和非GC兼容,请使用:

frontWindow = (AXUIElementRef) CFMakeCollectable(CFRetain(theElement)); 
+0

非常详细和有趣的答案。谢谢! – 2011-09-26 12:58:59

+1

伟大的起点!不要忘记查看文档https://developer.apple。com/library/mac/documentation/Accessibility/Reference/AccessibilityLowlevel/AccessibilityLowlevel.pdf和示例应用程序https://developer.apple.com/library/mac/#samplecode/iChatStatusFromApplication/Introduction/Intro.html – vinzenzweber 2013-03-16 16:49:27

+2

也是UIElementInspector示例项目似乎很有帮助https://developer.apple.com/library/mac/#samplecode/UIElementInspector/Introduction/Intro.html – vinzenzweber 2013-03-16 16:52:17

3

进一步研究打开了“石英显示服务”

有趣的功能,我的需求是CGRegisterScreenRefreshCallback。

相关问题