在 AppleScript 中调整不可编写脚本的应用程序的窗口大小

发布于 2024-11-10 06:47:33 字数 1102 浏览 1 评论 0原文

我正在开发一个应用程序,可以移动 OSX 上其他应用程序的窗口并调整其大小。 主要应用程序是用 Cocoa 编写的,但调整大小部分是用 AppleScript 完成的,因为 Cocoa 似乎没有这种功能。

以下是常规调用 ActionScript 的结果(作为字符串传递给 NSAppleScript):

tell application "TextEdit"
    set currentWindow to the window id 5184
    set bounds of the currentWindow to {2855, 218, 3790, 578}
end tell

窗口 ID 是使用 OSX 10.6 中引入的 CGWindowListCopyWindowInfo API 获取的。

此方法适用于大多数窗口,但不适用于不可编写脚本的应用程序。 最突出的例子是 OSX 自己的预览版。

我尝试过使用此代码的变体“告诉”系统事件而不是预览

tell application "System Events"
    set bounds of window 5184 to {1920, -502, 2855, 578}
end tell

但是,OSX 给了我一条错误消息:

"System Events got an error: Can’t set bounds of window 5184 to {1920, -502, 2855, 578}."

当试图获取对窗口的引用时也会发生同样的情况:

tell application "System Events"
    get window 5184
end tell

我已经仔细检查了窗口是否存在以及窗口 ID是正确的。

在 OSX 上以编程方式调整不可编写脚本的窗口大小的正确方法是什么? 我可以从 moom 等应用程序中看到这是可能的。

任何建议 - 无论是基于 Cocoa 或 AppleScript 或完全其他的东西 - 都非常受欢迎。

I am working on an application that moves and resizes windows of other applications on OSX.
The main application is written in Cocoa but the resizing part is done in AppleScript as Cocoa does not seem to have this kind of feature.

Here is the result of a regular call to ActionScript (passed as a string to NSAppleScript):

tell application "TextEdit"
    set currentWindow to the window id 5184
    set bounds of the currentWindow to {2855, 218, 3790, 578}
end tell

The Window ID is obtained using the CGWindowListCopyWindowInfo API introduced in OSX 10.6.

This approach works fine for most windows but fails for applications that are unscriptable.
The most prominent example is OSX's own Preview.

I have tried "telling" System Events instead of Preview using variations of this code

tell application "System Events"
    set bounds of window 5184 to {1920, -502, 2855, 578}
end tell

However, OSX gives me an error message:

"System Events got an error: Can’t set bounds of window 5184 to {1920, -502, 2855, 578}."

The same happens when just trying to get a reference to the window:

tell application "System Events"
    get window 5184
end tell

I have doublechecked that the window exists and the window ID is correct.

What is the proper way to programmatically resize unscriptable windows on OSX?
I can see it is possible from applications such as moom.

Any advice - be it Cocoa- or AppleScript-Based or something else entirely - is more than welcome.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦晓ヶ微光ヅ倾城 2024-11-17 06:47:33

不幸的是,应用程序窗口的AppleScripting取决于应用程序的开发人员——一般来说没有干净的方法来做到这一点。看看我几年前为所有特殊情况编写的脚本:

    -- Get screen bounds and origins
set f to (path to preferences from local domain as Unicode text) & "com.apple.windowserver.plist"
tell application "System Events" to set {{|Width|:w1, |Height|:h1, |OriginX|:OX1, |OriginY|:OY1}, {|Width|:w2, |Height|:h2, |OriginX|:OX2, |OriginY|:OY2}} to value of property list items of property list item 1 of property list item "DisplaySets" of property list file f
set SecondaryScreenBounds to {OX2, OY2, OX2 + w2, OY2 + h2}
set RHedge to OX1
set BOTedge to OY1

