【问题标题】:AppleScript: Get list of windows on all desktopsAppleScript:获取所有桌面上的窗口列表
【发布时间】:2024-01-18 12:02:01
【问题描述】:

我需要统计每个应用程序的所有窗口。我尝试这样做的每一种方式,我只得到分配给当前(任务控制)桌面的窗口计数。 (我目前运行的是 Mac OS X 10.7,所以是后 Spaces。)有没有办法获得所有桌面上所有窗口的每个应用程序计数?

我尝试过的关键:

tell application "System Events"
  repeat with _app in (every process whose visible is true)
    tell _app
      log (name as string) & ": " & (count of every window)
    end tell
  end repeat
end tell

请注意,whose visible is true 子句不是问题所在。它会找到所有适当的进程,但是一旦我向进程询问窗口,它们只会计算活动桌面中的进程。

我尝试将log 线从tell 中拉出并使用name of _appcount of every window of _app,但没有区别。我尝试从System Events 中获取processes 以外的东西,但任何有用的东西最终都只是获得相同对象的不同方式。我尝试迭代 UI elements,但没有显示不在当前桌面上的窗口,尽管我确实为每个应用程序获得了一个菜单栏。

我可以遍历所有桌面(尽管实际上并没有切换到所有桌面),但我什至找不到获取桌面列表的方法。 This answer 声称描述了如何做到这一点,但我只在 every desktop 中得到一个元素。并不是说一旦您拥有该 Desktop 对象,就有一种明显的方式来获取窗口。

还值得指出的是,桌面由 Dock 控制,而不是由 Mission Control 控制。我不知道 AppleScript 有什么方法可以与 Dock 对话,所以如果你知道一些事情,那么对此的回答或评论可能会帮助我指明正确的方向。

我在尝试做一些不可能的事情吗?

【问题讨论】:

  • “桌面”是指多显示器桌面还是虚拟桌面(可通过 10.7 中的任务控制获得)?另一个问题是只处理多显示器桌面。
  • 好点。我的意思是任务控制式桌面。 Apple 重载这个名词使得搜索解决方案真的变得容易。 ://
  • 所以我发现您可以使用以下 tcsh one-liner:@ x = ( `strings ~/Library/Preferences/com.apple.spaces.plist | grep -c '^\$'` + 1 ); echo $x 获取(假设:虚拟)桌面的数量。试试看是否适合你,因为我不确定这种 hacky 方法是否可靠。我正在运行 Mojave,这对我来说似乎是准确的。如果可行,您应该能够在 applescript 中使用击键来切换桌面并收集窗口名称。
  • 碰到一个旧线程......有人找到解决方案吗?编辑:可能在 AppleScript 中...

标签: user-interface automation window applescript osx-lion


【解决方案1】:

由于 OP 已超过六年,我无法在当时使用的 OS X 10.7 下进行测试,但是,以下内容example AppleScript codema​​cOS Catalina 下为我工作并返回正确的窗口计数跨所有桌面/空间,但理解给定AppleScript 命令的任何应用程序以及为什么正在使用tryon error 语句

示例 AppleScript 代码

tell application "System Events" to ¬
    set appBundleIdentifierList to ¬
        the bundle identifier of ¬
            (every process whose visible is true)

repeat with appBundleIdentifier in appBundleIdentifierList
    try
        tell application id appBundleIdentifier to ¬
            set {appName, winCount} to {name, (count windows)}
        log appName & ": " & winCount
    on error errorMessage
        log errorMessage
    end try
end repeat

我的系统上的示例 输出,该系统有多个 桌面/空间,所有或一些桌面/空间和每个的窗口计数在所有桌面/空间上都是正确的,而不仅仅是活动的桌面/ 脚本的运行空间

(*Safari: 6*)
(*Terminal: 2*)
(*TextEdit: 4*)
(*Script Editor: 7*)
(*Finder: 3*)
(*BBEdit: 1*)
(*Norton Secure VPN got an error: every window doesn’t understand the “count” message.*)
(*Music: 2*)

注意事项:

并非所有应用程序都是AppleScript可编写脚本的,因为有些应用程序的中不包含AppleScript 字典 em>应用程序包

由于application process 无法在所有桌面/空间 中返回正确的窗口 数量,此方法依赖application 来返回 的数量>windows 跨所有桌面/空间



更新:

以下示例 AppleScript 代码 执行以下操作:

  • 获取可见为真的每个进程的包标识符。

  • 对于每个包标识符,通过直接查询 应用程序 来获取它的 namewindow 计数。

    如果 应用程序 理解 AppleScript 命令,那么如果转到下一个 item appBundleIdentifierList 列表

    如果不明白,则window计数按如下方式计算:

    • 尝试获取不可见的窗口会被计入,因为它们不会显示在应用程序窗口菜单上。
    • 根据应用程序Window菜单上显示的窗口数计算window计数。
    • 如果这些方法失败,它会通过查询 应用程序进程 获得 window 计数,仅对活动 Desktop/Space 准确,并且是仅包含使用 basic vanilla AppleScript 尝试确定 window 计数的完整性。
    • 转到appBundleIdentifierList列表中的应用程序

示例 AppleScript 代码

set menuName to "Window"

tell application id "com.apple.systemevents" to ¬
    set appBundleIdentifierList to ¬
        the bundle identifier of ¬
            (every process whose visible is true)

