窗口在OS X中移动并调整API大小

我试图在OS X上查找记录(或未记录,如果这是我唯一的选择)API从窗口服务器查询窗口列表,然后导致窗口移动和调整大小。 任何人都可以将我指向正确的方向吗? 我想我会从Win32下的FindWindowEx和MoveWindow开始。

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


使用辅助功能API。 使用这个API,你可以连接到一个进程,获得一个窗口列表(实际上是一个数组),获取每个窗口的位置和大小,并且如果你喜欢,也可以改变窗口属性。

但是,如果用户在其偏好设置中启用了对辅助设备的访问(系统偏好设置 - >通用访问),则应用程序只能使用此API,在这种情况下,所有应用程序都可以使用此API,或者如果您的应用程序是受信任的辅助应用程序(当它被信任的时候,它可以使用API​​,即使这个选项没有被选中)。 Accessibility API本身提供了使您的应用程序可信的必要功能 - 基本上,您必须成为root用户(使用安全服务请求用户的root权限),然后将您的进程标记为可信。 一旦您的应用程序被标记为受信任,它必须重新启动,因为受信任状态仅在启动时被检查,并且在应用程序运行时不能更改。 信任状态是永久的,除非用户将应用程序移动到其他位置或应用程序二进制文件的哈希更改(例如更新后)。 如果用户在其首选项中启用了辅助设备,则所有应用程序都被视为可信。 通常你的应用程序会检查这个选项是否启用,如果是,继续做你的东西。 如果没有,它会检查它是否已经被信任,如果是的话,再次做你的东西。 如果不尝试让自己信任,然后重新启动应用程序,除非用户拒绝了根授权。 API提供了检查所有这些的所有必要功能。

有些私人功能可以使用Mac OS窗口管理器进行相同的操作,但唯一可以买到的优点是您无需成为受信任的辅助功能应用程序(在大多数情况下首次启动时只需执行一次操作) 。 缺点是这个API可能会随时改变(过去它已经改变了),它都没有记录,只有通过反向工程才知道函数。 然而,辅助功能是公开的,它有文档记录,并且自引入它的第一个OS X版本以来没有太大变化(一些新功能在10.4和10.5中都添加了,但没有其他更改)。

这是一个代码示例。 它会等待5秒钟,所以你可以在做任何其他事情之前切换到另一个窗口(否则它将始终与终端窗口一起工作,而非无聊测试)。 然后,它会得到最前面的过程,这个过程的最前面的窗口,打印它的位置和大小,并最终将它向右移动25个像素。 你可以像这样在命令行上编译它(假设它命名为test.c)

gcc -framework Carbon -o test test.c

请注意,为了简单起见,我不在代码中执行任何错误检查(如果出现错误并且某些事情可能/可能会出错,可能会导致程序崩溃的各种地方)。 代码如下:

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

正弦本问你如何得到评论中所有窗口的列表,这里是如何:

您可以使用AXAXIElementCopyAttributeValue函数的“kAXWindowsAttribute”来代替“kAXFocusedWindowAttribute”。 结果是没有AXUIElementRef,而是一个AXUIElementRef元素的CFArray,每个窗口对应一个。


我同意无障碍是最好的前进方向。 但是,如果你想快速又脏兮兮的,AppleScript也可以。

链接地址: http://www.djcxy.com/p/49953.html

上一篇: Window move and resize APIs in OS X

下一篇: iPad Javascript/jQuery touchstart issue