TerminalInput::HandleKey should never return "unhandled" for a key event #21031

Open
opened 2026-01-31 07:31:09 +00:00 by claunia · 0 comments
Owner

Originally created by @j4james on GitHub (Dec 31, 2023).

Description of the new feature/enhancement

If I've enabled VT input mode, I expect to get back a simple stream of characters representing the VT sequences for each key press. If using ReadConsoleInput, then I'd expect a single key event for each character in the sequence, with no virtual key code, and with the character values in the UnicodeChar field.

However, what I get now is a weird mix of the original keyboard events, interspersed with the VT sequence characters. For example, if I press Ctrl+A, I expect to get a single event like this:

bKeyDown wVirtualKeyCode UnicodeChar
DOWN 0x00 U+0001

But what I actually get is this:

bKeyDown wVirtualKeyCode UnicodeChar
DOWN VK_CONTROL U+0000
DOWN 0x00 U+0001
UP VK_A U+0001
UP VK_CONTROL U+0000

If I enter a character consisting of a surrogate pair, e.g. entering 😛 from the Win+. emoji picker, I get both up and down events for the two surrogate pairs, but the up event arrives before the down event for the first code point!

bKeyDown wVirtualKeyCode UnicodeChar
UP VK_OEM_PERIOD U+002E
UP 0x00 U+D83D
DOWN 0x00 U+D83D
DOWN 0x00 U+DE1B
UP 0x00 U+DE1B

And note that I also get the up event for the . key from triggering the emoji picker. All I expected to see were the two down events representing the emoji glyph:

bKeyDown wVirtualKeyCode UnicodeChar
DOWN 0x00 U+D83D
DOWN 0x00 U+DE1B

This all stems from the fact that we return an "unhandled" state from the TerminalInput::HandleKey method for key-up events, as well as key-down events that don't map to a VT sequence, and those events then get injected back into the input queue. I think it would be better if we just returned an empty string for those cases. That way the only key events that end up in the queue are the actual VT characters.

Proposed technical implementation details (optional)

As explained above, we should only return MakeUnhandled() if we receive something that isn't a KEY_EVENT. Otherwise we should return a blank string, i.e. MakeOutput({}), for any key events that aren't handled.

Originally created by @j4james on GitHub (Dec 31, 2023). # Description of the new feature/enhancement If I've enabled VT input mode, I expect to get back a simple stream of characters representing the VT sequences for each key press. If using `ReadConsoleInput`, then I'd expect a single key event for each character in the sequence, with no virtual key code, and with the character values in the `UnicodeChar` field. However, what I get now is a weird mix of the original keyboard events, interspersed with the VT sequence characters. For example, if I press <kbd>Ctrl</kbd>+<kbd>A</kbd>, I expect to get a single event like this: | bKeyDown | wVirtualKeyCode | UnicodeChar | |----------|-----------------|-------------| | DOWN | 0x00 | U+0001 | But what I actually get is this: | bKeyDown | wVirtualKeyCode | UnicodeChar | |----------|-----------------|-------------| | DOWN | VK_CONTROL | U+0000 | | DOWN | 0x00 | U+0001 | | UP | VK_A | U+0001 | | UP | VK_CONTROL | U+0000 | If I enter a character consisting of a surrogate pair, e.g. entering 😛 from the <kbd>Win</kbd>+<kbd>.</kbd> emoji picker, I get both up and down events for the two surrogate pairs, but the up event arrives _before_ the down event for the first code point! | bKeyDown | wVirtualKeyCode | UnicodeChar | |----------|-----------------|-------------| | UP | VK_OEM_PERIOD | U+002E | | UP | 0x00 | U+D83D | | DOWN | 0x00 | U+D83D | | DOWN | 0x00 | U+DE1B | | UP | 0x00 | U+DE1B | And note that I also get the up event for the <kbd>.</kbd> key from triggering the emoji picker. All I expected to see were the two down events representing the emoji glyph: | bKeyDown | wVirtualKeyCode | UnicodeChar | |----------|-----------------|-------------| | DOWN | 0x00 | U+D83D | | DOWN | 0x00 | U+DE1B | This all stems from the fact that we return an "unhandled" state from the `TerminalInput::HandleKey` method for key-up events, as well as key-down events that don't map to a VT sequence, and those events then get injected back into the input queue. I think it would be better if we just returned an empty string for those cases. That way the only key events that end up in the queue are the actual VT characters. # Proposed technical implementation details (optional) As explained above, we should only return `MakeUnhandled()` if we receive something that isn't a `KEY_EVENT`. Otherwise we should return a blank string, i.e. `MakeOutput({})`, for any key events that aren't handled.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#21031