update at 2026-07-15 11:04:39

This commit is contained in:
douboer
2026-07-15 11:04:39 +08:00
parent 995d672f4a
commit aeade0f813
7 changed files with 386 additions and 820 deletions

525
README.md
View File

@@ -1,353 +1,286 @@
# Vim 输入法自动切换插件
[![Version](https://img.shields.io/badge/version-2.0.3-blue.svg)](./CHANGELOG.md)
[![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey.svg)](#安装要求)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE.txt)
面向 macOS 原生 Vim 的输入法自动切换方案:
[English](./README_en.md) | 中文
- Normal 模式固定英文输入法
- Insert 模式恢复同一 Vim 进程内上次使用的中/英状态
- macOS 上优先使用 Hammerspoon `hs.keycodes.setLayout()` / `hs.keycodes.setMethod()`
- `im-select` 仅作为 fallback
[感谢 github 中的 vim-im-switch这个项目](https://github.com/yourusername/vim-im-switch)
这个项目不能满足需求,在这个项目基础上改进。
> 说明:本次 Hammerspoon 方案和行为调整只针对原生 Vim 插件 `vim-im-switch-select.vim`。Obsidian 插件逻辑不变。
作者Gavin Chan
## Obsidian 插件说明
> 🚀 **智能输入法管理工具** - 为 Vim 用户打造的无感知输入法切换体验
本仓库仍包含 Obsidian 插件入口 `main.ts`,用于在 Obsidian 启用 Vim keymap 时切换输入法。
这是为 **原生 Vim****Obsidian 编辑器** 的 Vim 模式设计的智能输入法自动切换插件,包含
- 🎯 **Obsidian 插件**:适用于 Obsidian 编辑器的 Vim 模式
-**Vim 插件**:适用于原生 Vim/NeoVim 编辑器
- 🌍 **跨平台支持**macOS、Linux、Windows 全平台兼容
当前 Obsidian 插件逻辑保持原样
## ✨ 功能亮点
- 通过 `fcitx-remote` 执行输入法查询和切换。
- 监听 Obsidian / CodeMirror 的 Vim 模式变化。
- Normal / Visual 模式切到英文输入法。
- Insert / Replace 模式恢复上次 Insert 状态。
- 配置项仍使用 `manifest.json` / 插件设置页中的 `fcitx-remote` 路径和输入法 ID。
- 🔄 **自动切换输入法**:在 Vim 的 Normal 模式和 Insert 模式之间切换时,自动切换输入法
- 🧠 **智能状态记忆**:记住上次 Insert 模式退出时的输入法状态,下次进入时自动恢复
- 🎭 **无感知体验**:完全静默切换,无 UI 闪烁或延迟
- 🌐 **中英混合友好**:完美支持中英文混合输入场景
-**多重保障机制**:三层检测确保切换的可靠性
本次 Hammerspoon `hs.keycodes.setLayout()` / `hs.keycodes.setMethod()` 方案只应用在原生 Vim 插件 `vim-im-switch-select.vim`,没有改造 Obsidian 插件。
## 核心特性
### 1. 模式切换自动化
- 进入 Normal 模式(按 ESC 或其他命令)→ 自动切换到英文输入法
- 进入 Insert 模式(按 i, a, o 等)→ 自动恢复上次的输入法状态
## 当前稳定策略
### 2. 输入法状态记忆
- 退出 Insert 模式时,自动检测并保存当前的输入法(中文/英文)
- 下次进入 Insert 模式时,自动恢复到上次保存的输入法状态
- 支持中英文混合输入场景
### 模式行为
### 3. 智能检测机制
插件采用**三重检测机制**确保可靠性:
| Vim 状态 | 行为 |
|---|---|
| Vim 启动后 | 延迟切到英文 `ABC` |
| 进入 Insert | 恢复本次 Vim 进程内上次 Insert 的中/英状态;首次默认中文 |
| 离开 Insert / `Esc` | 先记录 Insert 中最后的中/英状态,再切到英文 `ABC` |
| 检测方式 | 优先级 | 说明 |
|---------|--------|------|
| 🎯 **键盘事件监听** | 最高 | 使用事件捕获模式监听 ESC 和 Insert 按键,响应最快 |
| 🔧 **CodeMirror 事件** | 中等 | 监听 vim-mode-change 事件,处理非按键触发的模式切换 |
| 🔄 **定时轮询** | 兜底 | 100ms 轮询检测模式变化,作为最后保障机制 |
示例:
### 4. 技术特性
-**异步处理**:使用 `job_start()` 异步执行,避免 UI 阻塞
- 🛡️ **防抖机制**100ms 防抖避免重复处理
- 🎯 **事件捕获优化**:使用 capture 模式确保最快响应
- 🔧 **自动检测**:智能检测和配置中文输入法
```text
第一次进入 Insert -> 中文
Insert 中手动切到英文 -> Esc -> 再次 Insert -> 英文
Insert 中手动切回中文 -> Esc -> 再次 Insert -> 中文
退出 Vim 后重新打开 -> 记忆重置,第一次 Insert 默认中文
```
### 为什么使用 Hammerspoon
之前只用 `im-select` 切换 macOS input source ID 时Apple 拼音可能出现:
```text
当前输入源ID: com.apple.inputmethod.SCIM.ITABC
当前键盘布局: ABC
当前输入法Method: Pinyin Simplified
```
表现为菜单栏显示中文输入法,但实际仍输入英文。
Hammerspoon 可以直接设置 layout/method
```lua
hs.keycodes.setLayout("ABC")
hs.keycodes.setMethod("Pinyin Simplified")
```
这能避免只切 source ID 导致的 Apple 拼音内部状态不一致。
## 安装要求
#### macOS
1. 安装 [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx):
```bash
brew install fcitx-remote-for-osx
```
### 1. Hammerspoon
2. 验证安装:
```bash
fcitx-remote -n
# 应该输出当前输入法的名称com.apple.keylayout.ABC
```
安装并运行 Hammerspoon。
`~/.hammerspoon/init.lua` 中启用 IPC
```lua
require("hs.ipc")
hs.ipc.cliInstall()
```
Reload Hammerspoon config 后,确认命令可用:
#### Linux
通过你的包管理器安装 `fcitx`
```bash
# Ubuntu/Debian
sudo apt-get install fcitx
# Fedora
sudo dnf install fcitx
# Arch Linux
sudo pacman -S fcitx
hs -c 'hs.keycodes.setLayout("ABC")'
hs -c 'hs.keycodes.setMethod("Pinyin Simplified")'
```
#### Windows
使用项目内置的 AutoHotkey 脚本:
1. 安装 [AutoHotkey](https://www.autohotkey.com/)
2. 使用项目中的 `fcitx-remote.ahk` 脚本
3. 或下载编译好的版本:[fcitx-remote.exe](https://github.com/yuanotes/obsidian-vim-im-switch-plugin/releases/download/1.0.3/fcitx-remote.exe)
4. 将 exe 文件放到系统 PATH 路径中
两条命令都应返回:
## 安装插件
### Obsidian 插件安装
1. 下载插件文件到 Obsidian 插件目录:
```bash
cd /path/to/your/vault/.obsidian/plugins/
git clone https://github.com/yourusername/vim-im-switch.git
```
2. 在 Obsidian 中启用插件:
- 打开设置 → 社区插件 → 浏览
- 找到 "Vim Input Method Switch"
- 点击启用
3. 配置输入法(可选):
- 打开插件设置
- 设置英文输入法(默认:`com.apple.keylayout.ABC`
- 设置中文输入法(默认:自动检测)
### Vim 插件安装
1. 复制插件文件到 Vim 配置目录:
```bash
mkdir -p ~/.vim/plugin
cp vim-im-switch.vim ~/.vim/plugin/
```
2. 重启 Vim插件会自动加载
3. 配置输入法(可选):
在 `.vimrc` 中添加:
```vim
" 英文输入法 ID默认值
let g:fcitx_english_im = 'com.apple.keylayout.ABC'
" 中文输入法 ID可选插件会自动检测
" let g:fcitx_chinese_im = 'com.tencent.inputmethod.wetype.pinyin'
```
#### 使用插件管理器安装
**vim-plug**:
```vim
Plug 'yourusername/vim-im-switch'
```text
true
```
**Vundle**:
```vim
Plugin 'yourusername/vim-im-switch'
如果出现:
```text
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`
使用部署脚本同时安装 Obsidian 插件和 Vim 插件:
```bash
# 克隆项目
git clone https://github.com/yourusername/vim-im-switch.git
cd vim-im-switch
# 构建并部署
npm install
./deploy.sh
im-select
im-select com.apple.keylayout.ABC
im-select com.apple.inputmethod.SCIM.ITABC
```
> 💡 **提示**: v2.0.2 修复了终端 Vim 中的标题闪烁问题,详见 [更新日志](./CHANGELOG.md)
常见输入源 ID
## 使用方法
| 输入法 | ID |
|---|---|
| ABC | `com.apple.keylayout.ABC` |
| Apple 简体拼音 | `com.apple.inputmethod.SCIM.ITABC` |
### 基本使用场景
## 安装 Vim 插件
1. **中文输入**
```
按 i → 进入 Insert 模式 → 输入法切换到中文(如果上次是中文)
输入中文内容
按 ESC → 退出到 Normal 模式 → 输入法切换到英文
```
复制插件到 Vim plugin 目录
2. **英文输入**
```
按 i → 进入 Insert 模式 → 输入法保持英文(如果上次是英文)
输入英文内容
按 ESC → 退出到 Normal 模式 → 输入法保持英文
```
```bash
mkdir -p ~/.vim/plugin
cp vim-im-switch-select.vim ~/.vim/plugin/
```
3. **中英混合**
```
按 i → 自动恢复上次的输入法
输入中文,然后手动切换到英文继续输入
按 ESC → 保存当前输入法状态(英文)
按 i → 自动恢复英文输入法
```
或在 `.vimrc` 中 source
### 支持的 Vim 命令
```vim
source /path/to/vim-im-switch-select.vim
```
- **进入 Insert 模式**`i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C`
- **退出 Insert 模式**`ESC`, 以及其他触发 Normal 模式的命令
## 配置
默认配置适用于 macOS ABC + Apple 简体拼音:
```vim
" 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'
```
延迟配置:
```vim
" 进入 Insert 后延迟恢复,默认 80ms
let g:imselect_restore_delay = 80
" 恢复后再次确认目标状态,默认 200ms
let g:imselect_confirm_delay = 200
```
## 工作原理
```mermaid
graph TD
A[Normal 模式<br/>英文输入法] -->|按 i/a/o 等| B[检测模式切换]
B --> C[恢复上次保存的<br/>输入法状态]
C --> D[Insert 模式<br/>自动恢复的输入法:<br/>中文/英文]
D -->|按 ESC| E[保存当前输入法<br/>状态 中/英]
E --> F[切换到英文输入法]
F --> A
核心事件:
style A fill:#e1f5ff,stroke:#01579b,stroke-width:2px
style D fill:#fff9c4,stroke:#f57f17,stroke-width:2px
style E fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
style F fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px
```
插件维护一个状态机,跟踪 Vim 模式和输入法状态,在模式转换时自动切换输入法,同时保留用户偏好设置。
## 🔧 故障排除
### 快速诊断
使用内置诊断脚本:
```bash
./diagnose-im.sh
```
### 常见问题
#### 🚫 插件没有效果
1. **检查依赖**:确认 fcitx-remote 是否正确安装
```bash
# macOS
fcitx-remote -n
# Linux
which fcitx-remote
# Windows
fcitx-remote.exe
```
2. **检查日志**
- **Obsidian**: 开发者控制台 (Ctrl+Shift+I)
- **Vim**: `:messages` 命令
3. **验证配置**:确认输入法名称与系统设置匹配
#### ⚠️ 输入法切换不正确
1. **获取正确的输入法名称**
```bash
# 切换到中文输入法后执行
fcitx-remote -n
```
2. **手动测试**
```bash
# 切换到英文
fcitx-remote -s com.apple.keylayout.ABC
# 切换到中文(替换为你的输入法名称)
fcitx-remote -s com.tencent.inputmethod.wetype.pinyin
```
3. **检查冲突**:暂时禁用其他 Vim 插件测试
#### 🐛 其他问题
- **权限问题**:确保 fcitx-remote 有执行权限
- **路径问题**:检查 fcitx-remote 是否在 PATH 中
- **版本兼容**:确认 Vim 版本支持 `job_start()` (Vim 8+)
## 🛠️ 开发指南
### 环境要求
- Node.js 14+
- TypeScript 4.2+
- Rollup (构建工具)
### 构建项目
```bash
# 安装依赖
npm install
# 开发模式(监听文件变化)
npm run dev
# 生产构建
npm run build
```
### 项目结构
```
vim-im-switch/
├── main.ts # Obsidian 插件主文件
├── vim-im-switch.vim # Vim 插件文件
├── fcitx-remote.ahk # Windows 支持脚本
├── fcitx-remote-for-osx/ # macOS 支持工具
├── deploy.sh # 一键部署脚本
├── diagnose-im.sh # 诊断脚本
└── vim-im-switch-plugin/ # 构建输出目录
```
### 调试方法
#### Obsidian 插件调试
插件会在控制台输出关键日志:
```
🚀 [VimIMSwitch] Loading plugin...
🔤 [VimIMSwitch] ESC → English (saved Chinese)
🈳 [VimIMSwitch] → Chinese
❌ [VimIMSwitch] Error: ...
```
#### Vim 插件调试
```vim
" 查看插件消息
:messages
" 检查插件是否加载
:echo exists('g:fcitx_remote')
" 手动测试函数
:call Fcitx2en()
:call Fcitx2zh()
InsertLeavePre -> 记录 Insert 中最后的中/英状态
InsertLeave -> 切到英文 ABC
InsertEnter -> 延迟恢复上次 Insert /英状态
VimEnter -> 启动后延迟切到英文 ABC
```
### 贡献指南
1. Fork 项目
2. 创建功能分支:`git checkout -b feature/amazing-feature`
3. 提交更改:`git commit -m 'Add amazing feature'`
4. 推送分支:`git push origin feature/amazing-feature`
5. 提交 Pull Request
关键点:
## 📋 版本历史
- `InsertLeavePre` 必须早于 `InsertLeave` 保存状态,否则 `InsertLeave` 已经切到英文。
- timer 回调会检查目标状态,避免快速 `i<Esc>` 后延迟回调把 Normal 模式切回中文。
- Hammerspoon 是主路径;`im-select` 只在 `hs` 不可用时 fallback。
- 状态记忆是 script-local 内存,只在当前 Vim 进程内有效。
| 版本 | 日期 | 主要更新 |
|------|------|----------|
| [v2.0.3](./CHANGELOG.md#203---2025-11-09) | 2025-11-09 | 修复 Normal 模式 ESC 键问题 |
| [v2.0.2](./CHANGELOG.md#202---2025-11-04) | 2025-11-04 | 修复终端兼容性问题 |
| [v2.0.0](./CHANGELOG.md#200---2025-11-04) | 2025-11-04 | 新增 Vim 原生插件支持 |
| [v1.0.8](./CHANGELOG.md#108---2025-01-04) | 2025-01-04 | 智能状态记忆功能 |
| [v1.0.0](./CHANGELOG.md#100---2024-06-01) | 2024-06-01 | 首次发布 |
## 手工测试
查看 [完整更新日志](./CHANGELOG.md) 获取详细的版本更新历史。
1. 打开 Vim
## 🔗 相关链接
```bash
vim test-im-switch.txt
```
- 📖 [English Documentation](./README_en.md)
- 📝 [更新日志](./CHANGELOG.md)
- 🛠️ [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx)
- 🐛 [问题反馈](https://github.com/yourusername/vim-im-switch
2. 第一次按 `i` 进入 Insert应切到中文。
3. 输入中文,按 `Esc`:应切到英文 `ABC`。
4. 再按 `i`:应恢复中文。
5. Insert 中手动切到英文,输入英文,按 `Esc`。
6. 再按 `i`:应恢复英文。
7. Insert 中手动切回中文,按 `Esc`,再按 `i`:应恢复中文。
8. 退出 Vim 后重新打开:第一次 Insert 默认中文,这是当前已知限制。
## 🙏 致谢
## 验证命令
感谢以下项目和贡献者
- [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx) - macOS 输入法控制工具
- [Obsidian](https://obsidian.md/) - 强大的知识管理工具
- [Vim](https://www.vim.org/) / [NeoVim](https://neovim.io/) - 经典的文本编辑器
Vimscript 加载检查
---
```bash
vim -Nu NONE -n -es -S "/path/to/vim-im-switch-select.vim" -c 'qa'
```
<div align="center">
Hammerspoon 检查:
**如果这个项目对你有帮助,请给个 ⭐ Star**
```bash
hs -c 'hs.keycodes.setLayout("ABC")'
hs -c 'hs.keycodes.setMethod("Pinyin Simplified")'
```
Made with ❤️ for Vim users
## 已知限制
</div>
### 跨 Vim 进程不持久记忆
当前插件只在同一次 Vim 进程内记忆 Insert 中最后的中/英状态。
```text
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 Lock`、`Ctrl-Space`、`Shift` 等系统快捷键。
原因:这些按键可能被 Vim 接收,导致退出 Insert 或产生额外副作用;之前调试也证明模拟 Caps 不稳定。
## 主要文件
| 文件 | 说明 |
|---|---|
| `vim-im-switch-select.vim` | 当前原生 Vim 稳定插件 |
| `README.md` | 当前说明文档 |
| `main.ts` | Obsidian 插件入口 |
## 故障排除
### 进入 Insert 仍然输入英文
先确认 Hammerspoon method 设置有效:
```bash
hs -c 'hs.keycodes.setMethod("Pinyin Simplified")'
```
如果返回 `true` 后仍异常,检查 Hammerspoon 日志或系统输入法名称是否不是 `Pinyin Simplified`。
### `hs -c` 报 IPC 错误
在 `~/.hammerspoon/init.lua` 加入:
```lua
require("hs.ipc")
hs.ipc.cliInstall()
```
然后 reload Hammerspoon。
### fallback 输入法 ID 不正确
切到目标输入法后运行:
```bash
im-select
```
将输出值配置到:
```vim
let g:imselect_chinese_im = '你的输入法ID'
```
## License
MIT License