A tiny Windows input method helper written in Rust. It switches, toggles and
queries the input method between English (United States, locale 1033) and
Chinese (Simplified) - Microsoft Pinyin (locale 2052).
It is designed to be called from a terminal editor (Neovim, etc.) running inside WSL, where a Linux input method framework is not available and the actual IME lives on the Windows side.
- Toggle between English and Microsoft Pinyin.
- Switch directly to a specific locale.
- Query the current input method state as a single token, for display in a
statusline (e.g.
lualine). - Distinguishes Microsoft Pinyin's Chinese mode from its English (latin pass-through) mode by reading the IME conversion status.
im-select-rs.exe Toggle between English (1033) and Chinese (2052)
im-select-rs.exe 1033 Switch to English (United States)
im-select-rs.exe 2052 Switch to Chinese (Simplified) - Microsoft Pinyin
im-select-rs.exe 简中, zh Switch Microsoft Pinyin to Chinese mode
im-select-rs.exe 简英, py_en Switch Microsoft Pinyin to English mode
im-select-rs.exe -s, --status Print current input method state token
im-select-rs.exe -r, --raw Print raw locale/IME values for debugging
im-select-rs.exe -h, --help Show this help
Prints exactly one token on stdout, intended for machine consumption:
| Token | Meaning | Label |
|---|---|---|
eng |
English keyboard layout / IME closed | ENG |
zh |
Microsoft Pinyin, Chinese (native) mode | 简中 |
py_en |
Microsoft Pinyin, English (latin pass-through) mode | 简英 |
Example:
> im-select-rs.exe --status
zh
Prints the underlying values for verification / tuning on your own machine:
> im-select-rs.exe --raw
locale=2052 open=true conv=0x1 status=zh
locale- the active input language LANGID low word (1033/2052).open- whether the IME is open.conv- thefdwConversionbitmask; bit0x0001(IME_CMODE_NATIVE) is what separates Chinese mode from English mode.
If the Chinese / English distinction does not behave as expected for your IME,
run --raw in each state and check whether the conv bit toggles.
- The active input language is read from the foreground window's thread via
GetKeyboardLayout. The low word of theHKLis the LANGID. - Switching is done with
LoadKeyboardLayoutW+ActivateKeyboardLayout, followed by broadcastingWM_INPUTLANGCHANGEREQUEST. 简中/zhand简英/py_enfirst switch to Microsoft Pinyin, then sendWM_IME_CONTROL(IMC_SETOPENSTATUS/IMC_SETCONVERSIONMODE) to request the Chinese or English sub-mode.- The IME Chinese/English sub-mode is queried by sending
WM_IME_CONTROL(IMC_GETOPENSTATUS/IMC_GETCONVERSIONMODE) to the foreground window's default IME window (ImmGetDefaultIMEWnd) usingSendMessageTimeoutW. This is the standard cross-process way to read IME state, since the IME input context is thread-local and cannot be read directly from another process.
Requires the Rust toolchain with the x86_64-pc-windows-msvc target and the MSVC
build tools.
cargo build --release
The resulting binary is target/release/im-select-rs.exe.
- Windows 10 / 11.
- The input languages
1033(English (United States)) and2052(Chinese (Simplified) - Microsoft Pinyin) installed. - "Let me use a different input method for each app window" should be enabled (Settings > Time & Language > Typing > Advanced keyboard settings) so that the foreground window reflects what the user is actually typing.
- For the
zh/py_endistinction to work, the foreground window must be a classic Win32 app (see Troubleshooting).
If --raw reports open=false conv=0x0 while Microsoft Pinyin is the active
layout, the foreground window is a modern TSF application (Windows Terminal,
modern PowerShell, UWP/Edge-style apps). Such windows do not expose the legacy
IMM fdwConversion bits to other processes, so the Chinese/English sub-mode of
Microsoft Pinyin cannot be read cross-process from a separate .exe (TSF
compartments are thread-local; there is no global API for it).
This is a platform limitation, not a bug in the tool. Enabling "Use previous version of Microsoft Pinyin" only helps when the foreground is a classic Win32 window (e.g. GVim); it does not help inside Windows Terminal.
When the sub-mode is unreadable, --status falls back to zh for an active
Microsoft Pinyin (its primary mode), rather than always reporting py_en. To
get a reliable on/off signal that always works, switch layouts with Win+Space
(1033 = eng, 2052 = zh) instead of toggling Pinyin's internal sub-mode.
MIT