Winit: Cannot extract original character when receiving a Ctrl character.

Created on 9 Sep 2020  路  7Comments  路  Source: rust-windowing/winit

When I use a keyboard layout with keys that are not from basic latin, and I press a non-basic-latin letter in conjunction with Ctrl the following happens:

  • The VirtualKeyCode seems to be the character at the same location from the US layout.
  • The ReceivedCharacter is sometimes identical to the VirtualKeyCode but it's sometimes an ASCII control character.

This happens on both Linux with X11 and on Windows. Actually, on Windows the ReceivedCharacter isn't even sent for some combinations.

The issue is that it seems the application has no way of telling what was the original key pressed. So for example if I'm using a Hungarian layout and I press Ctrl+ I get a '\u{1c}' in ReceivedCharacter and my applications has no idea that was ever pressed. This may not be relevant for text input but it's relevant for shortcuts.

Most helpful comment

On Windows, you can use MapVirtualKeyW to map a scancode to a VK_* value, but you'd have to convert that to winit's VirtualKeyCode on your own, since the function that maps between VK_* and VirtualKeyCode isn't part of the public api. I don't know what the situation is like on any of the other platforms.

Implementing something like this directly in winit itself has been briefly mentioned, but that seems to have been intended for "display purposes".

Honestly, if you're expecting winit to have some sort of good solution for keyboard shortcuts then you're SOL, because all the options have some major downsides.

  • ReceivedCharacter is very layout-dependent, and doesn't mesh well with modifiers. Using character input for shortcuts is generally a bad idea.
  • VirtualKeyCode is also layout-dependent. VirtualKeyCode is probably what you want, but there's no built-in way to go from VirtualKeyCode to "what's (probably) printed on the key-cap" based on the current layout so you can tell the user where they should look. Some layouts also shift the virtual key-codes around in unpredictable ways, so the lack of "VirtualKeyCode-to-what's-on-the-keycap" hurts even more.
  • scancodes are layout-independent, but they are platform-dependent. They're also reported in a less-than ideal way at the moment, as evidenced by #1679.

I don't really expect this situation to change much unless we can get some momentum behind a solution for #753.

All 7 comments

This sounds like you want to look at the VirtualKeyCode or scancode of the button press?

I don't see how VirtualKeyCode would help me figuring out that was pressed. The ScanCode probably could help but I don't know of any way to transform the scancode into the appropriate character with winint. Do you @chrisduerr?

On Windows, you can use MapVirtualKeyW to map a scancode to a VK_* value, but you'd have to convert that to winit's VirtualKeyCode on your own, since the function that maps between VK_* and VirtualKeyCode isn't part of the public api. I don't know what the situation is like on any of the other platforms.

Implementing something like this directly in winit itself has been briefly mentioned, but that seems to have been intended for "display purposes".

Honestly, if you're expecting winit to have some sort of good solution for keyboard shortcuts then you're SOL, because all the options have some major downsides.

  • ReceivedCharacter is very layout-dependent, and doesn't mesh well with modifiers. Using character input for shortcuts is generally a bad idea.
  • VirtualKeyCode is also layout-dependent. VirtualKeyCode is probably what you want, but there's no built-in way to go from VirtualKeyCode to "what's (probably) printed on the key-cap" based on the current layout so you can tell the user where they should look. Some layouts also shift the virtual key-codes around in unpredictable ways, so the lack of "VirtualKeyCode-to-what's-on-the-keycap" hurts even more.
  • scancodes are layout-independent, but they are platform-dependent. They're also reported in a less-than ideal way at the moment, as evidenced by #1679.

I don't really expect this situation to change much unless we can get some momentum behind a solution for #753.

Thank you for the in-depth description!

I'm wondering how do other applications handle keyboard shortcuts with let's say Russian or Arabic keyboard layouts. When listing the available keyboard shortcuts, what do applications show on the GUI to the user with such layouts? Do they display the "virtual key" or do they display the layout dependent character?

If it's the virtual key than this really is not an issue - or more like an issue that already has a widely accepted workaround.

I don't really expect this situation to change much unless we can get some momentum behind a solution for #753.

I do expect the keyboard handling situation to get better, but that won't fix this problem. The biggest problem right now is just with consistency, one platform does it one way and another platform does it differently. Even on the same platform you run into issues where suddenly DeviceEvent has a VirtualKeyCode but WindowEvent doesn't.

Generally what winit does right now with offering all of scancode/received_char/VirtualKeyCode is relatively similar to what the browser does and it's a decent solution.

I'm wondering how do other applications handle keyboard shortcuts with let's say Russian or Arabic keyboard layouts.

Not a lot of applications have keyboard shortcuts and even fewer of those have the necessity that users type in the names of those shortcuts manually. If you set them by having the user press the button, it's becomes relatively trivial.

Portable shortcuts are not a trivial problem, and not just for Rust / winit.

Qt has some notes on this, in particular:

  • Ctrl + + actually maps to Ctrl + Shift + = on a British keyboard, but Ctrl + + (on a different key) on a Norwegian keyboard
  • Macs often use the Command key and in general different platforms have different standard shortcuts
  • Qt's key enum is considerably larger than VirtualKeyCode including, for example, Qt::Key_Adiaeresis (盲), though I think not 'U with double acute' (疟).

Thus, Qt provides a library of platform-specific common shortcuts. Of course this doesn't solve everything.

Even on the same platform you run into issues where suddenly DeviceEvent has a VirtualKeyCode but WindowEvent doesn't.

Yep. I've been trying to untangle "Alt Graph" on the Windows backend, as well as trying to figure out how to deal with "Pause/Break" and "NumLock" being weird. I'll submit a PR when the code is in a state I'm somewhat comfortable with.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ryanisaacg picture ryanisaacg  路  3Comments

chemicstry picture chemicstry  路  3Comments

francesca64 picture francesca64  路  5Comments

mistodon picture mistodon  路  4Comments

alexheretic picture alexheretic  路  4Comments