在Mac上的Cocoa上,我想要检测属于其他应用程序的窗口何时被移动,调整大小或重新绘制。我怎样才能做到这一点?我的应用程序如何检测到另一个应用程序窗口的更改?
12
A
回答
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));
3
进一步研究打开了“石英显示服务”
有趣的功能,我的需求是CGRegisterScreenRefreshCallback。
相关问题
- 1. 检测应用程序窗口
- 2. 更改应用程序窗口样式
- 3. 如何让另一个应用程序的窗口透明?
- 4. 从我的应用程序调用另一个应用程序
- 5. 从另一个桌面找到应用程序的窗口
- 6. 如何在我的应用程序的窗口中运行另一个Android应用程序/活动
- 7. 如何使另一个应用程序的窗口的父窗口?
- 8. 用OpenGL绘制到另一个应用程序窗口
- 9. 从我的应用程序打开另一个应用程序?
- 10. android:我如何从我的应用程序打开另一个应用程序?
- 11. 从另一个应用程序更改应用程序的变量
- 12. 如何检测另一个应用程序何时使用我的web服务?
- 13. 如何更改另一个应用程序的屏幕方向
- 14. 获取另一个应用程序窗口的唯一ID
- 15. 看不到我的第一个窗口应用程序
- 16. addChild我的窗口到其他应用程序的窗口
- 17. 如何在我的应用程序的MDI窗口中显示另一个进程的窗口
- 18. 如何使用VB.Net从另一个应用程序更改一个应用程序的UserSettings值?
- 19. 如何从我的应用程序打开另一个应用程序?
- 20. 测试Web应用程序:在另一个窗口“镜报”的ad-hoc测试
- 21. 如何更改Surface应用程序的应用程序方向
- 22. 如何在IPhone窗口应用程序中显示另一个窗口
- 23. 窗口应用程序到web应用程序
- 24. 从C#中的另一个应用程序显示WPF窗口#
- 25. 在另一个应用程序中的OpenGL窗口
- 26. 从我的应用程序打开pdf到另一个pdfviewer应用程序
- 27. 将应用程序加载到另一个应用程序中
- 28. 应用程序重定向到另一个应用程序
- 29. 检测页面更改为一个页面应用程序JS
- 30. AngularJs应用程序无法从另一个窗口侦听localStorage更改
非常详细和有趣的答案。谢谢! – 2011-09-26 12:58:59
伟大的起点!不要忘记查看文档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
也是UIElementInspector示例项目似乎很有帮助https://developer.apple.com/library/mac/#samplecode/UIElementInspector/Introduction/Intro.html – vinzenzweber 2013-03-16 16:52:17