AppleScript:循环遍历应用程序窗口;将每一个窗口置于前台并在其他应用程序中触发操作?

5

简短版

我想编写一些 AppleScript,用于迭代应用程序的(非最小化)窗口,并针对每个窗口将其置于前台并触发另一个应用程序 BTT 中的某些操作(该操作将移动窗口)。目标是将该应用程序的所有窗口移动到同一位置。移动部分由 BTT 处理,我只需要帮助实现将此操作应用于所有应用程序窗口。

详细版

(这个问题涉及BetterTouchTool,但事实上不是关于它的 - 我认为 - 而且我猜你不需要知道任何关于 BTT 的信息来回答...)

我正在尝试编写一个 AppleScript 脚本,其中包括(当我将其简化为可能的最简版本时)激活某个应用程序并循环遍历所有窗口,并为每个窗口触发 BetterTouchTool 中的“命名触发器”。命名触发器的作用是将当前窗口移动到某个位置,但那些细节并不重要。

这对我来说感觉应该很简单,但我似乎找不到正确的方法。我尝试过随意复制它,但我没有任何进展(除了怀疑我需要涉及“系统事件”)... 我是一名经验丰富的程序员,但我从未深入研究过 AppleScript,并发现它的做事方式相当奇怪/令人困惑。

到目前为止,我已经有一个有效地运行的版本,它不循环窗口,所以它只触发“第一个”窗口(在某种意义上,“第一个”的定义是“最近活动的此应用程序窗口”)。

例如,以下内容有效。 (在这里,我已将其硬编码为 VSCode,尽管在我尝试编写的完整脚本中,它会迭代应用程序名称列表和要运行的触发器。)

on run
    if application "Visual Studio Code" is running then
        tell application "Visual Studio Code" to activate
        tell application "BetterTouchTool"
            trigger_named "Move window: monitor 4k: core"
        end tell
    end if
end run

这会启动VSCode,然后告诉BTT运行一个命名触发器将当前窗口移动到屏幕上的某个位置。效果是最近使用的VSCode窗口被移动。

好的,这不错,但我想对所有的VSCode窗口这样做(或者理想情况下,所有未最小化的窗口在当前可见的桌面上都要这样做)。

BTT的AppleScript接口似乎不支持定位特定的窗口 - 它只对当前活动的应用程序/窗口起作用,因此我需要以某种方式激活/置顶(?)窗口,然后调用BTT触发器。

我猜我需要像这样的东西(暂时忽略省略最小化窗口的问题):

on run
    if application "Visual Studio Code" is running then
        tell application "Visual Studio Code" to activate
        repeat with app_window in windows
            bring_window_to_front()
            tell application "BetterTouchTool"
                trigger_named "Move window: monitor 4k: core"
            end tell
        end repeat
    end if
end run

我想要:

  • 给定一个应用程序名称...
  • 获取该应用程序的所有窗口,并循环遍历每个窗口,对于每个窗口:
  • 激活/将该窗口置于前台(如果没有最小化)并...
  • 告诉BetterTouchTool运行给定名称的触发器。

......但我不知道如何执行bring_window_to_front()部分!

(此外,这里没有考虑其他桌面; 但我认为我可以没有它。)

概述

我希望:

  • 给定一个应用程序名称...
  • 获取该应用程序的所有窗口,并循环遍历每个窗口,对于每个窗口:
  • 激活/将该窗口置于前台(如果没有最小化)并...
  • 告诉BetterTouchTool运行给定名称的触发器。

上下文

  • MacOS Mojave 10.14.5
  • BetterTouchTouch 3.072 (我认为这没有任何影响)
2个回答

4
任何可编写脚本的应用程序——我假设“Visual Studio Code”是可编写脚本的(从您所写的内容推断)——都应该对此代码做出响应:

最初的回答:任何可编写脚本的应用程序——我假设“Visual Studio Code”是可编写脚本的(从您所写的内容推断)——都应该对此代码做出响应:
on run
    if application "Visual Studio Code" is running then
        tell application "Visual Studio Code" to activate
        set wList to every window whose visible is true
        repeat with app_window in wList
            set index of app_window to 1
            delay .5
            tell application "BetterTouchTool"
                trigger_named "Move window: monitor 4k: core"
            end tell
        end repeat
    end if
end run
  • 第4行的... whose visible is true部分排除了隐藏或最小化的窗口。
  • 第6行的set index of ...命令将每个窗口循环到前台。

indexvisible是标准窗口属性的一部分,所有的AppleScript开发人员都应该实现,所以除非应用程序设计师是完全的业余爱好者,否则它们应该“正常工作”。确保在脚本编辑器中查看脚本字典。有时,AppleScript设计人员会添加有用的特殊命令,或更改标准属性的名称(可能只是为了让人烦恼)。

我不确定第7行的 delay .5 是否需要。我加入它是为了确保窗口在BTT调用之前已经处于最前面。

除非应用程序不支持脚本化,否则不要使用GUI脚本或系统事件。当需要时,GUI脚本非常有用,但如果应用程序具有脚本字典,使用它将更有效和可靠。GUI脚本笨重、缓慢,并且容易受到不可预测的干扰。但如果确实需要使用它,则代码类似。

tell application "System Events"
    tell process "Visual Studio Code"
        set frontmost to true
        set wlist to every window
        repeat with aWindow in wlist
            tell aWindow
                perform action "AXRaise"
                delay .5
                tell application "BetterTouchTool"
                    trigger_named "Move window: monitor 4k: core"
                end tell
            end tell
        end repeat
    end tell
end tell

1

是的,您需要使用系统事件。它可以为您提供所有正在运行和可见的进程(即应用程序),并为每个进程列出窗口列表。

更重要的是,您可以直接更新每个窗口的位置。以下是一个示例脚本,它获取所有应用程序的所有打开窗口,并移动“Script Editor”的“Library”窗口的位置(我为测试而打开它):

tell application "System Events"
set theProcesses to application processes whose visible is true
repeat with aProcess in theProcesses -- loop thru all visible processes

    set allWindows to every window of aProcess
    repeat with myWindow in allWindows -- for each process, look for all windows

        set Pname to name of aProcess
        set Wname to name of myWindow
        if Pname = "Script Editor" and Wname = "Library" then
            set position of myWindow to {400, 900}
        end if

    end repeat -- window loop
end repeat -- process loop
end tell

谢谢 - 但我不想使用AppleScript来定位窗口,我明确希望通过BTT来实现,以便不重复我的位置规格。因此问题仍然存在,如何激活/将这些窗口置于前台,以便BTT触发器可以对其进行操作?此外,这种方法不允许我按名称定位应用程序(这是我需要的,因为不同的应用程序需要触发不同的BTT触发器)。最后,这种方法似乎限制在可见进程而不是非最小化窗口上 - 尽管也许我可以解决这个问题。还是很感谢,可能会有所帮助。 - gimboland
抱歉,我错过了BTT的重点。每个进程的名称都在变量Pname中。使用该名称,您可以访问相关应用程序。要使窗口成为活动窗口,“AXRaise”操作是Ted提出的解决方案。请注意,脚本仅限于“可见”进程以选择正在运行的应用程序。但是,我没有将窗口循环限制为仅限于可见窗口;因此,最小化的窗口也被考虑在内。 - pbell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接