Description
I'm encountering a peculiar issue with my TSF implementation on Windows 11. My custom IME generally works well with multiple input methods when implemented in a separate thread isolated from the main thread's message loop. Specifically:
The IME creates an invisible window running in a dedicated thread
Handles keyboard input capture through ::SetFocus
and AssociateFocus
when needed
Problem
- When using Microsoft Pinyin(During candidate selection phase), Pressing Shift to switch conversion mode to English;
- Results in complete loss of keyboard events (
WM_KEYUP/DOWN
)in the IME thread. - And
Shift
key stops toggling conversion mode.
Contrastingly, iFly IME:
Doesn't send conversion status changes to TSF/IMM. Shows no issues under identical test conditions.
Debug Findings:
After the deadlock occurs, AssociateFocus
with empty document will restores event flow, all blocked events flood in simultaneously.
Implementation Details
Full TextStoreAPC
, IElementSink
, ITfContextOwnerCompositionSink
interfaces implemented.
Key Questions
- What TSF internal state could block keyboard event propagation?
- How might document focus ownership affect this behavior?
- Recommended patterns to prevent event pipeline blockage?
Description
I'm encountering a peculiar issue with my TSF implementation on Windows 11. My custom IME generally works well with multiple input methods when implemented in a separate thread isolated from the main thread's message loop. Specifically:
The IME creates an invisible window running in a dedicated thread
Handles keyboard input capture through ::SetFocus
and AssociateFocus
when needed
Problem
- When using Microsoft Pinyin(During candidate selection phase), Pressing Shift to switch conversion mode to English;
- Results in complete loss of keyboard events (
WM_KEYUP/DOWN
)in the IME thread. - And
Shift
key stops toggling conversion mode.
Contrastingly, iFly IME:
Doesn't send conversion status changes to TSF/IMM. Shows no issues under identical test conditions.
Debug Findings:
After the deadlock occurs, AssociateFocus
with empty document will restores event flow, all blocked events flood in simultaneously.
Implementation Details
Full TextStoreAPC
, IElementSink
, ITfContextOwnerCompositionSink
interfaces implemented.
Key Questions
- What TSF internal state could block keyboard event propagation?
- How might document focus ownership affect this behavior?
- Recommended patterns to prevent event pipeline blockage?
1 Answer
Reset to default 0I've identified the root cause: the ITfMessagePump
interface is blocked. Previously, my message loop implementation was referenced from the Windows-classic-samples/winui/tsfpad
codebase. Through extensive debugging, I've confirmed this issue stems from an implementation flaw in the TSF ITfMessagePump
component.
Currently, my message loop:
bool done = false;
while (!done)
{
BOOL fResult = 0;
if (pMessagePump->PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE, &fResult) != S_OK)
{
done = true;
}
if (fResult != FALSE)
{
continue;
}
if (::GetMessageW(&msg, nullptr, 0, 0) <= 0)
{
break;
}
if (IsImeWantMessage(msg, pKeystrokeMgr)) // use ITfKeystrokeMgr test message is consumed by IME
{
continue;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
{
done = true;
}
if (done)
{
break;
}
}