Files
vim-im-switch/README.md
2026-07-15 11:04:39 +08:00

7.0 KiB
Raw Blame History

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 进程内有效。

手工测试

  1. 打开 Vim

    vim test-im-switch.txt
    
  2. 第一次按 i 进入 Insert应切到中文。

  3. 输入中文,按 Esc:应切到英文 ABC

  4. 再按 i:应恢复中文。

  5. Insert 中手动切到英文,输入英文,按 Esc

  6. 再按 i:应恢复英文。

  7. Insert 中手动切回中文,按 Esc,再按 i:应恢复中文。

  8. 退出 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 正在运行
  • hs CLI 可用
  • hs.ipc 已启用
  • 输入法名称 Pinyin Simplified 与系统一致

如果 Hammerspoon 不可用,插件会 fallback 到 im-select,但 fallback 只能切 input source ID不能完全解决 Apple 拼音内部状态问题。

不模拟 CapsLock / Ctrl-Space

当前实现不模拟 Caps LockCtrl-SpaceShift 等系统快捷键。

原因:这些按键可能被 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