Mac电脑效能神器 Hammerspoon 入门和几个改善

intro1: 你是否为在Mac电脑上切换不同的应用时也需要切换输入法而觉得恼怒?比如刚在微信中文下聊天,这时转向命令行工具,打了一半才发现是中文,不得不再重新输入?
intro2: 如果你恰巧还是一名 hacker,是否苦于为了某些系统改进而搜索一堆 Applescript最后发现实现不了你要的功能。
intro3: 这是去年写的短文,一直没时间(懒)再深入完善,今天修改了些,但也只做了简单的入门和介绍

Hammerspoon

最近升级了Mac系统,发现之前的hammerspoon有个脚本耗电偏高,该脚本就是实现打开 Terminal/iTerm2(命令行)/Spotlight等可以将输入法自动切换到拼音输入法,打开Chrome/Firefox等可以自动切换中文输入法。

如果你还不了解Hammerspoon是什么,可以参考下面几个链接:

  1. 免费又强大的 macOS 自动化工具,Hammerspoon 可以让你少买很多 App
  2. 推荐一个 MacOS 上用了就无法自拔的神器Hammerspoon
  3. 打造 macOS 的生产力环境 - Hammerspoon

最开始是在某论坛看到的一段脚本实现输入法自动切换,大概功能就是绑定 Alt+Tab快捷键,切换时就切换了输入法,很早期了。最近刚好想到 Hammerspoon 除了事件机制,窗口焦点事件,于是想想是否有这类机制的实现。

于是我尝试用 “Hammerspoon + 窗口事件” 搜索了一番,找到了几篇文章。实际上不看文章,只是看代码的话也并不难,就在 Hammerspoon.app的Contents/Resources/extensions/hs/window目录下,可以看到下图:

在这里,订阅 hs.window.filter.windowCreatedhs.window.filter.windowFocused 事件一般可以满足上述输入法自动切换的需求了。

但是应该怎样把上述联系起来,编码实现功能?我并不算是个深入了解 Hammerspoon 的用户,所以首先求助其文档,幸亏他的文档写的好又详细,在这里hs.window.filter

上面帮助文档罗列描述很清楚,如果留意上面提到的 hs/window/filter.lua 的代码,我们还可以发现这段注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
--- A *default windowfilter* (not to be confused with the default filter *within* a windowfilter) is provided as convenience;
--- it excludes some known apps and windows that are transient in nature, therefore unlikely to be "interesting" for e.g. window management.
--- `hs.window.filter.new()` (with no arguments) returns a copy of the default windowfilter that you can further tailor to your needs - see `hs.window.filter.default` and `hs.window.filter.new()` for more information.
---
--- -- set the exact scope of what you're interested in - see hs.window.filter:setAppFilter()
--- wf_terminal = wf.new{'Terminal','iTerm2'} -- all visible terminal windows
--- wf_timewaster = wf.new(false):setAppFilter('Safari',{allowTitles='reddit'}) -- any Safari windows with "reddit" anywhere in the title
--- wf_leftscreen = wf.new{override={visible=true,fullscreen=false,allowScreens='-1,0',currentSpace=true}}
--- -- all visible and non-fullscreen windows that are on the screen to the left of the primary screen in the current Space
--- wf_editors_righthalf = wf.new{'TextEdit','Sublime Text','BBEdit'}:setRegions(hs.screen.primaryScreen():fromUnitRect'0.5,0/1,1')
--- -- text editor windows that are on the right half of the primary screen
--- wf_bigwindows = wf.new(function(w)return w:frame().area>3000000 end) -- only very large windows
--- wf_notif = wf.new{['Notification Center']={allowRoles='AXNotificationCenterAlert'}} -- notification center alerts
---
--- -- subscribe to events
--- wf_terminal:subscribe(wf.windowFocused,some_fn) -- run a function whenever a terminal window is focused
--- wf_timewaster:subscribe(wf.hasWindow,startAnnoyingMe):subscribe(wf.hasNoWindows,stopAnnoyingMe) -- fight procrastination :)
---

这个注释是不是非常地清晰,看完后代码就出来了呢?
是的!
下面就是一个完整可运行的代码,直接拷贝到自己的 ~/.hammerspoon/init.lua – Finally那段注释上面就可以运行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-----------------------mine start-----------------------------
-- ADD by Thomas
local function Chinese()
hs.console.printStyledtext("chinese")
hs.keycodes.currentSourceID("com.apple.inputmethod.SCIM.ITABC")
end
local function English()
hs.console.printStyledtext(hs.keycodes.currentSourceID())
hs.keycodes.currentSourceID("com.apple.keylayout.ABC")
end
hs.console.printStyledtext("inputM:" + hs.keycodes.currentSourceID())
local function set_app_input_method(app_name, set_input_method_function, event)
event = event or hs.window.filter.windowFocused
hs.window.filter.new(app_name)
:subscribe(event, function() set_input_method_function() end)
end
set_app_input_method('Hammerspoon', English, hs.window.filter.windowCreated)
set_app_input_method('Spotlight', English, hs.window.filter.windowCreated)
-- set_app_input_method('Emacs', English)
set_app_input_method('Slack', English)
set_app_input_method('Terminal', English)
set_app_input_method('iTerm2', English)
set_app_input_method('Google Chrome', English)
set_app_input_method('WeChat', Chinese)
-----------------------mine end-----------------------------

