26

画面上でサードパーティ製アプリケーションのウィンドウを移動するアプリケーションに取り組んでいます。

現在開いているすべてのウィンドウの概要を取得するには、次を使用します

CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);

これは、開いているすべてのウィンドウを定義する辞書の配列を返します。返される辞書の例を次に示します。

{
    kCGWindowAlpha = 1;
    kCGWindowBounds =         {
        Height = 442;
        Width = 475;
        X = 3123;
        Y = "-118";
    };
    kCGWindowIsOnscreen = 1;
    kCGWindowLayer = 0;
    kCGWindowMemoryUsage = 907184;
    kCGWindowName = Untitled;
    kCGWindowNumber = 7328;
    kCGWindowOwnerName = TextEdit;
    kCGWindowOwnerPID = 20706;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
    kCGWindowWorkspace = 3;
},

ディクショナリには、他の場所で使用される優れた情報が満載ですが、ウィンドウの位置を変更するために使用できるアクセシビリティ オブジェクトがありません。ウィンドウは、ウィンドウ番号によって明確に識別されます。

現在、PID (kCGWindowOwnerPID) を使用して、ウィンドウのアプリケーションのアクセシビリティ オブジェクトを作成しています。

AXUIElementRef app = AXUIElementCreateApplication(pid);

次に、AXUIElementCopyAttributeValues を使用して、アプリケーションが開いたすべてのウィンドウのリストを取得します。

NSArray *result;

AXUIElementCopyAttributeValues(
                               (AXUIElementRef) app, 
                               kAXWindowsAttribute,
                               0,
                               99999,
                               (CFArrayRef *) &result
                               );

これは機能し、AXUIElements の配列を返します。これは私が立ち往生しているところです。アクセシビリティ オブジェクトのウィンドウ番号を取得するための API 呼び出しはないようです。いずれかの方法はありますか

a) アクセシビリティ オブジェクトのウィンドウ番号を検索します (最終的に配列を反復処理して、適切なウィンドウを見つけます)。

また

b) それ以外の場合、CGWindowListCopyWindowInfo によって返される配列に記述されたウィンドウが、AXUIElementCopyAttributeValues によって返されるアクセシビリティ オブジェクトに明確に一致しますか?

4

2 に答える 2

28

最終的に、このタスクのために専任のアクセシビリティ開発者を雇うことになりました。

文書化されていない API を使用しないと、これを行う方法がないことがわかりました (この場合はできません)。

幸いなことに、実用的な回避策があります。

アプリの開いているすべてのウィンドウをループします。位置、サイズ、およびタイトルを取得します。

AXUIElementCopyAttributeValue(target, kAXPositionAttribute, CFTypeRef*)&posValue);
AXUIElementCopyAttributeValue(target, kAXSizeAttribute, (CFTypeRef*)&sizeValue);
AXUIElementCopyAttributeValue(target, kAXTitleAttribute, (CFTypeRef*)&titleValue);

CGPoint次に、位置とサイズを実際のCGSize値に変換します。

AXValueGetValue(posValue, kAXValueCGPointType, &point);
AXValueGetValue(sizeValue, kAXValueCGSizeType, &size);

サイズ、位置、およびタイトルを、 のオブジェクトによって返される値と比較しますCGWindowListCopyWindowInfo()。それらが一致する場合は、それが探していたウィンドウであると安全に想定し、既に開いている AXUIElement (targetこの場合) を使用してそれを操作できます。

開いているすべてのウィンドウをループするためのオーバーヘッドは、OSX では無視できることがわかりました。同時に開いているウィンドウの数にはかなり低い上限があります。

また、これは 100% 正確ではありませんが (2 つのウィンドウの位置、サイズ、タイトルが同じである可能性があります)、これまでのところ、実際の使用状況でこれが発生する状況に遭遇したことはありません。

于 2011-06-15T22:19:10.397 に答える
12

window: の特定の AX オブジェクトの CG ウィンドウ番号を取得するためのプライベート関数があります_AXUIElementGetWindow。SO ディスカッションの詳細OS X でアクティブなウィンドウを一意に識別する 100% の確率でタスクを実行するパブリック API はないようです。タイトルとフレーム (上記の回答で説明したように) でウィンドウを識別すると、99.9% のケースで機能します。

于 2013-08-19T17:15:12.070 に答える