AppleScript:获取所有桌面窗口列表

7

我需要获取每个应用程序的窗口总数。无论我尝试什么方法,我只能得到当前(Mission Control)桌面分配的窗口计数。(我目前正在运行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子句不是问题所在。它找到了所有适当的进程,但一旦我要求这些进程的窗口时,它们只计算活动桌面中的窗口。
我尝试将tell中的log语句提取出来,并使用name of _appcount of every window of _app,但没有任何区别。我试图从System Events中获取除process之外的其他内容,但任何有用的内容最终都变成了获得相同对象的不同方式。我试图迭代UI elements,但没有显示出不在当前桌面上的窗口,尽管我对每个应用程序都能获得菜单栏。
我可以遍历所有桌面(虽然不需要实际切换到所有桌面),但我甚至找不到获取桌面列表的方法。 此答案声称描述了如何做到这一点,但我始终只在every desktop中得到一个元素。更何况,一旦你拥有了那个桌面对象,也没有明显的方法可以获取窗口。
还值得指出的是,桌面受到Dock的控制,而不是Mission Control的控制。我不知道任何AppleScript可以与Dock通信的方法,因此如果您知道某些内容,则有关该方面的答案或评论可能有助于指导我正确的方向。
我正在尝试做一些不可能的事情吗?

“桌面”是指多屏幕桌面还是虚拟桌面(在10.7中通过任务控制可用)?那个其他问题仅涉及多屏幕桌面。 - adamh
好的观点。我指的是类似于任务控制中心的桌面。苹果过度使用这个名词,使得寻找解决方案变得非常容易。 :/ - wfaulk
自上次评论以来,我已经微调了我的一行代码。我编写了一个非常难以阅读的Perl 1-liner,否则我会详细描述它,但是周围的AppleScript将一个名为“numClusteredDesktops”的变量设置为其输出减去显示器数量加1。如果该结果小于2,则我几乎与上述内容相同,但在序列中添加了“sort -u”。 - hepcat72
天啊,我应该看一下上面的代码注释:这个逻辑可能不对。它可能只在我的两台电脑上随机工作。逻辑是strings ~/Library/Preferences/com.apple.spaces.plist返回(任意)一组包含每个桌面和监视器的连续UID集群,因此可以通过减去显示器数量并再次添加1来确定桌面数量以获取主显示器(或者,如果没有辅助显示器,则仅为每个桌面返回非连续UID)。还有一个假设是每个全屏应用程序都会获得一个桌面UID。 - hepcat72
因此,考虑到该评论,我的 Perl 一行代码创建了出现在相邻行上的 UID 组,并返回最大组。然后,包围它的 Applscript 执行“- numMonitors + 1”。 - hepcat72
显示剩余3条评论
3个回答

2
作为该OP已经超过六年了,我无法在当时使用的OS X 10.7下进行测试,尽管如此,以下示例AppleScript代码对我来说在macOS 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字典

由于应用程序进程无法跨所有桌面/空间返回正确数量的窗口,因此该方法依赖于应用程序返回所有桌面/空间窗口的数量。



更新:

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

获取每个可见进程的捆绑标识符。 对于每个捆绑标识符,通过直接查询应用程序来获取其名称和窗口计数。
如果应用程序理解AppleScript命令,则转到appBundleIdentifierList列表中的下一项。
如果不理解,则按以下方式计算窗口计数:
- 尝试获取不可见窗口计数,因为它们不会显示在应用程序的Window菜单中。 - 通过在应用程序的Window菜单中显示的窗口数量计算窗口计数。 - 如果这些方法失败,则通过查询应用程序进程来获取窗口计数,这只对活动的桌面/空间准确,并且仅包含尝试使用基本vanilla AppleScript确定窗口计数的完整性。
然后转到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.*)

作为一个本地的默认macOS应用程序,即使是Activity Monitor,窗口菜单也必须被查询,因为该应用程序直接不能理解基本的count windows AppleScript命令。尽管第二个版本的代码输出在执行时准确跨越了所有的桌面/空间,但任何具有“通过查询应用程序进程。可能不准确,请根据需要验证。”作为其输出一部分的应用程序只包括从执行的活动桌面/空间的窗口计数。底线是使用基本的vanilla AppleScript,没有保证能够获得每个可见应用程序的完整准确的窗口计数,除非可以直接查询所有应用程序。通过其应用程序进程查询窗口菜单也应该是准确的。

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


1

我运行了你的代码,将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

回复:“我有什么没看到的吗?”-- 这个答案的代码中没有任何需要 use AppleScript version "2.4" -- Yosemite (10.10) or later 或者 use scripting additions 的内容。话虽如此,OP 正在使用 OS X 10.7,所以代码的第一行显然不适用!这个答案的问题在于它完全忽略了最重要的要求:有没有办法获取所有桌面上所有窗口的每个应用程序计数? 这也存在同样的问题,它只能获取活动 桌面window 计数,而不能获取所有 桌面 的计数! - user3439894
@user3439894,感谢您的回复。我收回我的答案。即使我可以在列表中看到所有应用程序,无论它们在哪个桌面上,但在除了桌面1之外的其他桌面上,应用程序的计数值仍为0。 - Dri

0
被老OP吸引,以解决我类似的问题,这里的答案激发了一个实验。我怀疑我的Sierra苹果脚本在Catalina上遇到了困难,但由于OP是关于Lion的,我意识到我的问题是其他方面。问题出在我编写的"System Events"脚本的方式上!我的代码的一个版本基本上要求"每个应用程序的窗口",而另一个版本要求"每个进程的窗口"。这两种方式在与任务控制中的多个桌面相关的方式上完全不同!这个实验尝试了3种计算窗口的方法:
Tell application "Script Editor"
   return count of every window of application "TextEdit"
  #return count of every window of application process "TextEdit"
  #return count of every window of process "TextEdit"
  --(uncomment whichever test your doing.)
end

结果是,“进程”和“应用程序进程”只计算当前桌面空间的窗口。但是,使用“应用程序”(不包括“进程”一词)会返回每个桌面空间上的每个窗口的值!希望这能帮到你!

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