在 macOS 中利用 Hammerspoon 自动切换输入法。

因为 Rime 目前的中英切换不是特别好用:

Rime 全局状态功能的进展:global input session, state shared by all client apps #294


我希望的是:无论当前是什么输入法,切换到 iTerm,就是英文,离开 iTerm,回到我原先的输入法。

类似于 Alfred 目前的功能(高级设置中的 Force Keyboard 设置为 ABC)。

我在 Typora 写中文,呼出 Alfred,变成英文输入法,用完了回到 Typora,变回中文输入法。


代码参考于:ibreathebsb/hammerspoon自动切换输入法.lua

使用方法:放到 ~/.hammerspoon/init.lua 重新部署就可以了。

可以用 Cmd + Ctrl + . 来查看当前窗口的 name 或 path;

可以在 Hammerspoon 的控制台输入 hs.keycodes.currentSourceID() 来查看当前输入法的 ID。

做的修改:

  • 以 App name 作为参数,看起来舒服点
  • 退出指定的程序后,恢复到原先的输入法
-- 当选中某窗口按下 ctrl+command+. 时会显示应用的路径、名字等信息
hs.hotkey.bind({'ctrl', 'cmd'}, ".", function()
    hs.pasteboard.setContents(hs.window.focusedWindow():application():path())
    hs.alert.show("App path:        " .. hs.window.focusedWindow():application():path() .. "\n" .. "App name:      " ..
                      hs.window.focusedWindow():application():name() .. "\n" .. "IM source id:  " ..
                      hs.keycodes.currentSourceID(), hs.alert.defaultStyle, hs.screen.mainScreen(), 3)
end)

-- 这里指定中文和英文输入法的 ID
local function Chinese()
    hs.keycodes.currentSourceID("im.rime.inputmethod.Squirrel.Rime")
end
local function English()
    hs.keycodes.currentSourceID("com.apple.keylayout.ABC")
end

-- 指定程序
local appInputMethod = {
    iTerm2 = English,
    ['EuDic LightPeek'] = English,
    Bitwarden = English,
    SnippetsLab = English,
    ['微信'] = Chinese,
}

-- activated 时切换到指定的输入法,deactivated 时恢复之前的状态
currentID = ""
function applicationWatcher(appName, eventType, appObject)
    if (eventType == hs.application.watcher.activated) then
        for app, fn in pairs(appInputMethod) do
            if app == appName then
                currentID = hs.keycodes.currentSourceID()
                fn()
            end
        end
    end
    if eventType == hs.application.watcher.deactivated then
        for app, fn in pairs(appInputMethod) do
            if app == appName then
                hs.keycodes.currentSourceID(currentID)
                currentID = hs.keycodes.currentSourceID()
            end
        end
    end
end

appWatcher = hs.application.watcher.new(applicationWatcher):start()

-- 输入法切换提示
-- hs.keycodes.inputSourceChanged(function()
--     if hs.keycodes.currentMethod() == nil then
--         hs.alert.show("ABC", hs.alert.defaultStyle, hs.screen.mainScreen(), 2)
--     else
--         hs.alert.show("拼音", hs.alert.defaultStyle, hs.screen.mainScreen(), 2)
--     end
-- end)

小问题:

无法识别 Alfred 的窗口,不过 Alfred 自带这个功能,和本配置功能一样。

本来想弄个提示的,但是每次切换时都会产生意料之外的多次切换,比如「ABC → ABC → ABC」或「ABC → 拼音 → ABC」,不知为何中间发生了多次切换,这导致菜单栏的输入法图标发生了一阵短暂而急促的抖动,不过好在结果都是正确的。

我看 Alfred 自己的功能也有这个问题,不知道有没有可能是 macOS 的 Bug。

最后只好注释掉 hs.alert.show 的提示了。