fix: respect xkb keysym remaps for editing keys - #15
Conversation
GDK delivers (keyval, keycode) pairs where the keyval may have been remapped via xkb (e.g. Caps Lock to BackSpace) while the keycode still identifies the original physical key. libghostty's input handling is keycode-driven, so the original physical key wins and the remap is silently dropped. Translate the keyval to the canonical evdev+8 keycode for known editing keys before handing the event to libghostty, and clear the Lock-derived CAPS modifier when the keycode is rewritten so the remap source does not leak its lock state into the synthesized event. Repro: bind Caps Lock to BackSpace in KDE; in Seance, Caps does nothing even though wev reports `sym: BackSpace`. With this patch, Caps acts as Backspace as expected.
|
This also resolves the reported case in #3 (filed for This patch is essentially fix (a) proposed in #3 — for a small set of named editing/navigation keys, translate The broader fix (b) in #3 — build an Note this is orthogonal to #6: that PR fixes the printable-text / IME path ( Two confirmed reporters now via XKB-level remaps (this and #3), so it is not a one-off config. |
Why I'm filing this
I use the Colemak keyboard layout and have Caps Lock remapped to Backspace at the xkb level — this is a very common ergonomic setup (Caps Lock is unused real estate, Backspace gets used constantly, the remap puts it under a home-row finger). Every other app on my system honours the remap. In Seance the remapped key does nothing, which makes the terminal effectively unusable for me without reaching across the keyboard for the real Backspace key.
This patch makes Seance honour the remap.
Summary
xkb-level keysym remaps (e.g. KDE's Caps Lock behaves as Backspace) are silently dropped inside Seance. The remapped key sends nothing to the terminal even though
wevconfirms the Wayland compositor delivers the remapped keysym.Root cause
GDK delivers a
(keyval, hardware_keycode)pair where the keyval reflects the xkb remap but the hardware keycode still identifies the original physical key.handleKeyEventinsrc/pane.zigforwards the raw keycode toghostty_surface_key. libghostty's input handling is keycode-driven (ghostty/src/apprt/embedded.ziglooks up the physical key ininput/keycodes.zigbyentry.native == keycode), so it sees the original physical key and ignores the remap.For Caps Lock to Backspace on Linux: GDK reports
keyval = BackSpace,keycode = 66(Caps physical). libghostty sees keycode 66, identifies it as Caps Lock, and treats the event as a modifier press rather than producing Backspace input.Fix
canonicalKeycode(keyval, keycode)returns the Linux evdev+8 keycode that natively produces the given keyval for a small set of named editing/navigation keys.handleKeyEventuses the canonical keycode when it differs and stripsGHOSTTY_MODS_CAPSin that case so the remap source's Lock state doesn't leak into the event.Repro
wevconfirmssym: BackSpace, utf8: '\b'for the Caps press.Notes / questions for review
gdk_display_map_keyvalwould query GDK for keycodes that produce a given keyval and avoid the hardcoded table. I went with the table because it allocates nothing on a hot input path, the editing-key set is small and stable on Linux, and Seance is already Linux-only perbuild.zig. Open to switching if you'd prefer.Test plan
zig buildsucceeds