Skip to content

Remove Timer from WindowsKeyboardSwitchingAdapter and add IME diag#1495

Open
jasonleenaylor wants to merge 2 commits intomasterfrom
bugfix/imeKeyboardGlitches
Open

Remove Timer from WindowsKeyboardSwitchingAdapter and add IME diag#1495
jasonleenaylor wants to merge 2 commits intomasterfrom
bugfix/imeKeyboardGlitches

Conversation

@jasonleenaylor
Copy link
Copy Markdown
Contributor

@jasonleenaylor jasonleenaylor commented Mar 27, 2026

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.


Open with Devin

This change is Reviewable

devin-ai-integration[bot]

This comment was marked as resolved.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 27, 2026

Palaso Tests

     4 files  ±0       4 suites  ±0   9m 54s ⏱️ -17s
 5 095 tests ±0   4 862 ✅ ±0  233 💤 ±0  0 ❌ ±0 
16 597 runs  ±0  15 878 ✅ ±0  719 💤 ±0  0 ❌ ±0 

Results for commit 2d10845. ± Comparison against base commit ce83cef.

♻️ This comment has been updated with latest results.

…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>
@jasonleenaylor jasonleenaylor force-pushed the bugfix/imeKeyboardGlitches branch from c509789 to ea7c9a2 Compare April 7, 2026 20:52
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines 65 to +107
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)}");
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 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.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants