Переместите другие окна в 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);
}
}
}