Move other windows on Mac OS X using Accessibility API

后端 未结 1 464
醉话见心
醉话见心 2020-12-23 02:52

I\'m trying to use the Accessibility API to change the position of other applications windows.What I wish to do is to get all the windows on the screen from all the applicat

相关标签:
1条回答
  • 2020-12-23 03:12

    Based on your sample code (slightly modified, as what you posted does not compile and will crash unmodified), I did some experiments.

    Here are a few caveats:

    • You are retrieving the Application by PID, but then acting upon it as if it is a window. That's the core of your problem, but it is only the beginning of the solution.
    • You will need to walk the window list for the accessibility application object in order to find relocatable windows that you can move with the Accessibility Framework.
    • CGWindowListCopyWindowInfo will return "all on screen" windows when asked the way you're calling it, but it doesn't guarantee that these are either "user windows" or windows with accessibility. Most menu bar items have a root window which is "on screen" and most of them aren't accessible (which shows up when you try to walk the accessibility tree for the PIDs you retrieve).
    • You may find the test for AXRole to be helpful, or you may find other window accessibility attributes more useful in determining whether to move the windows or not.

    I've included here modifications to your code (this will run without crashing), which will grab the pertinent window information from the applications you retrieve via PID and then move the windows. I have a sleep statement so that I could stop execution, since I was just testing for the effect of movement:

    #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 讨论(0)
提交回复
热议问题