【问题标题】:OSX Lion AppleScript : How to get current space # from mission control?OSX Lion AppleScript:如何从任务控制中获取当前空间#?
【发布时间】:2011-10-09 18:24:56
【问题描述】:

我试图弄清楚如何从任务控制中获取当前空间#。来源会有所帮助,但更有帮助的是有关如何自己解决这个问题的信息。我写了一些applescripts,但似乎任何时候我都需要做一些新的事情(我找不到字典文档)它属于“告诉这个特定的应用程序”的类别(例如“系统事件“)这个非常具体的事情”,我不知道我该如何弄清楚。


特别是我想要做的事情:

讨厌 OSX 10.7 中的新任务控制。我希望我的空间“网格”回来,因为我一直在使用它。我曾经每隔几秒钟使用箭头键(例如 ALT+)在空格之间导航。现在我被这个笨重的 1x9 空间阵列所困扰,而不是优雅的 3x3 网格。我重新映射了所有空间以使用数字键盘,这部分解决了问题(因为它是 3x3 网格),但仅在我连接了外部键盘时。

基本上,我希望能够再次使用 ALT+,但要这样做我需要检测当前space # 这样我就可以从空间 5-->2 切换,例如。

Dave 在下面的回答虽然比我预期的要详细得多,但需要编写一个应用程序才能做到这一点(而且它仍然不能完全回答这个问题)。如果可能的话,我宁愿将几个键绑定到一个applescript。

