使用Accessibility API在Mac OS X上移动其他窗口 [英] Move other windows on Mac OS X using Accessibility API

查看:143
本文介绍了使用Accessibility API在Mac OS X上移动其他窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Accessibility API来更改其他应用程序窗口的位置.我希望做的是从所有应用程序中获取屏幕上的所有窗口,然后将它们移至所有给定的偏移量(让我们说5或10或任何值).我很难做到这一点,因为这对我来说是Objective-C编程的第一天.

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 applications, then move them all a given offset (lets say 5 or 10 or any value). I am having difficulties doing this since this is day one of programming in Objective-C for me.

这就是我现在正在做的事情.首先,我使用CGWindowListCopyWindowInfo查找窗口及其PID的列表.然后,对于每个窗口,我使用AXUIElementCreateApplication来获取窗口的AXUIElementRef.之后,我应该将AXUIElementCopyAttributeValue与属性kAXPositionAttribute一起使用(我无法获得正确的位置,总是得到零).最后,我应该在位置上添加所需的偏移量,并将AXUIElementSetAttributeValue与属性kAXPositionAttribute和新的位置点一起使用(即使我将绝对值设置为0,0,也会出现运行时错误).

Here is what I am doing right now. First, I find the list of windows and their PIDs using CGWindowListCopyWindowInfo. Then, for each window I use AXUIElementCreateApplication to get the AXUIElementRef of the window. After, that I should use AXUIElementCopyAttributeValue with the attribute kAXPositionAttribute (which I fail in getting the proper position, always get zeros). Finally, I should add the wanted offset to the position and use AXUIElementSetAttributeValue with the attribute kAXPositionAttribute and the new position point (which I get runtime errors even if I set absolute values like 0,0).

当我尝试了很多没有运气的事情时,有人可以帮助我完成上面所述的内容吗?另外,它不必完全像我决定在上面实现它一样.如果有更好的方法可以做到这一点,那么我很乐意对其进行更改.

Can someone help me with a snippet doing what I described above, as I tried many things without any luck. Also, it shouldn't need to be exactly as I decided to implement it above. If there is a better way to go about doing that, then I'll be happy to change it.

更新: 根据评论的要求,以下是其中一种尝试的代码段:

Update: As requested in the comment, here is a code snippet of one of the attempts:

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

推荐答案

根据您的示例代码(稍作修改,因为您发布的内容无法编译,并且会在未修改的情况下崩溃),所以我做了一些实验.

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

以下是一些警告:

  • 您正在通过PID检索应用,但随后对其进行处理就好像它是一个窗口一样.那是您问题的核心,但这仅仅是解决方案的开始.
  • 您将需要遍历可访问性应用程序对象的窗口列表,以便找到可随可访问性框架一起移动的可重定位窗口.
  • 当询问您
  • CGWindowListCopyWindowInfo的调用方式时,它将返回所有屏幕"窗口,但不能保证这些窗口是用户窗口"或具有辅助功能的窗口.大多数菜单栏项目都有一个在屏幕上"的根窗口,并且其中大多数是不可访问的(当您尝试遍历检索到的PID的可访问性树时会显示该窗口).
  • 您可能会发现AXRole的测试会有所帮助,或者您可能会发现其他窗口可访问性属性对于确定是否移动窗口更为有用.
  • 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.

我在这里包括对您的代码的修改(它将在不崩溃的情况下运行),它将从您通过PID检索的应用程序中获取相关的窗口信息,然后移动窗口.我有一个sleep语句,因此我可以停止执行,因为我只是在测试运动的效果:

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);
    }       
    }
}

这篇关于使用Accessibility API在Mac OS X上移动其他窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