Ilya Zakharevich
Ilya Zakharevich

Reputation: 1419

The switch of keyboard layout on Windows: synchronization with the multistage-processing of character input

I’m thinking about what would be “the most robust way” to handle the user switching the keyboard layout. And more I think about it, the more I’m confused about the synchronization of WM_INPUTLANGCHANGE with other parts of keyboard input processing.

Indeed, there are several stages a keyboard event passes through from the moment of pressing the key to it being digested by the application. If my understanding is correct, first it is processed by the keyboard driver, and the corresponding message is put into the system queue. My conjecture is that the translation scancode→virtual␣code happens on this stage — but it depends on the keyboard-layout. So some of the messages in the queue may be processed with one layout, some with another.

Second, the message pump extracts these messages from the system queue, and (often) squeezes them through TranslateMessage — which in turn uses ToUnicodeEx. This translation also depends on the current layout — but since it happens much later, “the layout might have a chance to be changed” between these two stages. So again, some of the messages are processed with one layout, some with the other — but the boundary may be at a different position in the queue than the boundary of the preceding paragraph.

Finally, the messages are posted-to/consumed in the window procedures — which may in turn call functions im/explicitly depending on the current keyboard layout. — And this happens at the different-again moment of time, so I may think that this may involve a third place separating events processed with the previous-vs.-current keyboard layouts!

Finally, the message WM_INPUTLANGCHANGE. is asynchronous — it is sent to the window procedure. So the time it arrives is “a fourth boundary" which (“theoretically”) should not have any particular relation to three preceding boundaries.

I’m at a loss about how to resolve which of these complications do arise and which do not. Is there any logic in the message processing decreasing the complexity, so “some of these possible complications” do not actually arise?

Upvotes: 0

Views: 29

Answers (1)

Ilya Zakharevich
Ilya Zakharevich

Reputation: 1419

Only a very limited solution so far — it is only for the last complication — that LANGUAGECHANGE message arrives as sent, so out-of-order.

The workaround: RegisterWindowMessage("PostedLanguageChange"); this makes a custom message. Then post it to yourselves when a LANGUAGECHANGE message arrives (as sent!). This way:

  • It is put after the keyboard messages which are already in the message queue, and before the future keyboard messages.
  • It can be processed in the message pump — where keyboard input processing belongs.

Remark: if the message pump does non-trivial processing of KEYUP/DOWN messages, then it seems that a similar thing should be done with “Focus Change” messages (at least those changing the processing thread¹⁾) — so the pump may know that the flow of these messages may have been interrupted by unknown events.

¹⁾ This is a very flaky solution²⁾: the keyboard input has a state (stored in the kernel), but this state is not localized per thread. It is stored in the keyboard driver, so is shared between all the windows with the same keyboard layout. See this comment of mine for the “obnoxious” reality of Windows’ keyboard input…

²⁾ I cannot see any way to improve this. At least, when the message pump maintains a certain state, this allows updating this state consistently. (Fortunately, there seems to be no way for windows in the same thread to have different input languages!)

Upvotes: 0

Related Questions