Console/ConPTY key event mismatch #471

Closed
opened 2026-01-30 21:53:08 +00:00 by claunia · 5 comments
Owner

Originally created by @parkovski on GitHub (Dec 7, 2018).

Originally assigned to: @zadjii-msft on GitHub.

When running neovim under tmux, pressing Alt-(anything) inserts a doubled key - for example, Alt-a sends ^[aa or <M-a>a. This is due to some (flawed) libuv logic here. However, I don't remember this happening before, and noticed that the key events generated under the regular console and through tmux's ConPTY are different and in a different order - see the screen shot below.

  • Your Windows build number: 18290

  • What you're doing and what's happening: (Copy & paste specific commands and their output, or include screen shots)
    The left side shows the events generated by pressing Alt-a under tmux. Release order doesn't matter; key up events are generated immediately. The right side shows pressing Alt-a under a regular console. Here, release order matters, but whether I release 'Alt' first (shown here), or 'a' first (the key up will have no UnicodeChar value), it satisfies libuv's logic.

console

  • What's wrong / what should be happening instead:
    TBH, the doubled char is a bug in libuv, but if the event messages could be made consistent it'd help avoid this kind of scenario, especially if it is in fact a change from previous behavior.
Originally created by @parkovski on GitHub (Dec 7, 2018). Originally assigned to: @zadjii-msft on GitHub. When running neovim under tmux, pressing Alt-(anything) inserts a doubled key - for example, Alt-a sends `^[aa` or `<M-a>a`. This is due to some (flawed) libuv logic [here](https://github.com/libuv/libuv/blob/f4feea331a54e2b1a1cd432e04ea83d32cfd6c5c/src/win/tty.c#L736). However, I don't remember this happening before, and noticed that the key events generated under the regular console and through tmux's ConPTY are different and in a different order - see the screen shot below. * Your Windows build number: 18290 * What you're doing and what's happening: (Copy & paste specific commands and their output, or include screen shots) The left side shows the events generated by pressing Alt-a under tmux. Release order doesn't matter; key up events are generated immediately. The right side shows pressing Alt-a under a regular console. Here, release order matters, but whether I release 'Alt' first (shown here), or 'a' first (the key up will have no UnicodeChar value), it satisfies libuv's logic. ![console](https://user-images.githubusercontent.com/1094150/49669156-c02d7400-fa1d-11e8-8a73-33f27676f8eb.png) * What's wrong / what should be happening instead: TBH, the doubled char is a bug in libuv, but if the event messages could be made consistent it'd help avoid this kind of scenario, especially if it is in fact a change from previous behavior.
Author
Owner

@zadjii-msft commented on GitHub (Dec 11, 2018):

I'm not totally sure I can fix this. With VT, we can't encode input with the same fidelity as we can with INPUT_RECORDs. In VT, the only thing that's sent during a Alt+a keypress is ^[a. That doesn't give us any information on what order the keys were pressed.

When we receive that through conpty, we have to translate that somehow into INPUT_RECORDs. I made the call while building this that the most correct way of translating that would be to convey a [(modifier down)*, key down, key up, (modifier up)*] sequence. There could also be multiple modifiers, so ^[^a would be [alt down, ctrl down, a down, a up, ctrl up, alt up] sequence.

@zadjii-msft commented on GitHub (Dec 11, 2018): I'm not totally sure I can fix this. With VT, we can't encode input with the same fidelity as we can with `INPUT_RECORD`s. In VT, the only thing that's sent during a <kbd>Alt</kbd>+<kbd>a</kbd> keypress is `^[a`. That doesn't give us any information on what order the keys were pressed. When we receive that through conpty, we have to translate that somehow into `INPUT_RECORD`s. I made the call while building this that the most correct way of translating that would be to convey a [(modifier down)\*, key down, key up, (modifier up)\*] sequence. There could also be multiple modifiers, so `^[^a` would be [alt down, ctrl down, a down, a up, ctrl up, alt up] sequence.
Author
Owner

@parkovski commented on GitHub (Dec 11, 2018):

I think the new behavior is correct, it's actually the non-PTY version that's a little odd. If you press Alt down, A down, A up, Alt up, the "A up" event will have its UnicodeChar value set to 0. Libuv seemed to assume this will always be the case, and the seemingly more correct way broke it. I opened an issue with them though, because it really is their bug that a key up generates a key down message.

@parkovski commented on GitHub (Dec 11, 2018): I think the new behavior is correct, it's actually the non-PTY version that's a little odd. If you press Alt down, A down, A up, Alt up, the "A up" event will have its UnicodeChar value set to 0. Libuv seemed to assume this will always be the case, and the seemingly more correct way broke it. I opened an issue with them though, because it really is their bug that a key up generates a key down message.
Author
Owner

@refack commented on GitHub (Dec 12, 2018):

@zadjii-msft thank you for the explanation (and for the great work)!

I have two follow up questions:

  1. For testing purposes, do you have a way to generate these events programmatically?

  2. Could you confirm my understanding that an end-of-unicode-sequence will always be

    KeyEvent.bKeyDown == 0 &&
    KeyEvent.wVirtualKeyCode == VK_MENU &&
    KeyEvent.uChar.UnicodeChar != 0
    

    (especially KeyEvent.wVirtualKeyCode == VK_MENU)?

@refack commented on GitHub (Dec 12, 2018): @zadjii-msft thank you for the explanation (and for the great work)! I have two follow up questions: 1. For testing purposes, do you have a way to generate these events programmatically? 2. Could you confirm my understanding that an end-of-unicode-sequence will always be ``` KeyEvent.bKeyDown == 0 && KeyEvent.wVirtualKeyCode == VK_MENU && KeyEvent.uChar.UnicodeChar != 0 ``` (especially `KeyEvent.wVirtualKeyCode == VK_MENU`)?
Author
Owner

@parkovski commented on GitHub (Dec 12, 2018):

I think I can answer the first question at least. For a regular console, AFAIK, you'll need to use GetConsoleWindow and SendMessage/WM_KEYDOWN/WM_KEYUP. Here the events are slightly different if you release alt first or the other key first. For a ConPTY, you can just write VT to it and read console events from the other end.

@parkovski commented on GitHub (Dec 12, 2018): I think I can answer the first question at least. For a regular console, AFAIK, you'll need to use `GetConsoleWindow` and `SendMessage`/`WM_KEYDOWN`/`WM_KEYUP`. Here the events are slightly different if you release alt first or the other key first. For a ConPTY, you can just write VT to it and read console events from the other end.
Author
Owner

@DHowett commented on GitHub (Aug 13, 2020):

On account of it looks like the new behavior is "more correct", and we haven't heard any more complaints about this I'm tentatively closing this bug out.

Thanks everyone for playing 😄

@DHowett commented on GitHub (Aug 13, 2020): On account of it looks like the new behavior is "more correct", and we haven't heard any more complaints about this I'm tentatively closing this bug out. Thanks everyone for playing :smile:
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#471