2014-01-11 4 views
9

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

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

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

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

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

Post код одного из ваших попыток, чтобы люди могли видеть, что вы начали. – gaige

+0

Это было объяснено шагами, и то, что у меня было, не работает, поэтому я не думал, что вам нужно работать. Я обновил его с помощью фрагмента. – tria

ответ

18

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

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

  • Вы извлекая Применение по PID, но действуя на него, как будто это окно. В этом суть вашей проблемы, но это только начало решения.
  • Вам нужно будет просмотреть список окон для объекта приложения доступности, чтобы найти перемещаемые окна, которые вы можете перемещать с помощью платформы специальных возможностей.
  • 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); 
    }  
    } 
} 
+0

+1 Удивительный ответ. – Caleb

+0

Отличный ответ, спасибо! Проголосовало и выбрано. Однако не могли бы вы подробно остановиться на использовании AXRole, как это будет полезно в этом случае? – tria

+0

@tria AXRole (в зависимости от его использования приложениями, доступными для Windows) может помочь вам решить, какие окна двигаться, например, 'kAXSystemWideRole',' kAXSheetRole'. Вы можете осмотреть свою собственную систему с помощью «Accessibility Inspector» (установленного в Xcode в наши дни). – gaige