15

アクセシビリティ API を使用して、他のアプリケーション ウィンドウの位置を変更しようとしています。私がやりたいことは、すべてのアプリケーションから画面上のすべてのウィンドウを取得し、それらすべてを特定のオフセット (5 または 10 としましょう) に移動することです。または任意の値)。これは私にとってObjective-Cでのプログラミングの初日であるため、これを行うのに苦労しています。

これが私が今していることです。まず、 を使用してウィンドウとその PID のリストを見つけますCGWindowListCopyWindowInfo。次に、ウィンドウごとに、ウィンドウAXUIElementCreateApplicationの を取得するために使用しAXUIElementRefます。その後、AXUIElementCopyAttributeValue属性で使用する必要がありますkAXPositionAttribute(適切な位置を取得できず、常にゼロを取得します)。最後に、必要なオフセットを位置に追加AXUIElementSetAttributeValueし、属性kAXPositionAttributeと新しい位置ポイントを使用する必要があります (0,0 のような絶対値を設定しても実行時エラーが発生します)。

運が悪くて多くのことを試したので、誰かが私が上で説明したことを行うスニペットで私を助けることができますか. また、上記で実装することにしたとおりである必要はありません。それを行うためのより良い方法があれば、喜んで変更します。

更新: コメントで要求されているように、試みの 1 つのコード スニペットを次に示します。

// Get all the windows
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
NSArray* arr = CFBridgingRelease(windowList);
// Loop through the windows
for (NSMutableDictionary* entry in arr)
{
    // Get window PID
    pid_t pid = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
    // Get AXUIElement using PID
    AXUIElementRef elementRef = AXUIElementCreateApplication(pid);
    CFTypeRef position;
    CGPoint point;
    // Get the position attribute of the window (maybe something is wrong?)
    AXUIElementCopyAttributeValue(elementRef, kAXPositionAttribute, (CFTypeRef *)&position);
    AXValueGetValue(position, kAXValueCGPointType, &point);
    // Debugging (always zeros?)
    NSLog(@"point=%@", point);
    // Create a point
    NSPoint newPoint;
    newPoint.x = 0;
    newPoint.y = 0;
    position = (CFTypeRef)(AXValueCreate(kAXValueCGPointType, (const void *)&newPoint));
    // Set the position attribute of the window (runtime error over here)
    AXUIElementSetAttributeValue(elementRef, kAXPositionAttribute, (CFTypeRef *)&position);
}
4

1 に答える 1

24

あなたのサンプル コード (あなたが投稿したものはコンパイルされず、変更されていないとクラッシュするため、わずかに変更されています) に基づいて、いくつかの実験を行いました。

以下にいくつかの注意事項を示します。

  • PID によってアプリケーションを取得していますが、ウィンドウであるかのように動作しています。それが問題の核心ですが、それは解決策の始まりに過ぎません。
  • アクセシビリティ フレームワークで移動できる再配置可能なウィンドウを見つけるには、アクセシビリティ アプリケーション オブジェクトのウィンドウ リストを調べる必要があります。
  • CGWindowListCopyWindowInfoは、呼び出し方を尋ねられたときに「画面上のすべて」のウィンドウを返しますが、これらが「ユーザー ウィンドウ」またはアクセシビリティのあるウィンドウのいずれかであることを保証するものではありません。ほとんどのメニュー バー項目には、「画面上」にあるルート ウィンドウがあり、それらのほとんどにアクセスできません (取得した PID のアクセシビリティ ツリーをたどろうとすると表示されます)。
  • AXRole のテストが役立つ場合もあれば、ウィンドウを移動するかどうかを判断するのに他のウィンドウ アクセシビリティ属性の方が役立つ場合もあります。

ここでは、PID を介して取得したアプリケーションから適切なウィンドウ情報を取得し、ウィンドウを移動するコードへの変更を含めました (これはクラッシュせずに実行されます)。動きの影響をテストしていたので、実行を停止できるように sleep ステートメントがあります。

#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <ApplicationServices/ApplicationServices.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {
    // Get all the windows
    CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
    NSArray* arr = CFBridgingRelease(windowList);
    // Loop through the windows
    for (NSMutableDictionary* entry in arr)
    {
        // Get window PID
        pid_t pid = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
        // Get AXUIElement using PID
        AXUIElementRef appRef = AXUIElementCreateApplication(pid);
        NSLog(@"Ref = %@",appRef);

        // Get the windows
        CFArrayRef windowList;
        AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute, (CFTypeRef *)&windowList);
        NSLog(@"WindowList = %@", windowList);
        if ((!windowList) || CFArrayGetCount(windowList)<1)
            continue;


        // get just the first window for now
        AXUIElementRef windowRef = (AXUIElementRef) CFArrayGetValueAtIndex( windowList, 0);
        CFTypeRef role;
        AXUIElementCopyAttributeValue(windowRef, kAXRoleAttribute, (CFTypeRef *)&role);         
        CFTypeRef position;
        CGPoint point;

        // Get the position attribute of the window (maybe something is wrong?)
        AXUIElementCopyAttributeValue(windowRef, kAXPositionAttribute, (CFTypeRef *)&position);
        AXValueGetValue(position, kAXValueCGPointType, &point);
        // Debugging (always zeros?)
        NSLog(@"point=%f,%f", point.x,point.y);
        // Create a point
        CGPoint newPoint;
        newPoint.x = 0;
        newPoint.y = 0;
        NSLog(@"Create");
        position = (CFTypeRef)(AXValueCreate(kAXValueCGPointType, (const void *)&newPoint));
        // Set the position attribute of the window (runtime error over here)
        NSLog(@"SetAttribute");
        AXUIElementSetAttributeValue(windowRef, kAXPositionAttribute, position);
        sleep(5);
    }       
    }
}
于 2014-01-12T22:16:26.833 に答える