Macos 有没有一种方法可以在Mac OS X中迭代所有打开的窗口?

Macos 有没有一种方法可以在Mac OS X中迭代所有打开的窗口?,macos,cocoa,applescript,Macos,Cocoa,Applescript,当您从笔记本电脑上拔下分辨率比macbook更高的外部显示器时,窗口大多保持其宽度,但其大小会与macbook屏幕的(较小)高度保持一致。当你把显示器插回电源时,它们的尺寸仍然小得令人沮丧 我的问题是:是否有任何方法可以迭代所有打开的窗口,保存它们的大小,并在再次插入显示器后恢复它们?以下AppleScript演示了如何: 循环浏览所有窗口 检索并更改窗口位置 检索并更改窗口大小 代码: 注意:脚本需要访问辅助设备(AfAD): “系统首选项”→ “通用接入”→ “启用辅助设备的访问” 编辑

当您从笔记本电脑上拔下分辨率比macbook更高的外部显示器时,窗口大多保持其宽度,但其大小会与macbook屏幕的(较小)高度保持一致。当你把显示器插回电源时,它们的尺寸仍然小得令人沮丧


我的问题是:是否有任何方法可以迭代所有打开的窗口,保存它们的大小,并在再次插入显示器后恢复它们?

以下AppleScript演示了如何:

  • 循环浏览所有窗口
  • 检索并更改窗口位置
  • 检索并更改窗口大小
代码:

注意:脚本需要访问辅助设备(AfAD):
“系统首选项”→ “通用接入”→ “启用辅助设备的访问”

编辑(回复评论)

从AppleScript启用AfAD可能会改善用户体验,但不要每次执行脚本时都这样做,只在禁用AfAD的情况下启用AfAD。在不通知用户的情况下启用功能不是一种好做法,提示用户获得启用AfAD的权限

例如:

set AccesEnables to do shell script "[ -e \"/private/var/db/.AccessibilityAPIEnabled\" ] && echo \"Yes\" || echo \"No\""
if (AccesEnables is equal to "No") then
    set askUser to display dialog "This application requires access for assistive devices. Enable this feature?" default button 2
    set answer to button returned of askUser
    if answer is equal to "OK" then
        do shell script "touch /private/var/db/.AccessibilityAPIEnabled" with administrator privileges
    else
        close
    end if
end if

目前为止,看到安妮答案的AppleScript解决方案是最简单的

如果您想将此信息提供给无法依靠的朋友,让他们了解如何启用辅助访问,或将其更广泛地分发,只需添加以下行:

do shell script ¬
  "touch /private/var/db/.AccessibilityAPIEnabled" ¬
  with administrator privileges
这将弹出通常的身份验证对话框,然后使用权限打开辅助访问

实际上,不需要辅助访问就可以做到这一点,但它需要在CoreGraphics/Quartz窗口服务中使用私有功能,即

使用公共API,您可以轻松枚举所有窗口:

CFArrayRef windows = 
  CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly |
                             kCGWindowListExcludeDesktopElements,
                             kCGNullWindowID);
这将返回一个字典数组,每个字典都包含一个kCGWindowBounds字典,该字典具有高度、宽度、X和Y整数值

但这些公共API是严格只读的。要实际移动窗口,您必须使用CGSPrivate.h执行以下操作:

CGSConnection conn = _CGSDefaultConnection();
for (NSDictionary *window in windows) {
  CGSWindow wid = (CGSWindow)[[window objectForKey:@"kCGWindowNumber"] intValue];
  CGRect bounds;
  CGRectMakeWithDictionaryRepresentation([window objectForKey:@"kCGWindowBounds"],
                                         &bounds);
  CGSMoveWindow(conn, wid, bounds.origin);
}
显然,这是非常讨厌的,如果你真的需要分发一个不需要辅助访问的应用程序,你就应该考虑它。


您也可以对Windows Server协议进行反向工程,并直接与之对话,但这甚至更糟糕。

+1,但可能值得展示如何通过请求授权(使用管理员权限执行shell脚本)以编程方式打开辅助访问。太糟糕了,我不能再次使用+1…但“使用管理员权限”已经弹出一个对话框询问是否授予权限,因此您不想弹出一个对话框询问是否弹出对话框询问权限,除非您是Windows Vista的忠实粉丝。:)这并不完全正确。第一个对话框通知用户需要启用其他功能才能使用应用程序。第二个对话框只要求输入密码,但没有解释原因。使用这两个对话框,用户知道发生了什么,并可以选择是否启用该功能。此外,您可以在第一个对话框中通知用户需要管理员权限,下一个窗口将询问密码。在通知用户中永久更改设置是不好的做法,这就是为什么应该使用附加对话框的原因。
warm==warn&&within==without
:)
CGSConnection conn = _CGSDefaultConnection();
for (NSDictionary *window in windows) {
  CGSWindow wid = (CGSWindow)[[window objectForKey:@"kCGWindowNumber"] intValue];
  CGRect bounds;
  CGRectMakeWithDictionaryRepresentation([window objectForKey:@"kCGWindowBounds"],
                                         &bounds);
  CGSMoveWindow(conn, wid, bounds.origin);
}