tell application "Finder"
    -- Get the running apps (excluding those with special windows)
    set |running| to name of processes whose visible is true and name is not "Finder" and name is not "QuickSilver" and name is not "CopyPaste" and name is not "DropCopy" and name is not "iPulse"
    repeat with anApp in |running|
        try -- for a scriptable App with window bounds property
            tell application anApp
                set allWindows to (every window)
                repeat with aWindow in allWindows
                    set Wbounds to (get bounds of aWindow)
                    if item 1 of Wbounds > RHE or item 2 of Wbounds > BoE then my moveWindows(contents of anApp)
                end repeat
            end tell
        on error -- for an App with window position & size properties
            tell application "System Events"
                tell application process anApp
                    set allWindows to (every window)
                    repeat with aWindow in allWindows
                        set {p1, p2} to aWindow's position
                        if p1 ≥ RHedge or p2 ≥ BOTedge then my moveWindows(contents of anApp)
                    end repeat
                end tell
            end tell
        end try
    end repeat
    -- for the Finder
    set allWindows to (every window whose visible is true)
    repeat with aWindow in allWindows
        set Wbounds to bounds of aWindow
        if (item 1 of Wbounds) > RHedge or (item 2 of Wbounds) > BOTedge then
            set bounds of aWindow to {200, 200, 1200, 800}
        end if
    end repeat
end tell
-- for Safari
if "Safari" is in |running| then tell application "Safari"
    set Wind to name of windows
    set Wbounds to bounds of windows
    repeat with k from 1 to count Wind
        set W to item k of Wind
        set B to item k of Wbounds
        if (item 1 of B) ≥ RHedge or (item 2 of B) ≥ BOTedge then
            set bounds of window W to {200, 200, 1200, 800}
        end if
    end repeat
end tell
-- for HoudahSpot
if "HoudahSpot" is in |running| then tell application "System Events" to tell process "HoudahSpot"
    set W to name of windows
    set B to position of windows
    repeat with k from 1 to count W
        if item k of W is not missing value and (item 1 of item k of B) ≥ RHedge then set position of window (item k of W) to {100, 100}
    end repeat
end tell

-- for Activity Monitor
if "Activity Monitor" is in |running| then tell application "System Events" to tell process "Activity Monitor"
    set W to name of windows
    set B to position of windows
    repeat with k from 1 to count W
        if item k of W is not missing value and (item 1 of item k of B) ≥ RHedge then set position of window (item k of W) to {100, 100}
    end repeat
end tell
-- for 1Password
if "1Password" is in |running| then tell application "System Events" to tell process "1Password"
    set W to name of windows
    set B to position of windows
    repeat with k from 1 to count W
        if item k of W is not missing value and (item 1 of item k of B) ≥ RHedge then set position of window (item k of W) to {100, 100}
    end repeat
end tell
-- for iCal
if "iCal" is in |running| then tell application "iCal"
    set iCB to bounds of window "iCal"
    if item 1 of iCB ≥ RHedge or item 2 of iCB ≥ BOTedge then
        set bounds of window "iCal" to {100, 100, 1200, 1000}
    end if
end tell
-- for a Help Window
tell application "System Events"
    if exists process "Help Viewer" then tell process "Help Viewer"
        set W to windows
        repeat with w1 in W
            set position of w1 to {200, 200}
        end repeat
    end tell
end tell

to moveWindows(anApp)
    tell application "System Events"
        if anApp is "ScriptLight" then
            tell process "ScriptLight" to set position of window 1 to {200, 200}
        else if anApp is "PowerKey" then
            tell process "PowerKey" to set position of window "PowerKey" to {200, 200}
        else if anApp is "Script Debugger 4" then
            tell application process "Script Debugger 4"
                set allWindows to (every window)
                repeat with aWindow in allWindows
                    set {p1, p2} to aWindow's position
                    if p1 ≥ 1680 or p2 > 1050 then set aWindow's position to {100, 100}
                end repeat
            end tell
        end if
    end tell
end moveWindows