【问题讨论】:

    标签: macos applescript spaces mission-control


    【解决方案1】:

    我正在尝试自己解决这个问题。还没有,但方向正确:

    • 每个任务控制“空间”都有一个分配给它的uuid...
    • ...除了第一个 (AFAIK) 和仪表板。

    你可以在这里阅读:

    $ defaults read com.apple.spaces
    $ defaults read com.apple.desktop
    

    文件位置:

    ~/Library/Preferences/com.apple.spaces.plist
    ~/Library/Preferences/com.apple.desktop.plist
    

    这是我的。我启用了四个空格,并显示了三个条目:

    $ defaults read com.apple.spaces
    {
        spaces =     (
                    {
                type = 0; 
                uuid = "9F552977-3DB0-43E5-8753-E45AC4C61973";
            },
                    {
                type = 0;
                uuid = "44C8072A-7DC9-4E83-94DD-BDEAF333C924";
            },
                    {
                type = 0;
                uuid = "6FADBDFE-4CE8-4FC9-B535-40D7CC3C4C58";
            }
        );
    }
    

    如果您删除一个空格,该条目将从文件中删除。如果添加空格,则会添加一个条目。同样,桌面 1 或仪表板永远不会有条目。

    我不确定是否有公共 API 可以确定显示器上显示的空间 uuid。我假设 no uuid 表示 Display 1,而其他人的意思是 Display 1+n。

    我快速浏览了 AppleScript 编辑器库(窗口 ---> 库),在系统事件下没有看到 spaces 的任何条目。这可能是 Cocoa 可以完成的事情,也许是通过私有 API,但我不确定 AppleScript。


    更新 - 2011 年 7 月 23 日

    看起来 Dock 控制着 Mission Control。你可以像这样获取它的头文件:

    1. 转至:/System/Library/CoreServices/Dock
    2. 右键单击并显示包内容
    3. 导航:/Contents/MacOS/
    4. Dock 二进制文件复制并粘贴到您的桌面。
    5. 运行:$class-dump ~/Desktop/Dock

    这会吐出它的所有头文件(它很长;将近 7,500 行)。您可以看到其中出现了spaceUUID 字符串。有一个名为 WVSpace 的类,它似乎代表 Mission Control 中的一个 Space,以及许多其他 WV* 类。

    我明天继续看;现在太累了。 :)


    更新 - 2011 年 7 月 24 日

    在 Dock 中有一个名为 WVSpaces 的类。它具有许多属性,包括:

    WVSpace *currentSpace;
    unsigned int currentWorkspace;
    WVSpace *nextSpace;                     // Space on the right???
    WVSpace *previousSpace;                 // Space on the left???
    BOOL currentSpaceIsDashboard;
    BOOL dashboardIsCurrent;
    ...lots more...
    

    每个WVSpace 类都有一个NSString *_uuid; 属性,这很可能是它的SpaceUUID。所以理论上你可以像这样得到当前的空间号:

    WVSpace *currentSpace = [[WVSpaces sharedInstance] currentSpace];
    NSString *currentSpaceUUID = [currentSpace _uuid];     // Empty string if main space???
    

    诀窍是,如何访问隐藏在 Dock 中的私有 WVSpaces 类?我假设它是 Singleton,因为它有一个 NSMutableArray *_spaces; 属性,其中可能列出了每个空格。一次只显示一个空间(如果您使用多台显示器,这也是如此;空间跨越它们),因此只有一个 WVSpaces 实例是有意义的。

    所以看起来它需要对 Dock 进行一些 SIMBL 黑客攻击才能访问 WVSpaces

    【讨论】:

    • 感谢您的信息。知道当前选择的 uuid 可能在哪里吗?我无法想象它会在一个 plist 中。仅供参考,我只是看了看,它们肯定是随机生成的 uuid。如果您删除桌面#然后重新添加它,它们会发生变化。你深究这个的理由是什么? :)
    • 我添加了一些我发现的更多信息。很高兴知道 UUID 是唯一且非持久的。我正在研究这个我正在编写的程序,这暂时还是个秘密。 ;)
    • 仅供参考,Apple API 中的所有 UUID 将在每次生成/请求 UUID 时随机生成,无论使用如何。 “在工厂”永远不会分配 UUID,因为这可能会在两个应用程序或设备通信时导致 UUID 冲突。 UUID 的全部意义在于唯一标识特定对象的特定实例。
    • 很遗憾没有。有一种破解方法可以提取它,但它在 OSX 10.8 中被破坏了。在 10.8 之前,您需要注册 @"NSWorkspaceActiveSpaceDidChangeNotification" 通知。收到后,您将通过CGWindowListCopyWindowInfo() 遍历所有NSWindow,并为每个窗口读取@"kCGWindowWorkspace" 的值,其中包含其工作区编号。这是一个可选键,因此并非所有窗口都返回某些内容,但您“通常”可以获取所有工作区 ID 的列表。但在 10.8 中,所有窗口的值都返回 nil,因此它不再起作用。
    【解决方案2】:

    我一直在四处寻找,我想出了这个:https://gist.github.com/1129406

    空格有一个不连续的 ID 和一个连续的索引(从 0 开始)。您可以通过两种方式获取 ID:

    • 来自公共 API(请参阅 get_space_id
    • 来自私有 CGS API CGSGetWorkspace

    您可以使用公共 API 按索引设置当前空间(尽管通知本身并未公开记录):请参阅 set_space_by_index

    您可以使用私有 CGS API CGSSetWorkspace 按 ID 设置当前空间。

    无法直接获取当前空间索引。但是,如果您始终使用同一组九个空格,您可以使用set_space_by_index 旋转一次,收集它们的 ID,并构建映射。然后就可以从ID中获取当前索引了。

    【讨论】:

    • @cocoacoder - Mountain Lion 上存在 API,但没有执行或返回任何有用的内容。
    【解决方案3】:

    ...也一直在做这个:)

    你说你“需要检测当前空间#”。这并不完全正确:要向下移动一行,您只需向右移动 3 个空格,因此原则上您可以绑定类似

    tell application "System Events" to tell process "WindowServer"
        key code {124, 124, 124} using control down
    end tell
    

    到 Alt-down(使用 FastScriptsAlfred 或其他一些避免 Automator 开销的快速方法)。当然,如果你在最后一排被击中,这种方法将失败——但如果你真的是硬连线,你永远不会这样做:)
    您必须在通用访问首选项窗格中“启用辅助设备访问”,key code 方法才能工作。

    警告:这不起作用。当我启动上面的脚本时,我很好地跳了三个空格。问题是之后我的键盘没有响应:似乎只有窗口管理器在接收事件:我可以关闭窗口和切换空间,但我无法与任何应用程序交互。
    我的理论是,当跳转导致当前应用程序在脚本执行期间发生变化时,就会发生这种情况——但我不知道如何解决这个问题。

    相关观察:Mission Control(即/Applications/Mission Control.app/Contents/MacOS/Mission\ Control)似乎对某些命令行参数有反应:

    • Mission\ Control: 显示任务控制
    • Mission\ Control 1: 显示桌面
    • Mission\ Control 2: 显示当前应用程序窗口

    我尝试输入来自defaults read com.apple.spaces 的一些 UUID,但这并没有起到多大作用。在黑暗中摸索就够了。

    【讨论】:

      【解决方案4】:

      我写了一个应用程序 - 它对你有用吗?

      Change Space.app

      实现它的关键是 control-shift 和箭头键,但如果您卡在 ALT 上,这可能是可以修复的。

      确保在开始之前设置了 9 个空格(桌面),并且您需要将系统偏好设置中的默认 ctrl-up 和 ctrl-down 键绑定更改为其他内容(在键盘 -> 键盘快捷键 - > 任务控制:任务控制和显示桌面)。

      在第一次运行时,它会循环遍历您的桌面,以便在您第一次更改空间时枚举它们。

      那么您应该能够像在 3x3 网格中那样在桌面之间进行切换。

      可能会有一些皱纹,但基本上是可以使用的,至少对我来说是这样。

      【讨论】:

      • 非常好(我是 TotalSpaces 的用户和粉丝),但我认为这里的想法是以编程方式,因为它提到苹果脚本。我记得 TS 有一个 API,但我不记得你是否可以控制它,或者只是从 API 中提取信息(我记录了我每个空间中发生的事情,所以如果我的机器崩溃了,我可以更轻松地将事情安排为我让他们在崩溃前)。也许您可以对此发表评论并举例说明如何做到这一点。
      • 另外,在 TS 网站上几乎没有提到 API。也许你可以在那里添加文档?
      【解决方案5】:

      http://switchstep.com/ReSpaceApp

      这很有效,是免费的(现在)而且很棒。

      请务必手动创建与您的布局(在首选项中)预期一样多的空间。

      【讨论】:

      • 现在是 TotalSpaces,18 美元。不过,这是值得的。除了“Choosy”之外,TotalSpaces 是我几乎离不开的唯一实用程序。
      【解决方案6】:

      我在 Mountain Lion 上,这似乎对我有用。

      defaults read com.apple.spaces

      查找“当前空间”。您会注意到,使用不同的活动空间运行此命令不会更改当前空间,但是如果您选中并取消选中“系统偏好设置”中的复选框按钮并再次运行它,您会看到它已更新。

      希望这对其他人有帮助!

      编辑:它很难看,但我正在使用这个:

      killall Dock && sleep 0.2 && defaults read com.apple.spaces | grep -A1 "Current Space" | tail -1 | awk '{print $NF }' | cut -f1 -d';'

      【讨论】:

      • '如果您选中和取消选中“系统偏好设置”中的复选框按钮' - 你能详细说明吗?
      【解决方案7】:
      on openNewSpace()
          tell application "System Events"
              —start mission control
              do shell script "/Applications/Mission\\ Control.app/Contents/MacOS/Mission\\ Control"
              tell process "Dock"
                  set countSpaces to count buttons of list 1 of group 1
                  --new space
                  click button 1 of group 1
                  --switch to new space
                  repeat until (count buttons of list 1 of group 1) = (countSpaces + 1)
                  end repeat
                  click button (countSpaces + 1) of list 1 of group 1
              end tell
          end tell
      end openNewSpace
      

      【讨论】:

        【解决方案8】:

        我已经在 macOS Catalina 中为自己想出了一个解决方法,尽管我希望这应该适用于多个 macOS 版本。这个解决方案解决了我的问题,即:

        1. 无法识别哪个桌面包含哪个项目,因为无法命名桌面。 (我通常同时将时间分配给多个项目,每个桌面都专门用于不同的项目[而且它们都使用相同的应用程序])
        2. 无法以编程方式(/轻松)随时确定我在哪个桌面上
        3. 缺乏工具来跟踪每个桌面所花费的时间

        很久以前我使用 Stickies.app 解决了第 1 项。我将项目名称放在足够大的字体中,以便在任务控制中的桌面缩略图中很容易辨认,并将便签窗口隐藏在我的 Dock 后面,专门分配给相应项目的桌面。 (我还将桌面名称复制为从 Dock 左侧下方伸出的小上标文本,以便我可以识别任务控制之外的当前桌面。)

        我刚刚通过applescript解决了第2项。在便签中,我添加了一个很小的、不显眼的字体字符串,将便签标识为桌面名称,例如'dtop'。例如。 “small_superscripted_name LARGE_NAME tiny_dtop_string”或“project1 PROJECT1 dtop”。请注意,此脚本假定项目名称不包含空格(即只有一个单词)。如果您愿意,您可以拆分为不同的字符/字符串。这是运行时生成桌面名称的applescript:

        tell application "System Events"
            --obtain the stickie with the desktop name
            set dstr to name of first item of (windows of application process "Stickies" of application "System Events" whose name contains "dtop")
        
            --Parse the desktop name from the stickie
            set astid to AppleScript's text item delimiters
            set AppleScript's text item delimiters to " "
            set dname to first item of (dstr's text items)
            set AppleScript's text item delimiters to astid
        
            --Show the result in a dialog window
             display dialog "Desktop: " & dname
        end tell
        

        就第 3 项而言,我还没有实现它,但我可以通过使用 osascript 调用脚本轻松地通过 cron 作业进行轮询。但是,我可能会探索映射我用来触发脚本的桌面键盘快捷键的可能性,例如,在 control-right/left-arrow 后 1 秒、F3 或 control-up-arrow 后 10 秒后延迟。 (它不会捕获触发桌面更改的窗口拖动,但自从我开始使用 2 个显示器以来,它一直没有起作用。)

        设置完成后,我可能会将桌面名称和时间戳输出到日志中,以便跟踪在每个桌面上花费的时间。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-02
          • 2011-10-05
          • 1970-01-01
          • 2011-07-14
          • 1970-01-01
          • 2012-03-19
          • 1970-01-01
          • 2016-05-29
          相关资源
          最近更新 更多