Remove Timer from WindowsKeyboardSwitchingAdapter and add IME diag#1495
Remove Timer from WindowsKeyboardSwitchingAdapter and add IME diag#1495jasonleenaylor wants to merge 2 commits intomasterfrom
Conversation
…tics Replace the Timer-based deferred IME conversion status restore with synchronous restore. The Timer caused jittery, unreliable IME switching for Chinese Pinyin and other TSF-based IMEs. The synchronous approach ensures ImmSetConversionStatus is applied before any subsequent SaveImeConversionStatus can capture stale values. Add Trace.WriteLine diagnostic logging throughout keyboard switching, IME save/restore, and post-switch state verification to aid debugging of intermittent IME composition issues. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
c509789 to
ea7c9a2
Compare
| private bool SwitchByProfile(WinKeyboardDescription keyboard) | ||
| { | ||
| var focusBefore = Win32.GetFocus(); | ||
| Trace.WriteLine($"[KbdSwitch] SwitchByProfile START: {keyboard.Name}, LangId=0x{keyboard.InputProcessorProfile.LangId:X4}, ProfileType={keyboard.InputProcessorProfile.ProfileType}, focus=0x{focusBefore:X}, focusClass={GetWindowClassName(focusBefore)}"); | ||
|
|
||
| _adaptor.ProcessorProfiles.ChangeCurrentLanguage(keyboard.InputProcessorProfile.LangId); | ||
| Trace.WriteLine($"[KbdSwitch] ChangeCurrentLanguage done, CurrentInputLanguage={InputLanguage.CurrentInputLanguage.Culture.Name}"); | ||
|
|
||
| Guid classId = keyboard.InputProcessorProfile.ClsId; | ||
| Guid guidProfile = keyboard.InputProcessorProfile.GuidProfile; | ||
| _adaptor.ProfileManager.ActivateProfile(keyboard.InputProcessorProfile.ProfileType, keyboard.InputProcessorProfile.LangId, ref classId, ref guidProfile, | ||
| keyboard.InputProcessorProfile.Hkl, TfIppMf.ForProcess); | ||
|
|
||
| RestoreImeConversionStatus( | ||
| keyboard); // Restore it even though sometimes windows will ignore us | ||
| Timer.Stop(); | ||
| Timer.Start(); // Start the timer for restoring IME status for when windows ignores us. | ||
| var focusAfter = Win32.GetFocus(); | ||
| var hkl = Win32.GetKeyboardLayout(0); | ||
| Trace.WriteLine($"[KbdSwitch] ActivateProfile done, CurrentInputLanguage={InputLanguage.CurrentInputLanguage.Culture.Name}, focus=0x{focusAfter:X} (focusChanged={focusBefore != focusAfter}), threadHKL=0x{hkl:X}"); | ||
|
|
||
| RestoreImeConversionStatus(keyboard); | ||
| TraceImeState("PostSwitch", focusAfter, keyboard); | ||
|
|
||
| Trace.WriteLine("[KbdSwitch] SwitchByProfile END"); | ||
| return true; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Log detailed IME state for diagnosing intermittent IME activation issues. | ||
| /// </summary> | ||
| private void TraceImeState(string context, IntPtr focusHwnd, WinKeyboardDescription keyboard) | ||
| { | ||
| var windowHandle = new HandleRef(this, focusHwnd); | ||
| var contextPtr = Win32.ImmGetContext(windowHandle); | ||
| if (contextPtr == IntPtr.Zero) | ||
| { | ||
| Trace.WriteLine($"[KbdSwitch] {context}: ImmGetContext=NULL (focus=0x{focusHwnd:X}) — no IME context available"); | ||
| return; | ||
| } | ||
| var contextHandle = new HandleRef(this, contextPtr); | ||
| var isOpen = Win32.ImmGetOpenStatus(contextHandle); | ||
| int convMode, sentMode; | ||
| Win32.ImmGetConversionStatus(contextHandle, out convMode, out sentMode); | ||
| Win32.ImmReleaseContext(windowHandle, contextHandle); | ||
| Trace.WriteLine($"[KbdSwitch] {context}: IME open={isOpen}, conversion=0x{convMode:X}, sentence=0x{sentMode:X}, focus=0x{focusHwnd:X}, focusClass={GetWindowClassName(focusHwnd)}"); | ||
| } |
There was a problem hiding this comment.
🚩 Diagnostic tracing left in production code
Numerous Trace.WriteLine calls have been added throughout the keyboard switching logic (SwitchByProfile, TraceImeState, SaveImeConversionStatus, RestoreImeConversionStatus, DeactivateKeyboard). System.Diagnostics.Trace.WriteLine is typically stripped in Release builds unless a trace listener is configured, so this won't affect production performance by default. However, this is a significant amount of diagnostic instrumentation — it appears to be intentionally left in to help diagnose intermittent IME issues per the PR description. Worth confirming this is the intended long-term approach rather than temporary debugging.
Was this helpful? React with 👍 or 👎 to provide feedback.
Replace the Timer-based deferred IME conversion status restore with synchronous restore. The Timer caused jittery, unreliable IME switching for Chinese Pinyin and other TSF-based IMEs. The synchronous approach ensures ImmSetConversionStatus is applied before any subsequent SaveImeConversionStatus can capture stale values.
Add Trace.WriteLine diagnostic logging throughout keyboard switching, IME save/restore, and post-switch state verification to aid debugging of intermittent IME composition issues.
This change is