7.0 KiB
Vim 输入法自动切换插件
面向 macOS 原生 Vim 的输入法自动切换方案:
- Normal 模式固定英文输入法
- Insert 模式恢复同一 Vim 进程内上次使用的中/英状态
- macOS 上优先使用 Hammerspoon
hs.keycodes.setLayout()/hs.keycodes.setMethod() im-select仅作为 fallback
说明:本次 Hammerspoon 方案和行为调整只针对原生 Vim 插件
vim-im-switch-select.vim。Obsidian 插件逻辑不变。
Obsidian 插件说明
本仓库仍包含 Obsidian 插件入口 main.ts,用于在 Obsidian 启用 Vim keymap 时切换输入法。
当前 Obsidian 插件逻辑保持原样:
- 通过
fcitx-remote执行输入法查询和切换。 - 监听 Obsidian / CodeMirror 的 Vim 模式变化。
- Normal / Visual 模式切到英文输入法。
- Insert / Replace 模式恢复上次 Insert 状态。
- 配置项仍使用
manifest.json/ 插件设置页中的fcitx-remote路径和输入法 ID。
本次 Hammerspoon hs.keycodes.setLayout() / hs.keycodes.setMethod() 方案只应用在原生 Vim 插件 vim-im-switch-select.vim,没有改造 Obsidian 插件。
当前稳定策略
模式行为
| Vim 状态 | 行为 |
|---|---|
| Vim 启动后 | 延迟切到英文 ABC |
| 进入 Insert | 恢复本次 Vim 进程内上次 Insert 的中/英状态;首次默认中文 |
离开 Insert / Esc |
先记录 Insert 中最后的中/英状态,再切到英文 ABC |
示例:
第一次进入 Insert -> 中文
Insert 中手动切到英文 -> Esc -> 再次 Insert -> 英文
Insert 中手动切回中文 -> Esc -> 再次 Insert -> 中文
退出 Vim 后重新打开 -> 记忆重置,第一次 Insert 默认中文
为什么使用 Hammerspoon
之前只用 im-select 切换 macOS input source ID 时,Apple 拼音可能出现:
当前输入源ID: com.apple.inputmethod.SCIM.ITABC
当前键盘布局: ABC
当前输入法Method: Pinyin – Simplified
表现为菜单栏显示中文输入法,但实际仍输入英文。
Hammerspoon 可以直接设置 layout/method:
hs.keycodes.setLayout("ABC")
hs.keycodes.setMethod("Pinyin – Simplified")
这能避免只切 source ID 导致的 Apple 拼音内部状态不一致。
安装要求
1. Hammerspoon
安装并运行 Hammerspoon。
在 ~/.hammerspoon/init.lua 中启用 IPC:
require("hs.ipc")
hs.ipc.cliInstall()
Reload Hammerspoon config 后,确认命令可用:
hs -c 'hs.keycodes.setLayout("ABC")'
hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")'
两条命令都应返回:
true
如果出现:
can't access Hammerspoon message port Hammerspoon; is it running with the ipc module loaded?
说明 Hammerspoon IPC 未启用或配置尚未 reload。
2. im-select fallback(可选但建议保留)
当 hs 不可用时,插件会退回使用 im-select:
im-select
im-select com.apple.keylayout.ABC
im-select com.apple.inputmethod.SCIM.ITABC
常见输入源 ID:
| 输入法 | ID |
|---|---|
| ABC | com.apple.keylayout.ABC |
| Apple 简体拼音 | com.apple.inputmethod.SCIM.ITABC |
安装 Vim 插件
复制插件到 Vim plugin 目录:
mkdir -p ~/.vim/plugin
cp vim-im-switch-select.vim ~/.vim/plugin/
或在 .vimrc 中 source:
source /path/to/vim-im-switch-select.vim
配置
默认配置适用于 macOS ABC + Apple 简体拼音:
" Hammerspoon 主路径:英文键盘布局名
let g:imselect_hs_english_layout = 'ABC'
" Hammerspoon 主路径:中文输入法 Method 名
let g:imselect_hs_chinese_method = 'Pinyin – Simplified'
" im-select fallback:英文输入源 ID
let g:imselect_english_im = 'com.apple.keylayout.ABC'
" im-select fallback:中文输入源 ID
let g:imselect_chinese_im = 'com.apple.inputmethod.SCIM.ITABC'
延迟配置:
" 进入 Insert 后延迟恢复,默认 80ms
let g:imselect_restore_delay = 80
" 恢复后再次确认目标状态,默认 200ms
let g:imselect_confirm_delay = 200
工作原理
核心事件:
InsertLeavePre -> 记录 Insert 中最后的中/英状态
InsertLeave -> 切到英文 ABC
InsertEnter -> 延迟恢复上次 Insert 中/英状态
VimEnter -> 启动后延迟切到英文 ABC
关键点:
InsertLeavePre必须早于InsertLeave保存状态,否则InsertLeave已经切到英文。- timer 回调会检查目标状态,避免快速
i<Esc>后延迟回调把 Normal 模式切回中文。 - Hammerspoon 是主路径;
im-select只在hs不可用时 fallback。 - 状态记忆是 script-local 内存,只在当前 Vim 进程内有效。
手工测试
-
打开 Vim:
vim test-im-switch.txt -
第一次按
i进入 Insert:应切到中文。 -
输入中文,按
Esc:应切到英文ABC。 -
再按
i:应恢复中文。 -
Insert 中手动切到英文,输入英文,按
Esc。 -
再按
i:应恢复英文。 -
Insert 中手动切回中文,按
Esc,再按i:应恢复中文。 -
退出 Vim 后重新打开:第一次 Insert 默认中文,这是当前已知限制。
验证命令
Vimscript 加载检查:
vim -Nu NONE -n -es -S "/path/to/vim-im-switch-select.vim" -c 'qa'
Hammerspoon 检查:
hs -c 'hs.keycodes.setLayout("ABC")'
hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")'
已知限制
跨 Vim 进程不持久记忆
当前插件只在同一次 Vim 进程内记忆 Insert 中最后的中/英状态。
Insert 中切到英文 -> Esc -> 再 Insert -> 英文
退出 Vim -> 重新 vi -> 第一次 Insert 默认中文
这是当前已知问题,暂不做文件持久化。
依赖 Hammerspoon 运行
稳定路径依赖:
- Hammerspoon 正在运行
hsCLI 可用hs.ipc已启用- 输入法名称
Pinyin – Simplified与系统一致
如果 Hammerspoon 不可用,插件会 fallback 到 im-select,但 fallback 只能切 input source ID,不能完全解决 Apple 拼音内部状态问题。
不模拟 CapsLock / Ctrl-Space
当前实现不模拟 Caps Lock、Ctrl-Space、Shift 等系统快捷键。
原因:这些按键可能被 Vim 接收,导致退出 Insert 或产生额外副作用;之前调试也证明模拟 Caps 不稳定。
主要文件
| 文件 | 说明 |
|---|---|
vim-im-switch-select.vim |
当前原生 Vim 稳定插件 |
README.md |
当前说明文档 |
main.ts |
Obsidian 插件入口 |
故障排除
进入 Insert 仍然输入英文
先确认 Hammerspoon method 设置有效:
hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")'
如果返回 true 后仍异常,检查 Hammerspoon 日志或系统输入法名称是否不是 Pinyin – Simplified。
hs -c 报 IPC 错误
在 ~/.hammerspoon/init.lua 加入:
require("hs.ipc")
hs.ipc.cliInstall()
然后 reload Hammerspoon。
fallback 输入法 ID 不正确
切到目标输入法后运行:
im-select
将输出值配置到:
let g:imselect_chinese_im = '你的输入法ID'
License
MIT License