其中:

  1. “com.apple.inputmethod.SCIM.ITABC”/“com.apple.keylayout.ABC”就是我的电脑上在用的中英文输入法,
    如果你不知道自己使用的输入法的名称可以切换对应输入法,打开 Hammerspoon 控制台,点击 Hammerspoon的 reload config,就会在Hammerspoon 控制台看到inputM 一段,就是你的输入法,替换上面对应名字即可。
  2. 如果有自己的应用需要,可以追加 set_app_input_method。

Bing 必应桌面的改进

使用 awesome-hammerspoon.git 下的Bing脚本,可以自动更新自己的桌面壁纸和必应官方同步,但是我发现有几个问题:
1)不支持多桌面。现在大多数工作环境都是两个或多个显示器,使用该脚本,发现只有一个桌面壁纸更新了。
原因在于 hammerspoon 默认更新的是mainScreen,它还有一个primaryScreen甚至allScreens区别,所以这里需要改一下。
2)下载的壁纸没有保存下来
3)桌面壁纸在大陆其实用的是 bing 国内版搜索的壁纸,想使用更适合做背景的国外版壁纸该怎么办?
只需要在请求链接的时候加一个 ENSEARCH=BENVER=1 的cookie就可以了。

上面问题的解决方法:
修改.hammerspoon/Spoons/BingDaily.spoon/init.lua文件,将下面代码中 +开头的代码行替换-开头的源代码行即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- local localpath = os.getenv("HOME") .. "/.Trash/" .. hs.http.urlParts(obj.full_url).lastPathComponent
- hs.screen.mainScreen():desktopImageURL("file://" .. localpath)
+ local localpath = os.getenv("HOME") .. "/Public/bing/" .. hs.http.urlParts(obj.full_url).queryItems[1].id
+ hs.console.printStyledtext("desktopIMG:" .. localpath)
+ hs.screen.primaryScreen():desktopImageURL("file://" .. localpath)
+ local scs=hs.screen.allScreens()
+ local count = 0
+ for _ in pairs(scs) do count = count + 1 end
+ hs.console.printStyledtext("table.size: " .. count)
+ for i=1,#scs do scs[i]:desktopImageURL("file://" .. localpath) end
- local user_agent_str = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4"
+ local user_agent_str = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
- hs.http.asyncGet(json_req_url, {["User-Agent"]=user_agent_str}, function(stat,body,header)
+ hs.http.asyncGet(json_req_url, {["User-Agent"]=user_agent_str,["cookie"]="ENSEARCH=BENVER=1"}, function(stat,body,header)
- local localpath = os.getenv("HOME") .. "/.Trash/" .. hs.http.urlParts(obj.full_url).lastPathComponent
+ local localpath = os.getenv("HOME") .. "/Public/bing/" .. hs.http.urlParts(obj.full_url).queryItems[1].id

其他:

在.hammerspoon/Spoons 文件夹下修改canlendar/aclokck的分布位置/大小/用色都较简单直白,就不列代码了。

最后,主要是对 Hammerspoon 扩展支持的功能还没深入了解过,希望有时间可以再做点开发,根据个人使用来看可添加的效率脚本太多了.

How

上面链接可见 Hammerspoon 是什么以及怎么用,可以重复下,非常简单:

1) 到官网下载并安装 Hammerspoon
2)最好给 Hammerspoon 授权,点击 “Enable Accessbility”

3)如果你是开发者,可以运行:

git clone https://github.com/ashfinal/awesome-hammerspoon.git   .hammerspoon

否则可直接下载 并保存到你的home文件夹下 的 .hammerspoon目录。

实际上述2步完成就是可用了,但只提供基本功能,如有需求可以自己写脚本了。不过感谢强大的开源文化,许多网友就开源了许多自己写的脚本,一开始可以用 3 步里的脚本合集,应该是早且权威的。

参考:

  1. 推荐一个 MacOS 上用了就无法自拔的神器Hammerspoon
  2. 免费又强大的 macOS 自动化工具,Hammerspoon 可以让你少买很多 App
  3. Use Hammerspoon to auto switch input methods
  4. 打造 macOS 的生产力环境 - Hammerspoon
  5. docs » hs.window.filter
  6. Emacs China