我的应用程式如何侦测到其他应用程式视窗的变更? [英] How can my app detect a change to another app's window?

查看:601
本文介绍了我的应用程式如何侦测到其他应用程式视窗的变更?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Mac上的Cocoa中,我想检测属于另一个应用程序的窗口何时被移动,调整大小或重新绘制。

In Cocoa on the Mac, I'd like to detect when a window belonging to another app is moved, resized, or repainted. How can I do this?

推荐答案

您需要使用Accessibility API框架。例如:

You would need to use the Accessibility APIs, which are plain-C, located inside the ApplicationServices framework. For instance:

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

First you create an application object:

AXUIElementRef app = AXUIElementCreateApplication( targetApplicationProcessID );

然后你从这里得到窗口。你可以请求窗口列表和枚举,或者你可以得到最前面的窗口(看看AXAttributeConstants.h中你使用的所有属性名称)。

Then you get the window from this. You can request the window list and enumerate, or you can get the frontmost window (look in AXAttributeConstants.h for all the attribute names you'd use).

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

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

Now you can request notification via a C callback function when a property of this window changes. This is a four-step process:

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

First you need a callback function to receive the notifications:

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 ,它管理回调例程。这需要与上面创建app元素时使用的相同的进程ID:

Next you need an AXObserverRef, which manages the callback routine. This requires the same process ID you used to create the 'app' element above:

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

得到你的观察者,下一步是要求通知某些事情。参见AXNotificationConstants.h获取完整列表,但对于窗口更改,您可能只需要这两个:

Having got your observer, the next step is to request notification of certain things. See AXNotificationConstants.h for the full list, but for window changes you'll probably only need these two:

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

注意,最后一个参数是传递一个假设的self对象作为contextData。这不保留,因此当此对象消失时,调用 AXObserverRemoveNotification 很重要。

Note that the last parameter there is passing an assumed 'self' object as the contextData. This is not retained, so it's important to call AXObserverRemoveNotification when this object goes away.

有了你的观察者和添加通知请求,现在您想要将观察者附加到您的runloop,以便您可以以异步方式(或甚至完全)发送这些通知:

Having got your observer and added notification requests, you now want to attach the observer to your runloop so you can be sent these notifications in an asynchronous manner (or indeed at all):

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

AXUIElementRef 是CoreFoundation风格的对象,所以你需要使用 CFRelease()来干净地处理它们。在这里,为了清洁,例如,一旦你获得了frontWindow元素,你将使用 CFRelease(app),因为你不再需要该应用程序。

AXUIElementRefs are CoreFoundation-style objects, so you need to use CFRelease() to dispose of them cleanly. For cleanliness here, for example, you would use CFRelease(app) once you've obtained the frontWindow element, since you'll no longer need the app.

有关Garbage-Collection的注意事项:要将AXUIElementRef保留为成员变量,请按如下所示进行声明:

A note about Garbage-Collection: To keep an AXUIElementRef as a member variable, declare it like so:

__strong AXUIElementRef frontWindow;

这会指示垃圾回收器跟踪此引用。当分配它时,为了与GC和非GC兼容,使用:

This instructs the garbage collector to keep track of this reference to it. When assigning it, for compatibility with GC and non-GC, use this:

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

这篇关于我的应用程式如何侦测到其他应用程式视窗的变更?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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