OS X中的窗口移动和调整大小API [英] Window move and resize APIs in OS X

查看:100
本文介绍了OS X中的窗口移动和调整大小API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在OS X上找到已记录(或未记录,如果那是我唯一的选择)的API,以从窗口服务器查询窗口列表,然后导致窗口移动和调整大小.谁能指出我正确的方向?我想我将从Win32下的FindWindowEx和MoveWindow开始.

I'm trying to find documented (or, undocumented, if that's my only option) APIs on OS X to query a list of windows from the window server and then cause the windows to move and resize. Can anyone point me in the right direction? I guess I'd be starting with something like FindWindowEx and MoveWindow under Win32.

请注意,我想从外部过程中执行此操作-我不是在问如何仅控制自己应用程序的窗口大小和位置.

Note that I want to do this from an external process - I'm not asking how to control just my own app's window size and position.

推荐答案

使用Accessibility API.使用此API,您可以连接到进程,获取窗口列表(实际上是数组),获取每个窗口的位置和大小,并根据需要更改窗口属性.

Use the Accessibility API. Using this API you can connect to a process, obtain a list of windows (actually an array), get the positions and sizes of each window and also change window properties if you like.

但是,仅当用户根据自己的喜好启用了对辅助设备的访问权限(系统偏好->通用访问权限)时,该应用程序才能使用此API,在这种情况下,所有应用程序都可以使用此API,或者如果您的应用程序是受信任的辅助应用程序(受信任时,即使未选中此选项,它也可以使用API​​). Accessibility API本身提供了使您的应用程序受信任的必要功能-基本上,您必须成为root用户(使用安全服务请求用户的root用户权限),然后将您的进程标记为受信任的.一旦您的应用程序被标记为受信任,就必须重新启动它,因为仅在启动时才检查受信任状态,并且在应用程序运行时无法更改.信任状态是永久的,除非用户将应用程序移到其他地方或应用程序的哈希值发生更改(例如,更新后).如果用户在自己的偏好中启用了辅助设备,则将所有应用程序视为受信任的应用程序.通常,您的应用会检查是否启用了此选项,如果继续,请继续执行操作.如果不是,它将检查它是否已经被信任,如果已经被信任,请再次执行您的工作.如果不是,请尝试使其自身受信任,然后重新启动应用程序,除非用户拒绝root授权.该API提供了所有必要的功能来检查所有这些内容.

However, an application can only be using this API if the user has enabled access for assistive devices in his preferences (System Prefs -> Universal Access), in which case all applications may use this API, or if your application is a trusted assitive application (when it is trusted, it may use the API, even if this option is not checked). The Accessibility API itself offers the necessary functions to make your application trusted - basically you must become root (using security services to request root permissions of the user) and then mark your process as trusted. Once your application has been marked trusted, it must be restarted as the trusted state is only checked on start-up and can't change while the app is running. The trust state is permanent, unless the user moves the application somewhere else or the hash of the application binary changes (e.g. after an update). If the user has assistive devices enabled in his prefs, all applications are treated as if they were trusted. Usually your app would check if this option is enabled, if it is, go on and do your stuff. If not, it would check if it is already trusted, if it is, again just do your stuff. If not try to make itself trusted and then restart the application unless the user declined root authorization. The API offers all necessary functions to check all this.

存在使用Mac OS窗口管理器执行相同操作的私有功能,但是可以买到您的唯一好处是您不必是受信任的Accessibility应用程序(该应用程序在Windows首次启动时即进行一次操作)在大多数情况下).缺点是此API随时可能更改(它过去已经更改过),全部未记录,并且只能通过逆向工程来知道功能.但是,可访问性是公开的,已有文档记录,并且自从引入它的第一个OS X版本以来并没有太大变化(在10.4和10.5中分别添加了一些新功能,但其他功能没有太大变化).

There exist private functions to do the same using the Mac OS window manager, but the only advantage that would buy you is that you don't need to be a trusted Accessibility application (which is a one time operation on first launch in most cases). The disadvantages are that this API may change any time (it has already changed in the past), it's all undocumented and functions are only known through reverse engineering. The Accessibility however is public, it is documented and it hasn't change much since the first OS X version that introduced it (some new functions were added in 10.4 and again in 10.5, but not much else has changed).

这是一个代码示例.它将等待5秒钟,因此您可以在执行其他任何操作之前切换到其他窗口(否则它将始终与终端窗口一起使用,这很无聊,无法进行测试).然后它将获得最前面的过程,该过程的最前面的窗口,打印其位置和大小,最后将其向右移动25个像素.您可以像这样在命令行上对其进行编译(假设它名为test.c)

