2014-01-11 83 views
9

我試圖使用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

回答

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(取決於其窗口可用的應用程序的使用情況)可幫助您決定要移動的窗口,例如「kAXSystemWideRole」,「kAXSheetRole」。您可以使用「輔助功能檢查器」(現在安裝爲Xcode的一部分)查看自己的系統。 – gaige