linebender / linebender/druid

Hotkey mapping on non-Latin keyboard layouts

Open
#1,069 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

discussion
Dominant language
Rust
Stars
9.7k
Forks
565
PR merge metrics
No merged PRs in 30d

Description

This issue is a spinoff of #1040; the main scope of that was delivering key events. The implementation PR (#1049) does a reasonably good job with non-QWERTY Latin layouts, but does not handle non-Latin well, so that's what this issue is about. This analysis is largely based on Windows but similar issues exist across the platforms.

After a bit of research of existing application behavior, I found that when a non-Latin keyboard layout is selected, hotkeys (Ctrl-Z and friends on Windows) map ASCII keys (I think in the US layout, but see below). However, the current code does not do this - it queries [VkScanKey](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscanw) to find which [virtual-key](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes) corresponds to the codepoint for "Z", and that function returns -1 indicating error. Thus, the hotkey binding is dropped.

What is the correct behavior? Since [ACCEL](https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-accel) is based on virtual-key codes, I suspect what happens is equivalent to having a fallback mapping when VkScanKey fails, choosing 0x5A (b'Z') to represent the mapping of "Z". If this is the case, there are two problems:

* First, virtual-key codes are really only well defined for A-Z and 0-9. Others (period, comma, etc) are reasonably stable, while others (VK_OEM_[1-9], corresponding to virgule, octothorpe, brackets, and other ASCII symbols) tend to move around a lot. For example, I have no idea how you'd map a Ctrl-"#" shortcut, which would be Ctrl-Shift 0x33 in a US layout but Ctrl VK_OEM_2 in a DE QWERTZ layout.

* Second, if virtual-key codes are the source of truth for such mappings, then with our current types we've lost the ability for event dispatching to interpret the key the same as hotkey bindings, as we currently throw the vk on the floor (after perhaps using it to derive a Key value). The Web keyboard event has a "legacy" [keyCode](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) which in my testing on Windows seems to match the virtual-key code, which we might consider restoring. (I'll also note that keyCode is not stable across platforms, for example "#" in a German QWERTZ layout has value VK_OEM_2 on Windows but VK_OEM_5 on macOS, though the non-legacy codes are consistent: `Key::Character("#")` and `Code::Backslash`)

A second possibility is to use "code" rather than vk as the source of truth, and fall back to symbol positions in a US layout when the primary mapping fails. In this approach, when there is no key corresponding to "#", then the fallback is to find the key with `Code::Digit3` and turn on the shift modifier. Basically, we'd have our own ASCII-to-code map based on a US layout, then on Windows use [MapVirtualKeyEx](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeyexw) with MAPVK_VSC_TO_VK to map the code back to a vk, and use the resulting vk in the ACCEL structure.

I am currently leaning towards the second approach, as it is based on more robustly standardized codes, and I see more clearly how to make it consistent across platforms. The main downside is that in edge cases it may not match the behavior of native Windows applications.

I'd love feedback from people who regularly use non-Latin layouts. Figuring out the right thing to do here probably mostly involves experimenting with a bunch of apps, and doesn't require any deep knowledge of Druid internals.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing implementation PR #1049 and the current hotkey and keyboard-event handling it introduced. Compare the VkScanKey/ACCEL approach with the Code and MapVirtualKeyEx alternative across non-Latin layouts and platforms. Done means choosing and implementing a consistent mapping that preserves matching hotkey and event interpretation.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.