fix(input): keys are physical positions on every layout; Input.key_label names them

The Windows runtime keyed the held set by the character MapVirtualKeyA gave a
virtual key, so a game's WASD belonged to whatever the active layout put there,
and with an input method on every letter arrived as VK_PROCESSKEY. The typing
block is now read from the scancode (the arrows, numpad and F-keys still by
virtual key); macOS reads keyCode the same way. Input.key_label(key) names a key
in the player's own layout (Windows) or as its US character elsewhere.

Verified on Windows with SendInput into a live window: VK_Z carrying W's scancode
holds 'w', VK_PROCESSKEY carrying A's holds 'a', Caps Lock changes nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-15 23:26:53 +03:00
parent 2a2f463d5b
commit 619476ffed
14 changed files with 60552 additions and 60168 deletions

16
changes/physical-keys.md Normal file
View file

@ -0,0 +1,16 @@
bump: patch
type: fix
**Keys are physical positions on Windows and macOS, whatever the layout** - `Input.key_down('w')`
is the key above S on every keyboard.
- **Windows** keyed the held set by the character the active layout gave a virtual key, so
a game's WASD belonged to whatever the layout put there: on AZERTY W and A were other
keys, and with an input method on (Chinese, Japanese, Korean) every letter arrived as
VK_PROCESSKEY and no letter key worked at all. The typing block is now read from the
scancode; the arrows, the numpad and the F-keys still go by virtual key, and the frame
key (`Input.key`, typing) keeps the layout's character.
- **macOS** did the same through `charactersIgnoringModifiers`; it now reads `keyCode`.
- **`Input.key_label(key)`** names a key for the player in their own layout - `'w'` shows
as "W" on QWERTY and "Z" on AZERTY - so a game that shows its bindings never shows a
key the player cannot find. Windows reads the layout; headless, macOS and the browser
give the US character.