窗口移动和调整OS X中的API

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

请注意,我想从外部过程中做到这一点 – 我不问如何控制我自己的应用程序的窗口大小和位置。

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

但是,如果用户在其偏好设置(System Prefs – > Universal Access)中启用了对辅助设备的访问权限,则应用程序只能使用此API,在这种情况下,所有应用程序都可以使用此API,或者如果您的应用程序是受信任的辅助应用程序(当它被信任的时候,即使这个选项没有被选中,它也可以使用这个API)。 Accessibility API本身提供了使应用程序可信的必要功能 – 基本上,您必须成为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; } 

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

AXUIElementCopyAttributeValue函数使用“kAXWindowsAttribute”而不是“kAXFocusedWindowAttribute”。 那么结果是没有AXUIElementRef,而是一个AXUIElementRef元素的CFArray,一个用于这个应用程序的每个窗口。

我同意无障碍是最好的方法。 但是,如果你想快速和肮脏,AppleScript也将工作。