OSX Lion AppleScript:如何从任务控制中获取当前空间#?

Posted

技术标签:

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

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


特别是我想要做的事情:

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

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

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

【问题讨论】:

【参考方案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。你可以像这样获取它的头文件:

    转至:/System/Library/CoreServices/Dock 右键单击并显示包内容 导航:/Contents/MacOS/Dock 二进制文件复制并粘贴到您的桌面。 运行:$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(使用 FastScripts、Alfred 或其他一些避免 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 版本。这个解决方案解决了我的问题,即:

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

很久以前我使用 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 个显示器以来,它一直没有起作用。)

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

【讨论】:

以上是关于OSX Lion AppleScript:如何从任务控制中获取当前空间#?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 XAMPP mac osx lion 中设置 memcache

XAMPP OSX Lion 让邮件正常工作

Applescript启动XAMPP osx,弹出时不会输入密码?

python tab 补全 Mac OSX 10.7 (Lion)

OSX 10.7 Lion 上的 JDK

升级到 OSX 10.7 Lion 后修复 Postgresql