当您从笔记本电脑上拔下分辨率比 macbook 更高分辨率的外接显示器时,窗口大多保持其宽度,但它们的大小会被裁剪到 macbook 屏幕的(较小)高度。当您重新插入显示器时,它们的尺寸仍然小得令人沮丧。
我的问题是:有什么方法可以遍历所有打开的窗口,保存它们的大小,并在再次插入显示器后恢复它们?
当您从笔记本电脑上拔下分辨率比 macbook 更高分辨率的外接显示器时,窗口大多保持其宽度,但它们的大小会被裁剪到 macbook 屏幕的(较小)高度。当您重新插入显示器时,它们的尺寸仍然小得令人沮丧。
我的问题是:有什么方法可以遍历所有打开的窗口,保存它们的大小,并在再次插入显示器后恢复它们?
以下 AppleScript 展示了如何:
代码:
tell application "System Events"
set theProcesses to application processes
repeat with theProcess from 1 to count theProcesses
tell process theProcess
repeat with x from 1 to (count windows)
set windowPosition to position of window x
set windowSize to size of window x
set position of window x to {0, 0}
set size of window to {100, 100}
end repeat
end tell
end repeat
end tell
注意:该脚本需要辅助设备访问权限(AfAD):
“系统偏好设置”→“通用访问权限”→“启用辅助设备访问权限”
编辑(回复评论)
从 AppleScipt 启用 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 解决方案(参见 Anne 的回答)是迄今为止最简单的解决方案。
如果您想将此提供给无法依赖的朋友来弄清楚如何启用辅助访问,或者更广泛地分发它,只需添加以下行:
do shell script ¬
"touch /private/var/db/.AccessibilityAPIEnabled" ¬
with administrator privileges
这将弹出通常的身份验证对话框,然后使用权限打开辅助访问。
实际上可以在没有辅助访问的情况下执行此操作,但它需要在 CoreGraphics/Quartz 窗口服务中使用私有函数,即CGSPrivate.h。
使用公共 API,您可以轻松枚举所有窗口:
CFArrayRef windows =
CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly |
kCGWindowListExcludeDesktopElements,
kCGNullWindowID);
这将返回一个字典数组,每个字典都包含一个 kCGWindowBounds 字典,其中包含 Height、Width、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);
}
显然,这很讨厌,只有在您确实需要分发一个不能请求辅助访问的应用程序时才应该考虑它。
您还可以对 Window Server 协议进行逆向工程并直接与之对话,但这更糟糕。