feat: fix TSF compartment external control for Weasel (Win10/Win11), deadlock fixes, --get-keyboard, and user guide#3
Open
VimWei wants to merge 17 commits into
Open
feat: fix TSF compartment external control for Weasel (Win10/Win11), deadlock fixes, --get-keyboard, and user guide#3VimWei wants to merge 17 commits into
VimWei wants to merge 17 commits into
Conversation
- Add `-g`/`--get-keyboard` CLI flag to query and display current keyboard open/close and alphanumeric/native state - Query TF compartment values directly in the hook to retrieve live keyboard state - Output keyboard state as "open native", "open alphanumeric", or "close" to stdout or file - Fix typo in usage string: "alphamumeric" to "alphanumeric" - use fprintln(outfile, ...) instead of println(...) for the -o file output
- Add type checks for VARIANT values before accessing keyboard open/close and conversion mode - Add new ERR_QUERY_KEYBOARD_STATE error code for query failures - Change --get-keyboard to use VERB_CURRENT instead of VERB_SWITCH - Add error reporting when fopen fails on the output file - Intentionally preserve prior error when keyboard state retrieval fails
Replace CreateFileMapping singleton guard with named mutex, add timeout to event wait, and reset stale event state. 1. Mutex (Local\IMControlMutex) replaces file mapping as singleton guard — auto-released when process dies, no residual blocking. 2. WaitForSingleObject timeout: INFINITE → 10000ms; on timeout returns ERR_SEND_MESSAGE_TIMEOUT_TIMED_OUT instead of hanging. 3. ResetEvent after CreateEventA to clear leftover signaled state from residual hook DLLs in target processes. 4. Bump version to 0.5.1.
- Check vt == VT_I4 || VT_UI4 before reading lVal from GetValue result, defaulting oldMode to 0 when the compartment is empty (S_FALSE) to avoid reading uninitialized memory - Set vt = VT_I4 before SetValue to ensure the variant type is correct even when GetValue returned S_FALSE and left vt as VT_EMPTY
Always calling SetValue on GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, even when the value is the same, triggers Weasel's OPENCLOSE handler (blind toggle of ascii_mode when _isToOpenClose=false). This causes spurious mode flips on every invocation that includes -k open. Read current value via GetValue and only call SetValue when it differs, matching the existing logic for the CONVERSION compartment.
Windows 11 TSF only triggers ITfCompartmentEventSink::OnChange for writes from activated clients (non-zero TfClientId). The hook was using TF_CLIENTID_NULL (0) in SetValue calls, so OnChange was never fired on Windows 11 — WeaselTSF's CONVERSION handler never executed for external compartment writes. Call ITfThreadMgr::Activate to obtain a valid TfClientId, use it in all SetValue calls, and Deactivate when done.
…Value Log TfClientId from ITfThreadMgr::Activate, and old/new mode + HRESULT for CONVERSION compartment SetValue. Use DebugView to diagnose Windows 11 OnChange behavior.
Replace OutputDebugStringW with LOG_INFO/LOG_ERROR for Activate and CONVERSION SetValue. Enable logInit for hook32 (was commented out). Logs go to %LOCALAPPDATA%\im-control\hook32.log and hook64.log.
On Windows 11, CoCreateInstance(CLSID_TF_ThreadMgr) returns a NEW ThreadMgr instance instead of the per-thread singleton. Compartment writes on the new instance don't trigger OnChange notifications on sinks (like WeaselTSF's) registered on the framework-provided singleton. TF_GetThreadMgr is an undocumented-but-stable export from msctf.dll that reliably returns the per-thread ThreadMgr singleton on both Windows 10 and 11. Replace both CoCreateInstance(CLSID_TF_ThreadMgr) calls (get-keyboard-state path and verb-switch path) with GetThreadMgrSingleton(). Debug logs confirmed: im-control SetValue succeeded (hr=S_OK) but WeaselTSF _HandleCompartment never fired on Windows 11.
Record the ThreadMgr pointer and thread ID from TF_GetThreadMgr to compare with WeaselTSF's ActivateEx pThreadMgr pointer.
The w mode overwrites the log on every im-control invocation, making it impossible to see historical calls. Use append mode to preserve all invocations for debugging.
Remove verbose LOG_INFO calls for TF_GetThreadMgr pointer, Activate clientId, and CONVERSION SetValue details. Restore log file open mode to w (truncate) as per original behavior.
Add section on Win11 TSF differences (TF_GetThreadMgr, TfClientId), guidance on decoupling CONVERSION and OPENCLOSE when used with Weasel, and link to the full fix analysis document.
Author
|
关闭了之前的两个PR,重新提交完整的PR。 PS:
|
- Read registry ToggleImeOnOpenClose at DllMain to detect Win10 (yes) vs Win11 (no) OPENCLOSE handler behavior - After writing CONVERSION compartment, only reopen OPENCLOSE when g_isToOpenClose is true and keyboard is currently closed - Skip reopen on Win11 (ToggleImeOnOpenClose=no) where OPENCLOSE else branch auto-reopens and intervention causes cascade ascii toggle - Fixes RIME being disabled when gvim exits insert mode with English active on Windows 10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR makes im-control's TSF compartment control fully work with Weasel (RIME) on both Windows 10 and Windows 11, and improves robustness across the board.
Core Fix: TSF Compartment Control for Weasel
Previously, programmatically writing
GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSIONvia im-control had no effect on Weasel. The root cause differed by OS:OnChange, but Weasel immediately reverts it_HandleCompartment: reads the compartment value instead, compares with current state, only switches if differentCoCreateInstance(CLSID_TF_ThreadMgr)returns a new instance instead of the per-thread singleton, so the write goes to a different TSF instance; (b)SetValue(TF_CLIENTID_NULL, ...)doesn't triggerOnChangefor non-activated clientsTF_GetThreadMgrexport frommsctf.dll(033c0cd); (b) CallITfThreadMgr::Activatefor a validTfClientId(c0b4eae)_SetKeyboardOpen(true), triggering OPENCLOSE handler's blind toggle that flipped the mode back_SetKeyboardOpen(true)from CONVERSION handler, fully decoupling the two compartmentsA detailed root cause analysis is available in the Weasel companion repo: compartment-external-control-fix.md.
Additional Robustness Fixes
VARIANTtype before reading/writing conversion compartment (f00137c)SetValuewhen value unchanged, avoiding unnecessary handler triggers (1c1b915)bbdb760)Deadlock & Hang Prevention
99cad69)169288d)New Features
--get-keyboardoption to query current keyboard state (2fae7de)-l/--listto enumerate installed input methods (028ba8c)-h/--helpfor CLI usage (5404ba8)Documentation
6a669cf)Companion Changes
im-controlim-controlim_control_set_mode()writes only CONVERSION, drops-k open— two compartments fully decoupled