Переместите другие окна в Mac OS X, используя Accessibility API

Я пытаюсь использовать Accessibility API, чтобы изменить положение окон других приложений. Что я хочу сделать, это получить все окна на экране из всех приложений, а затем переместить их все с заданным смещением (скажем, 5 или 10). или любое значение). У меня возникают трудности с этим, так как для меня это первый день программирования в Objective-C.

Вот что я сейчас делаю. Во-первых, я нахожу список окон и их PID, используя CGWindowListCopyWindowInfo, Затем для каждого окна я использую AXUIElementCreateApplication чтобы получить AXUIElementRef окна. После того, что я должен использовать AXUIElementCopyAttributeValue с атрибутом kAXPositionAttribute (что мне не удается получить правильную позицию, всегда получить нули). Наконец, я должен добавить требуемое смещение к позиции и использовать AXUIElementSetAttributeValue с атрибутом kAXPositionAttribute и новая точка положения (что я получаю ошибки во время выполнения, даже если я устанавливаю абсолютные значения, такие как 0,0).

Может ли кто-нибудь помочь мне с фрагментом, выполнив то, что я описал выше, так как я попробовал много вещей без какой-либо удачи. Кроме того, это не должно быть точно так, как я решил реализовать это выше. Если есть лучший способ сделать это, тогда я буду рад изменить это.

Обновление: в соответствии с просьбой в комментарии приведен фрагмент кода одной из попыток:

// 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);
}

1 ответ

Решение

Основываясь на вашем примере кода (слегка измененном, поскольку то, что вы опубликовали, не скомпилируется и не будет изменено), я провел несколько экспериментов.

Вот несколько предостережений:

  • Вы извлекаете приложение по PID, но затем воздействуете на него, как будто это окно. В этом суть вашей проблемы, но это только начало решения.
  • Вам нужно будет пройти список окон для объекта приложения специальных возможностей, чтобы найти перемещаемые окна, которые можно перемещать с помощью Accessibility Framework.
  • CGWindowListCopyWindowInfo будет возвращать окна "все на экране", когда их спросят, как вы их называете, но это не гарантирует, что это "пользовательские окна" или окна с доступностью. Большинство элементов строки меню имеют корневое окно, которое находится "на экране", и большинство из них недоступны (который появляется, когда вы пытаетесь просмотреть дерево доступности для PID, которые вы получаете).
  • Вам может пригодиться тест на AXRole или другие атрибуты доступности окна, более полезные при определении, перемещать окна или нет.

Я включил сюда модификации вашего кода (они будут работать без сбоев), которые будут извлекать соответствующую информацию о окнах из приложений, которые вы извлекаете через PID, а затем перемещать окна. У меня есть оператор сна, чтобы я мог остановить выполнение, так как я только проверял эффект движения:

#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);
    }       
    }
}
Другие вопросы по тегам