网站首页 > 精选文章 正文
有一天,我用Homebrew安装了一些软件——因为已经是一个月前的事情了,所以已经记不清是安装了什么。安装后并没有立即出现什么问题,只是又过了两天我重新启动电脑后,发现同样是由Homebrew安装的Emacs不由分说地无法启动了。这下可麻烦了,毕竟我是org-mode的重度使用者,还需要偶尔用SLIME写点Common Lisp的代码,而它们都运行在Emacs中。
直觉告诉我,也许重新安装一下Emacs,一切就可以恢复正常。重装了Emacs后,又遇到了别的问题——用BetterTouchTools在Touch Bar中添加的按钮,无法在Emacs已经启动的情况下,切换到它的窗口上。
非要说,问题其实也不大,毕竟很多时候是将MacBook Pro合上盖子当主机用的,Touch Bar在工作时的使用频率并不高。此外,糊Node.js等语言的代码时也用不到Emacs——还是VSCode更合适。
但这就是令人不爽,因此我决定要解决它——用Hammerspoon。
Hammerspoon是什么?
Hammerspoon的官网很好地说明了这款工具的定位和原理
This is a tool for powerful automation of OS X. At its core, Hammerspoon is just a bridge between the operating system and a Lua scripting engine. What gives Hammerspoon its power is a set of extensions that expose specific pieces of system functionality, to the user.
- 它运行在OS X上——现在应该叫macOS;
- 它是用来自动化操作的——就像系统内置的Automator或第三方的Alfred Workflow那样;
- 它的原理是将操作系统的功能封装成了可以用Lua代码调用的模块;
例如下面的代码
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "E", function()
hs.alert.show("Hello World!")
end)
就可以让使用者在按下组合键e的时候,在屏幕正中间显示Hello World!这段文本
为什么用Hammerspoon?
Hammerspoon正好可以解决我的问题,它的hs.window模块既可以让使用者遍历所有打开的窗口(用hs.window.allWindows函数),也可以聚焦到指定的窗口上(用focus方法)。有了它们,将Emacs调到最前面(front-most)来也就是水到渠成的事情了:
- 调用函数hs.window.allWindows函数,获得所有窗口的列表;
- 逐个检查列表中的窗口对象,如果属于Emacs的,就调用窗口的方法focus,并跳出循环。
剩下的两个问题便是:
- Emacs的bundle ID是什么;
- 如何知道一个窗口对象的bundle ID。
Emacs的bundle ID
Bundle ID可以在macOS中独一无二地标识一个应用。要想知道Emacs的bundle ID是什么,只需要打开文件/Applications/Emacs.app/Contents/Info.plist,看看其中键为CFBundleIdentifier的值即可。
Contents grep -A 1 'CFBundleIdentifier' Info.plist
<key>CFBundleIdentifier</key>
<string>org.gnu.Emacs</string>
Contents
可以看到,Emacs的bundle ID是org.gnu.Emacs。
来点Lua代码吧
有了Emacs的bundle ID,接下来就可以在Hammerspoon中定义快捷键了。由于最后会通过Touch Bar上的按钮来触发这组快捷键,复杂点也不要紧,因此我直接沿用了Hammerspoon的入门指引中作为例子的w
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "W", function()
end)
为了在一个循环中逐个遍历窗口对象,将hs.window.allWindows的返回值保存到一个局部变量中
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "W", function()
local windows = hs.window.allWindows()
end)
照着简书上的这篇文章,依葫芦画瓢地用for和pairs来遍历变量windows
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "W", function()
local windows = hs.window.allWindows()
-- 在Lua中遍历表的方法:https://www.jianshu.com/p/de5a4b132918
for _, win in pairs(windows) do
end
end)
窗口自身没有bundle ID,为此需要先获取窗口所属的应用。查看文档可以知道,有一个application方法正是用来获取应用对象的
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "W", function()
local windows = hs.window.allWindows()
-- 在Lua中遍历表的方法:https://www.jianshu.com/p/de5a4b132918
for _, win in pairs(windows) do
local app = win:application()
end
end)
调用allWindows时使用的是英文句号(.),调用application则是用冒号(:),这正是Lua中调用函数与方法时语法上的差异。
再用应用的bundleID方法获得它的bundle ID
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "W", function()
local windows = hs.window.allWindows()
-- 在Lua中遍历表的方法:https://www.jianshu.com/p/de5a4b132918
for _, win in pairs(windows) do
local app = win:application()
local bundleID = app:bundleID()
end
end)
现在,只要变量bundleID等于Emacs的bundle ID就可以聚焦到当前遍历的窗口上了
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "W", function()
local windows = hs.window.allWindows()
-- 在Lua中遍历表的方法:https://www.jianshu.com/p/de5a4b132918
for _, win in pairs(windows) do
local app = win:application()
local bundleID = app:bundleID()
if bundleID == "org.gnu.Emacs" then
win:focus()
end
end
end)
让Touch Bar按钮触发这一切
只需要在BetterTouchTools中配置一下即可
这个方法比此前唤起/Applications/Emacs.app的方式更好,因为它只依赖于Emacs逻辑上亘古不变的东西——bundle ID,而不依赖于其物理上的安装位置。
猜你喜欢
- 2025-09-13 Anthropic预告将推新Claude AI桌面应用
- 2025-09-13 VSCode调试python_vscode+python
- 2025-09-13 多学习才能多赚钱之:vscode怎么安装插件
- 2025-09-13 VS code使用入门(2)_vs code 入门
- 2025-09-13 vscode中如何调试c语言写的代码_vscode 调试c代码
- 2025-09-13 Python 安装、Vscode IDE配置python开发环境
- 2025-09-13 Cursor 进阶使用教程_cursorloader
- 2025-09-13 vscode 缩放字体快捷键设置_vscode字体放大快捷键
- 2025-09-13 译文:动图演示23个VScode快捷键_vscode快捷键运行代码
- 最近发表
-
- 使用VSCode来书写你的Jupyter Notebooks
- 在VSCode中使用uv管理Python项目_用vscode写python怎么运行
- Mac M2芯片 VSCode配置C#开发环境
- 配置vscode远程访问docker_vscode远程window开发
- 普通人 如何 利用 类似 ChatGPT AI 编写程序
- 在Vs code中使用sftp插件以及连接windows远程sftp协议部署指导
- 零代码编程:用kimichat合并一个文件夹下的多个文件
- Windows 10下使用编译并使用openCV
- 基于Springboot + vue3实现的汽车美容与保养网
- 超级右键iRightMouse--Mac强大工具
- 标签列表
-
- 向日葵无法连接服务器 (32)
- git.exe (33)
- vscode更新 (34)
- dev c (33)
- git ignore命令 (32)
- gitlab提交代码步骤 (37)
- java update (36)
- vue debug (34)
- vue blur (32)
- vscode导入vue项目 (33)
- vue chart (32)
- vue cms (32)
- 大雅数据库 (34)
- 技术迭代 (37)
- 同一局域网 (33)
- github拒绝连接 (33)
- vscode php插件 (32)
- vue注释快捷键 (32)
- linux ssr (33)
- 微端服务器 (35)
- 导航猫 (32)
- 获取当前时间年月日 (33)
- stp软件 (33)
- http下载文件 (33)
- linux bt下载 (33)