Here's a code example. It will wait 5 seconds, so you can switch to a different window before it does anything else (otherwise it will always work with the terminal window, rather boring for testing). Then it will get the front most process, the front most window of this process, print it's position and size and finally move it by 25 pixels to the right. You compile it on command line like that (assuming it is named test.c)

gcc -framework Carbon -o test test.c

请注意,为简单起见,我没有在代码中执行任何错误检查(在某些地方,如果出了问题,某些事情可能/可能会出错,可能会导致程序崩溃).这是代码:

Please note that I do not perform any error checking in the code for simplicity (there are various places that could cause the program to crash if something goes wrong and certain things may/can go wrong). Here's the code:

/* Carbon includes everything necessary for Accessibilty API */
#include <Carbon/Carbon.h>

static bool amIAuthorized ()
{
    if (AXAPIEnabled() != 0) {
        /* Yehaa, all apps are authorized */
        return true;
    }
    /* Bummer, it's not activated, maybe we are trusted */
    if (AXIsProcessTrusted() != 0) {
        /* Good news, we are already trusted */
        return true;
    }
    /* Crap, we are not trusted...
     * correct behavior would now be to become a root process using
     * authorization services and then call AXMakeProcessTrusted() to make
     * ourselves trusted, then restart... I'll skip this here for
     * simplicity.
     */
    return false;
}


static AXUIElementRef getFrontMostApp ()
{
    pid_t pid;
    ProcessSerialNumber psn;

    GetFrontProcess(&psn);
    GetProcessPID(&psn, &pid);
    return AXUIElementCreateApplication(pid);
}


int main (
    int argc,
    char ** argv
) {
    int i;
    AXValueRef temp;
    CGSize windowSize;
    CGPoint windowPosition;
    CFStringRef windowTitle;
    AXUIElementRef frontMostApp;
    AXUIElementRef frontMostWindow;

    if (!amIAuthorized()) {
        printf("Can't use accessibility API!\n");
        return 1;
    }

    /* Give the user 5 seconds to switch to another window, otherwise
     * only the terminal window will be used
     */
    for (i = 0; i < 5; i++) {
        sleep(1);
        printf("%d", i + 1);
        if (i < 4) {
            printf("...");
            fflush(stdout);
        } else {
            printf("\n");
        }
    }

    /* Here we go. Find out which process is front-most */
    frontMostApp = getFrontMostApp();

    /* Get the front most window. We could also get an array of all windows
     * of this process and ask each window if it is front most, but that is
     * quite inefficient if we only need the front most window.
     */
    AXUIElementCopyAttributeValue(
        frontMostApp, kAXFocusedWindowAttribute, (CFTypeRef *)&frontMostWindow
    );

    /* Get the title of the window */
    AXUIElementCopyAttributeValue(
        frontMostWindow, kAXTitleAttribute, (CFTypeRef *)&windowTitle
    );

    /* Get the window size and position */
    AXUIElementCopyAttributeValue(
        frontMostWindow, kAXSizeAttribute, (CFTypeRef *)&temp
    );
    AXValueGetValue(temp, kAXValueCGSizeType, &windowSize);
    CFRelease(temp);

    AXUIElementCopyAttributeValue(
        frontMostWindow, kAXPositionAttribute, (CFTypeRef *)&temp
    );
    AXValueGetValue(temp, kAXValueCGPointType, &windowPosition);
    CFRelease(temp);

    /* Print everything */
    printf("\n");
    CFShow(windowTitle);
    printf(
        "Window is at (%f, %f) and has dimension of (%f, %f)\n",
        windowPosition.x,
        windowPosition.y,
        windowSize.width,
        windowSize.height
    );

    /* Move the window to the right by 25 pixels */
    windowPosition.x += 25;
    temp = AXValueCreate(kAXValueCGPointType, &windowPosition);
    AXUIElementSetAttributeValue(frontMostWindow, kAXPositionAttribute, temp);
    CFRelease(temp);

    /* Clean up */
    CFRelease(frontMostWindow);
    CFRelease(frontMostApp);
    return 0;
}

Sine Ben问您如何获取评论中所有窗口的列表,方法如下:

Sine Ben asked how you get a list of all windows in the comments, here's how:

对AXUIElementCopyAttributeValue函数使用"kAXWindowsAttribute"代替"kAXFocusedWindowAttribute".这样,结果就不会是AXUIElementRef,而是一个CFArray的AXUIElementRef元素,此应用程序的每个窗口一个.

Instead of "kAXFocusedWindowAttribute" you use "kAXWindowsAttribute" for the AXUIElementCopyAttributeValue function. The result is then no AXUIElementRef, but a CFArray of AXUIElementRef elements, one for each window of this application.

这篇关于OS X中的窗口移动和调整大小API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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