repeat with appBundleIdentifier in appBundleIdentifierList
    try
        tell application id appBundleIdentifier to ¬
            set {appName, winCount} to {name, (count windows)}
        log appName & ": " & winCount & ¬
            " -- By querying the application directly."
    on error
        set winCount to 0
        set notVisibleWindowList to {}
        set errAppName to ¬
            name of application id appBundleIdentifier
        tell application id "com.apple.systemevents"
            try
                tell application process errAppName
                    set notVisibleWindowList to ¬
                        (windows whose visible is false)
                    if notVisibleWindowList is {} then ¬
                        set winCount to ¬
                            length of notVisibleWindowList
                end tell
            end try
            try
                set theTargetMenuItemsList to ¬
                    the reverse of ¬
                        (get name of ¬
                            menu items of ¬
                            menu menuName of ¬
                            menu bar item menuName of ¬
                            menu bar 1 of ¬
                            application process errAppName)
            on error
                set theTargetMenuItemsList to {}
            end try
        end tell
        if theTargetMenuItemsList is not {} then
            repeat with anItem in theTargetMenuItemsList
                if contents of anItem is ¬
                    missing value then exit repeat
                set winCount to winCount + 1
            end repeat
            log errAppName & ": " & winCount & ¬
                " -- By querying the Window menu of the application process."
        else
            try
                tell application id "com.apple.systemevents" to ¬
                    set winCount to ¬
                        (count windows of ¬
                            application process errAppName)
                log errAppName & ": " & winCount & ¬
                    " -- By querying the application process. " & ¬
                    "May not be accurate, verify as necessary."
            end try
        end if
    end try
end repeat

运行两个版本的示例 AppleScript 代码以显示输出的差异:

第一版示例 AppleScript 代码

(*Safari: 6*)
(*TextEdit: 4*)
(*Finder: 3*)
(*BBEdit: 1*)
(*Norton Secure VPN got an error: every window doesn’t understand the “count” message.*)
(*Music: 2*)
(*Sublime Text 2 got an error: every window doesn’t understand the “count” message.*)
(*DiskCatalogMaker got an error: every window doesn’t understand the “count” message.*)
(*Script Editor: 7*)
(*System Preferences: 2*)
(*VMware Fusion got an error: every window doesn’t understand the “count” message.*)
(*Activity Monitor got an error: every window doesn’t understand the “count” message.*)
(*Terminal: 2*)

第二版示例 AppleScript 代码

(*Safari: 6 -- By querying the application directly.*)
(*TextEdit: 4 -- By querying the application directly.*)
(*Finder: 3 -- By querying the application directly.*)
(*BBEdit: 1 -- By querying the application directly.*)
(*Norton Secure VPN: 0 -- By querying the application process. May not be accurate, verify as necessary.*)
(*Music: 2 -- By querying the application directly.*)
(*Sublime Text 2: 4 -- By querying the Window menu of the application process.*)
(*DiskCatalogMaker: 2 -- By querying the Window menu of the application process.*)
(*Script Editor: 7 -- By querying the application directly.*)
(*System Preferences: 2 -- By querying the application directly.*)
(*VMware Fusion: 1 -- By querying the Window menu of the application process.*)
(*Activity Monitor: 0 -- By querying the Window menu of the application process.*)
(*Terminal: 2 -- By querying the application directly.*)

您甚至可以看到 Activity Monitor,一个原生默认 ma​​cOS 应用程序Window 菜单必须直接查询为应用程序不懂基本的count windowsAppleScript command

虽然第二版代码的输出在执行时在所有桌面/空间上都是准确的,但任何应用程序有“通过查询申请过程。可能不准确,根据需要进行验证。”作为其输出的一部分,仅包括它执行形式的活动桌面/空间窗口计数。底线是使用 basic vanilla AppleScript 无法保证获得每个可见应用程序的完整准确的窗口计数> 除非当时的所有应用程序都可以直接查询。通过应用进程查询Window菜单也应该是准确的。

话虽如此,我认为可能需要使用其他方法来获得准确的计数。

【讨论】:

    【解决方案2】:

    我运行了您的代码,将 Applescript 版本设置为 2.4(这是一种习惯);在第一次运行时,您的代码向我展示了每个应用程序所有窗口的适当数量。

    这段代码是我试过的,结果似乎还算满意。有什么我没看到的吗?

    use AppleScript version "2.4" -- Yosemite (10.10) or later
    use scripting additions
    
    
    tell application "System Events"
        set my_list to {}
        repeat with _app in (every process whose visible is true)
            tell _app
                log (name as string) & ": " & (count of every window)
                set my_list to my_list & {name as string, count of every window}
            end tell
        end repeat
        log my_list
    end tell
    

    【讨论】:

    • RE:“有什么我没看到的吗?” -- 此答案的代码 中没有任何内容需要use AppleScript version "2.4" -- Yosemite (10.10) or lateruse scripting additions。也就是说,OP 使用的是 OS X 10.7,所以第一行 code 肯定不适用!这个答案的问题是它完全错过了最重要的要求:有没有办法获得所有桌面上所有窗口的每个应用程序计数?这遇到了同样的问题,因为它只得到活动 Desktopwindow 计数,而不是所有 Desktops
    • @user3439894,感谢您的回复。我收回我的回答。即使我可以看到列表中的所有应用程序,无论它们位于哪个桌面,对于桌面 1 以外的桌面上的应用程序,计数值为 0。