Eric's Blog 时光荏苒,岁月如梭

解决 Windows 系统下输入法问题

2025-04-23
Eric Wong

遇到的问题

最近更新 Windows 系统后,使用 ALT-Tab 快捷键切换窗口,每次切换回终端,输入法就会自动变成中文模式,非常影响 Neovim 的操作。

比如:每次切换到浏览器,复制下相关内容后,到 nvim 里面来想黏贴,通常使用 "+p 快捷键就可以了,但是由于当前输入法变成了中文模式, 就变成输入了 “+, Normal 模式下 无用,+ 直接给换到下一行。p 按键不会直接输入到终端,反而会弹出输入法候选框。

此外,由于自动切换到了中文输入,当想执行 Neovim 命令时,比如 :w<Cr> 的时候,同样的按键顺序,就会变成了:w, 未保存,同时相当于 Normal 模式下执行了一次 w 光标向前移动一个词位置。

实际原因

网上类似的讨论有很多:

  • https://www.v2ex.com/t/1120452

  • https://chunyujin.top/chunyujin/8728f196

但是并没有讲到真实的原因。在以前的系统里面(Win7),通常语言设置会有两个键盘,一个叫做美式键盘(一个灰色小的键盘图标), 另外一个键盘通常就是我们的输入法,比如搜狗的红色小图标,日常最常用的快捷键是 ctrl-space 来切换的是键盘,而不是某个输入法的中英文模式。 有时候,还不止两个键盘,比如同时安装了搜狗拼音、搜狗五笔,那么加上默认的美式键盘,就是三个键盘。通常使用 ctrl-space 来回切换,ctrl-shift 轮换。 虽然,以前搜狗输入也好,微软输入法也好,大多数提供了内置的中英文输入切换,通常快捷键是 shift 键。 而在最新版的 Windows 系统中,微软做了一件非常恶心的的事情,就是默认不给你安装美式键盘,只给你安装一个微软输入法, 并且把默认的键盘切换按键ctrl-space改为win-space,同时无法改回,只能在微软输入法里面设置ctrl-space切换自己的中英文模式。

解决方法

设置 - 时间和语言 - 语言和区域 - 首选语言 - 添加语言 - 找到 English(United States)添加。

此时就有两个键盘,使用 win-space 可以切换键盘。

美式键盘只做英文输入,微软拼音只做中文输入,关闭管软拼音的英文模式。

完成以上操作后就可以使用命令行工具 im-select 进行键盘切换了。

打开命令行窗口:分别在两个键盘模式下执行一次下载的 im-select.exe 可以看到输出如下:

关于这个命令的说明:

  1. 直接不带参数执行,获取当前键盘值,比如上图中,我分别先后在美式键盘和微软拼音下单独执行命令,获取到两个键盘值 1033 和 2052。
  2. 执行命令,并带上键盘值参数,切换至指定键盘,比如 im-select.exe 1033 切换至美式键盘,im-select.exe 2052 切换至微软拼音。

使用 Neovim autocmd 自动执行 im-select

local augroup = vim.api.nvim_create_augroup('wsdjeg', { clear = true })

local create_autocmd = vim.api.nvim_create_autocmd
-- 这里指定下载的 im-select.exe 的绝对路径,
-- 当然,你也可以将这个命令丢 PATH 里,个人不喜欢污染 PATH
local imselect = 'C:\\Users\\wsdjeg\\Downloads\\im-select.exe'

create_autocmd({ 'InsertLeave', 'FocusGained', 'CmdlineLeave', 'VimEnter' }, {
    pattern = { '*' },
    group = augroup,
    callback = function(_)
        -- 切换至美式键盘
        vim.system({ imselect, '1033' })
    end,
})
create_autocmd({ 'FocusLost' }, {
    pattern = { '*' },
    group = augroup,
    callback = function(_)
        -- 切换至微软拼音
        vim.system({ imselect, '2052' })
    end,
})

更好的解决方法

如果不想增加美式键盘,那么可以使用 im-select-mspy,对应的 Neovim 配置如下:


local augroup = vim.api.nvim_create_augroup('wsdjeg', { clear = true })

-- download im-select-mspy from https://github.com/daipeihust/im-select/raw/refs/heads/master/win-mspy/out/x64/im-select-mspy.exe
local imselect = 'C:\\Users\\wsdjeg\\Downloads\\im-select-mspy.exe'

local function imselect_cn()
    vim.system({ imselect, '-k=ctrl+space', '中文模式' })
end

local function imselect_en()
    vim.system({ imselect, '-k=ctrl+space', '英语模式' })
end

-- 使用 table 存储不同 buffer 的 Insert 模式下的输入法
local buffer_im = {}

create_autocmd({ 'InsertLeave' }, {
    pattern = { '*' },
    group = augroup,
    callback = function(ev)
        vim.system({ imselect }, { text = true }, function(o)
            -- 这里说明下,再 Windows Terminal 内执行该命令输出的内容默认编码是 `cp936`,
            -- 需要转码成 utf-8,同时,输出内容尾部有换行符,使用 trim 函数去除。
            buffer_im[ev.buf] = vim.trim(vim.iconv(o.stdout, 'cp936', 'utf-8'))
        end)
        imselect_en()
    end,
})
create_autocmd({ 'InsertEnter' }, {
    pattern = { '*' },
    group = augroup,
    callback = function(ev)
            local c = '英语模式'
        if buffer_im[ev.buf] and buffer_im[ev.buf] ~= '英语模式' then
            -- 此处设置快捷键,可以在输入法按键设置里面查看,我选择的是使用 ctrl-space 切换中英文
            -- 默认我记得是 shift,同时这个命令默认也是 `-k=shift`
            vim.system({ imselect, '-k=ctrl+space', buffer_im[ev.buf] })
        end
    end,
})

create_autocmd({ 'FocusGained', 'CmdlineLeave', 'VimEnter' }, {
    pattern = { '*' },
    group = augroup,
    callback = function(_)
        imselect_en()
    end,
})
create_autocmd({ 'FocusLost' }, {
    pattern = { '*' },
    group = augroup,
    callback = function(_)
        imselect_cn()
    end,
})

版权声明:本文为原创文章,遵循 署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)版权协议,转载请附上原文出处链接和本声明。


延生阅读

分享到:

评论

目前只支持使用邮件参与评论。