Unfortunately, the AppleScripting the windows of an app is up to the developer of the app -- there's no clean way to do it in general. Look at this script I wrote some years ago for all the special cases:

    -- Get screen bounds and origins
set f to (path to preferences from local domain as Unicode text) & "com.apple.windowserver.plist"
tell application "System Events" to set {{|Width|:w1, |Height|:h1, |OriginX|:OX1, |OriginY|:OY1}, {|Width|:w2, |Height|:h2, |OriginX|:OX2, |OriginY|:OY2}} to value of property list items of property list item 1 of property list item "DisplaySets" of property list file f
set SecondaryScreenBounds to {OX2, OY2, OX2 + w2, OY2 + h2}
set RHedge to OX1
set BOTedge to OY1

tell application "Finder"
    -- Get the running apps (excluding those with special windows)
    set |running| to name of processes whose visible is true and name is not "Finder" and name is not "QuickSilver" and name is not "CopyPaste" and name is not "DropCopy" and name is not "iPulse"
    repeat with anApp in |running|
        try -- for a scriptable App with window bounds property
            tell application anApp
                set allWindows to (every window)
                repeat with aWindow in allWindows
                    set Wbounds to (get bounds of aWindow)
                    if item 1 of Wbounds > RHE or item 2 of Wbounds > BoE then my moveWindows(contents of anApp)
                end repeat
            end tell
        on error -- for an App with window position & size properties
            tell application "System Events"
                tell application process anApp
                    set allWindows to (every window)
                    repeat with aWindow in allWindows
                        set {p1, p2} to aWindow's position
                        if p1 ≥ RHedge or p2 ≥ BOTedge then my moveWindows(contents of anApp)
                    end repeat
                end tell
            end tell
        end try
    end repeat
    -- for the Finder
    set allWindows to (every window whose visible is true)
    repeat with aWindow in allWindows
        set Wbounds to bounds of aWindow
        if (item 1 of Wbounds) > RHedge or (item 2 of Wbounds) > BOTedge then
            set bounds of aWindow to {200, 200, 1200, 800}
        end if
    end repeat
end tell
-- for Safari
if "Safari" is in |running| then tell application "Safari"
    set Wind to name of windows
    set Wbounds to bounds of windows
    repeat with k from 1 to count Wind
        set W to item k of Wind
        set B to item k of Wbounds
        if (item 1 of B) ≥ RHedge or (item 2 of B) ≥ BOTedge then
            set bounds of window W to {200, 200, 1200, 800}
        end if
    end repeat
end tell
-- for HoudahSpot
if "HoudahSpot" is in |running| then tell application "System Events" to tell process "HoudahSpot"
    set W to name of windows
    set B to position of windows
    repeat with k from 1 to count W
        if item k of W is not missing value and (item 1 of item k of B) ≥ RHedge then set position of window (item k of W) to {100, 100}
    end repeat
end tell

-- for Activity Monitor
if "Activity Monitor" is in |running| then tell application "System Events" to tell process "Activity Monitor"
    set W to name of windows
    set B to position of windows
    repeat with k from 1 to count W
        if item k of W is not missing value and (item 1 of item k of B) ≥ RHedge then set position of window (item k of W) to {100, 100}
    end repeat
end tell
-- for 1Password
if "1Password" is in |running| then tell application "System Events" to tell process "1Password"
    set W to name of windows
    set B to position of windows
    repeat with k from 1 to count W
        if item k of W is not missing value and (item 1 of item k of B) ≥ RHedge then set position of window (item k of W) to {100, 100}
    end repeat
end tell
-- for iCal
if "iCal" is in |running| then tell application "iCal"
    set iCB to bounds of window "iCal"
    if item 1 of iCB ≥ RHedge or item 2 of iCB ≥ BOTedge then
        set bounds of window "iCal" to {100, 100, 1200, 1000}
    end if
end tell
-- for a Help Window
tell application "System Events"
    if exists process "Help Viewer" then tell process "Help Viewer"
        set W to windows
        repeat with w1 in W
            set position of w1 to {200, 200}
        end repeat
    end tell
