2009-05-12 11 views

答えて

41

ApplicationServicesフレームワーク内にあるプレーンCのアクセシビリティAPIを使用する必要があります。例えば:

まず、アプリケーションオブジェクトを作成します。

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コールバック関数を介して通知を要求できます。これは、4段階のプロセスです:

まず、通知を受信するコールバック関数を必要とする:

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 

あなたのオブザーバーを得たが、次のステップは、特定の物事の通知を要求することです。最後のパラメータはcontextDataとし「自己」のオブジェクトが渡されることを

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

注:完全なリストについては、しかし、ウィンドウのAXNotificationConstants.hを参照してくださいあなたはおそらく唯一のこれら二つが必要になります変更します。これは保持されないので、このオブジェクトがなくなるとAXObserverRemoveNotificationに電話することが重要です。

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

AXUIElementRef秒:

は、あなたが今、あなたは(実際に全くまたは)、非同期的にこれらの通知を送ることができるように、実行ループにオブザーバーを添付したい、あなたのオブザーバーを持って、通知要求を追加しましたCoreFoundationスタイルのオブジェクトなので、完全に破棄するにはCFRelease()を使用する必要があります。例えばここでは、フロントウインドウの要素を取得したら、CFRelease(app)を使用します。これは、アプリケーションが不要になるためです。

ガベージ・コレクションに関する注意:そうのようにそれを宣言し、メンバ変数としてAXUIElementRefを保つために:

__strong AXUIElementRef frontWindow; 

これはそれまで、この参照を追跡するために、ガベージコレクタを指示します。それを割り当てるときは、GCと非GCとの互換性のために、次のように使用してください:

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

非常に不評で興味深い答えです。ありがとう! –

+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

+2

また、UIElementInspectorサンプルプロジェクトは非常に役に立つと思われます。https://developer.apple.com/library/mac/#samplecode/UIElementInspector/Introduction/Intro.html – vinzenzweber

3

さらなる研究は、「クォーツ表示サービス」を自分のニーズに

興味深い機能がCGRegisterScreenRefreshCallbackされるまでになりました。

関連する問題