使用Accessibility API在Mac OS X上移动其他窗口

使用Accessibility API在Mac OS X上移动其他窗口

问题描述:

我试图使用Accessibility API来更改其他应用程序窗口的位置。我想要做的是从所有应用程序获取屏幕上的所有窗口,然后将它们全部移到给定的偏移量(可以说5或10或任何值)。我在这方面遇到了困难,因为这是Objective-C编程的第一天。使用Accessibility API在Mac OS X上移动其他窗口

这是我现在正在做的。首先,我使用CGWindowListCopyWindowInfo找到窗口列表和它们的PID。然后,对于每个窗口,我使用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); 
} 
+0

后的代码,使人们可以看到你开始用什么。 – gaige

+0

这是在步骤解释,我有什么不工作,所以我认为不需要一个不工作的。我已经用这个片段更新了它。 – tria

基于您的示例代码(略作修改,为你所发布的不编译会崩溃未修改),我做了一些实验。

这里有几个注意事项:

  • 您是通过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(取决于其窗口可用的应用程序的使用情况)可帮助您决定要移动的窗口,例如“kAXSystemWideRole”,“kAXSheetRole”。您可以使用“辅助功能检查器”(现在安装为Xcode的一部分)查看自己的系统。 – gaige