end tell

to moveWindows(anApp)
    tell application "System Events"
        if anApp is "ScriptLight" then
            tell process "ScriptLight" to set position of window 1 to {200, 200}
        else if anApp is "PowerKey" then
            tell process "PowerKey" to set position of window "PowerKey" to {200, 200}
        else if anApp is "Script Debugger 4" then
            tell application process "Script Debugger 4"
                set allWindows to (every window)
                repeat with aWindow in allWindows
                    set {p1, p2} to aWindow's position
                    if p1 ≥ 1680 or p2 > 1050 then set aWindow's position to {100, 100}
                end repeat
            end tell
        end if
    end tell
end moveWindows
夏天碎花小短裙 2024-11-17 06:47:33

您提到了预览,因此在预览中打开一个窗口并运行此脚本。

tell application "System Events"
    tell process "Preview"
        set theWindows to windows
        return properties of (item 1 of theWindows)
    end tell
end tell

查看返回的属性。没有“id”属性,因此您无法以这种方式访问​​窗口。没有“bounds”属性,因此您无法设置边界。另请注意,您必须从系统事件调用中的“进程”获取窗口。因此,如果您想使用系统事件,您的代码还很遥远。

最好的选择是找到您想要定位的窗口的名称。然后在 applescript 中,您将获得像我上面那样的 Windows,然后循环检查它们的名称。当您找到正确的名称时,您就找到了合适的窗口。然后您可以设置该窗口的“大小”和“位置”属性。

祝你好运,因为你的任务很艰巨!

You mentioned Preview, so open a window in Preview and run this script.

tell application "System Events"
    tell process "Preview"
        set theWindows to windows
        return properties of (item 1 of theWindows)
    end tell
end tell

Look at the properties that are returned. There is no "id" property so you can't access windows that way. There is no "bounds" property so you can't set the bounds. Also notice that you have to get the windows from a "process" in the system events call. So if you want to use system events your code is pretty far off.

Your best bet would be to find the name of the window you want to target. Then in applescript you get theWindows as I have above, then loop through them checking their name. When you find the proper name you have found the appropriate window. Then you could set the "size" and "position" properties of that window.

Good luck because your task is a large one!

梦境 2024-11-17 06:47:33

我在尝试使用与您所使用的逻辑类似的逻辑来调整应用程序的大小时遇到​​了同样的问题。

就我而言,我需要调整应用程序的大小以匹配屏幕大小,我发现如果您授予脚本编辑器辅助访问。如果您将脚本保存为应用程序 您将需要授予该应用程序访问权限。

以下脚本只是获取屏幕大小,重新打开应用程序以确保其已打开,然后使用“系统事件”设置前窗口的大小。

注意:我的目标是下面一个名为“cefclient”的应用程序

set theApp to "cefclient"

tell application "Finder"
    set screenResolution to bounds of window of desktop
end tell

set screenWidth to item 3 of screenResolution
set screenHeight to item 4 of screenResolution

tell application theApp
    activate
    reopen
end tell

tell application "System Events"
    tell process theApp
        set the size of front window to {screenWidth, screenHeight}
    end tell
end tell

I was having the same issue trying to resize an application using similar logic to what you were using.

In my case I needed to resize an application to match the screen size and I found that you could use "System Events" if you grant script editor assistive access. If you save the script as an app you will need to grant that app access instead.

The following script simply grabs the screen size, reopens the app to make sure it is open, then uses "System Events" to set the size of the front window.

NOTE: I'm targeting an application called "cefclient" below

set theApp to "cefclient"

tell application "Finder"
    set screenResolution to bounds of window of desktop
end tell

set screenWidth to item 3 of screenResolution
set screenHeight to item 4 of screenResolution

tell application theApp
    activate
    reopen
end tell

tell application "System Events"
    tell process theApp
        set the size of front window to {screenWidth, screenHeight}
    end tell
end tell
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文