From cf8fbc4d9d1c551f8be2d66d343693da9acdee27 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 14 Apr 2026 23:49:08 +0300 Subject: [PATCH] sokol: fix numpad arrow keys not returning correct values (fixes #15775) --- vlib/sokol/sapp/sapp_state_linux.v | 35 ++++++++++++++++++++++++++++ vlib/sokol/sapp/sapp_wayland_linux.v | 31 ++++-------------------- vlib/sokol/sapp/sapp_x11_linux.v | 24 +++++++++++++++---- 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/vlib/sokol/sapp/sapp_state_linux.v b/vlib/sokol/sapp/sapp_state_linux.v index 301506fd5..95de3761b 100644 --- a/vlib/sokol/sapp/sapp_state_linux.v +++ b/vlib/sokol/sapp/sapp_state_linux.v @@ -4,6 +4,41 @@ module sapp // Linux-specific state structs for the V sokol_app backend. // Shared state (SappTiming, SappMouse, etc.) is in sapp_state.v. +// X11 and XKB share keypad/navigation keysyms. Keep the stateful keypad mapping in one place so +// Num Lock can flip keypad arrows between navigation keys and keypad digits consistently. +fn linux_translate_navigation_or_keypad_keysym(keysym u32) KeyCode { + return match keysym { + 0xff63, 0xff9e { .insert } + 0xffff, 0xff9f { .delete } + 0xff50, 0xff95 { .home } + 0xff57, 0xff9c { .end } + 0xff55, 0xff9a { .page_up } + 0xff56, 0xff9b { .page_down } + 0xff51, 0xff96 { .left } + 0xff53, 0xff98 { .right } + 0xff52, 0xff97 { .up } + 0xff54, 0xff99 { .down } + 0xffb0 { .kp_0 } + 0xffb1 { .kp_1 } + 0xffb2 { .kp_2 } + 0xffb3 { .kp_3 } + 0xff9d, 0xffb5 { .kp_5 } + 0xffb4 { .kp_4 } + 0xffb6 { .kp_6 } + 0xffb7 { .kp_7 } + 0xffb8 { .kp_8 } + 0xffb9 { .kp_9 } + 0xffac, 0xffae { .kp_decimal } + 0xffaf { .kp_divide } + 0xffaa { .kp_multiply } + 0xffad { .kp_subtract } + 0xffab { .kp_add } + 0xff8d { .kp_enter } + 0xffbd { .kp_equal } + else { .invalid } + } +} + // Wayland-specific state (only compiled when -d sokol_wayland is used) $if sokol_wayland ? { struct SappWayland { diff --git a/vlib/sokol/sapp/sapp_wayland_linux.v b/vlib/sokol/sapp/sapp_wayland_linux.v index 8b6034ece..66a28c1bc 100644 --- a/vlib/sokol/sapp/sapp_wayland_linux.v +++ b/vlib/sokol/sapp/sapp_wayland_linux.v @@ -130,6 +130,10 @@ $if sokol_wayland ? { // === Key translation === fn wl_translate_key(keysym Xkb_keysym_t) KeyCode { + key := linux_translate_navigation_or_keypad_keysym(u32(keysym)) + if key != .invalid { + return key + } return match keysym { xkb_key_space { .space } xkb_key_apostrophe { .apostrophe } @@ -183,16 +187,6 @@ $if sokol_wayland ? { xkb_key_return { .enter } xkb_key_tab { .tab } xkb_key_backspace { .backspace } - xkb_key_insert { .insert } - xkb_key_delete { .delete } - xkb_key_right { .right } - xkb_key_left { .left } - xkb_key_down { .down } - xkb_key_up { .up } - xkb_key_page_up { .page_up } - xkb_key_page_down { .page_down } - xkb_key_home { .home } - xkb_key_end { .end } xkb_key_caps_lock { .caps_lock } xkb_key_scroll_lock { .scroll_lock } xkb_key_num_lock { .num_lock } @@ -223,23 +217,6 @@ $if sokol_wayland ? { xkb_key_f23 { .f23 } xkb_key_f24 { .f24 } xkb_key_f25 { .f25 } - xkb_key_kp_0 { .kp_0 } - xkb_key_kp_1 { .kp_1 } - xkb_key_kp_2 { .kp_2 } - xkb_key_kp_3 { .kp_3 } - xkb_key_kp_4 { .kp_4 } - xkb_key_kp_5 { .kp_5 } - xkb_key_kp_6 { .kp_6 } - xkb_key_kp_7 { .kp_7 } - xkb_key_kp_8 { .kp_8 } - xkb_key_kp_9 { .kp_9 } - xkb_key_kp_decimal { .kp_decimal } - xkb_key_kp_divide { .kp_divide } - xkb_key_kp_multiply { .kp_multiply } - xkb_key_kp_subtract { .kp_subtract } - xkb_key_kp_add { .kp_add } - xkb_key_kp_enter { .kp_enter } - xkb_key_kp_equal { .kp_equal } xkb_key_shift_l { .left_shift } xkb_key_control_l { .left_control } xkb_key_alt_l { .left_alt } diff --git a/vlib/sokol/sapp/sapp_x11_linux.v b/vlib/sokol/sapp/sapp_x11_linux.v index 3685c8459..8b4f59924 100644 --- a/vlib/sokol/sapp/sapp_x11_linux.v +++ b/vlib/sokol/sapp/sapp_x11_linux.v @@ -713,6 +713,22 @@ fn x11_translate_keysyms(keysyms &KeySym, width int) KeyCode { } } +fn x11_lookup_keysym(event &C.XEvent) KeySym { + mut keysym := KeySym(0) + unsafe { + C.XLookupString(&event.xkey, nil, 0, &keysym, nil) + } + return keysym +} + +fn x11_translate_event_key(scancode int, keysym KeySym) KeyCode { + key := linux_translate_navigation_or_keypad_keysym(u32(keysym)) + if key != .invalid { + return key + } + return x11_translate_key(scancode) +} + // XKB key name to keycode mapping entry struct X11KeymapEntry { mut: @@ -1637,7 +1653,8 @@ fn x11_on_focusout(event &C.XEvent) { fn x11_on_keypress(event &C.XEvent) { unsafe { keycode := int(event.xkey.keycode) - key := x11_translate_key(keycode) + keysym := x11_lookup_keysym(event) + key := x11_translate_event_key(keycode, keysym) repeat := x11_keypress_repeat(keycode) mut mods := x11_mods(event.xkey.state) // X11 doesn't set modifier bit on key down, so emulate that @@ -1645,8 +1662,6 @@ fn x11_on_keypress(event &C.XEvent) { if key != .invalid { x11_key_event(.key_down, key, repeat, mods) } - mut keysym := KeySym(0) - C.XLookupString(&event.xkey, nil, 0, &keysym, nil) chr := x11_keysym_to_unicode(keysym) if chr > 0 { x11_char_event(u32(chr), repeat, mods) @@ -1657,7 +1672,8 @@ fn x11_on_keypress(event &C.XEvent) { fn x11_on_keyrelease(event &C.XEvent) { unsafe { keycode := int(event.xkey.keycode) - key := x11_translate_key(keycode) + keysym := x11_lookup_keysym(event) + key := x11_translate_event_key(keycode, keysym) x11_keyrelease_repeat(keycode) if key != .invalid { mut mods := x11_mods(event.xkey.state) -- 2.39.5