8000 fix(wayland): derive Key from the level-0 keysym by emoon · Pull Request #430 · emoon/rust_minifb · GitHub
[go: up one dir, main page]

Skip to content

fix(wayland): derive Key from the level-0 keysym - #430

Merged
emoon merged 1 commit into
masterfrom
wayland-level0-keysym
Aug 29, 2026
Merged

emoon merged 1 commit into
masterfrom
wayland-level0-keysym

Conversation

@emoon
@emoon emoon commented Aug 29, 2026
Copy link
Copy Markdown
Owner

Follow-up to #429.

The shifted-keysym table hardcodes US pairings. On a German layout Shift+2 is quotedbl, so the press sets Key::Apostrophe while the release after Shift is up arrives as 2 and clears Key::Key2, leaving Apostrophe held.

Takes Key from level 0 of the active layout instead, as x11.rs does with XLookupKeysym(&ev.key, 0), and drops the table. Character input keeps the state-resolved keysym.

Also fixes two others:

Tests drive handle_key through an embedded keymap fixture; the rollover and numpad cases fail on 7724f43.

Copilot AI left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The newly added Wayland XKB test fixture performs FFI calls without asserting non-null xkb_context_new/xkb_state_new results, which can lead to undefined behavior if allocation fails.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR fixes Wayland key handling by deriving Key from shift-level 0 of the active layout (matching the X11 approach) to avoid layout-specific shifted-keysym mismatches that can cause stuck keys, and it removes the now-unneeded shifted-keysym translation table. It also corrects Wayland set_key_repeat_rate forwarding and adds focused unit tests using an embedded XKB keymap fixture to cover rollover and numpad/NumLock cases.

Changes:

  • Compute Key from level-0 keysyms (shift-invariant) while keeping character input based on the state-resolved keysym.
  • Fix Window::set_key_repeat_rate in the Wayland backend to call set_key_repeat_rate (not set_key_repeat_delay).
  • Add unit tests that exercise shift rollover, layout-specific shifted symbols, numpad with NumLock, and undeclared keycodes.
File summaries
File Description
src/os/posix/xkb_keysyms.rs Removes shifted-keysym constants that are no longer needed after switching to level-0 mapping.
src/os/posix/xkb_ffi.rs Extends xkbcommon FFI to support querying keysyms by layout/level and detecting invalid layouts.
src/os/posix/wayland.rs Implements level-0 keysym resolution for Key, fixes repeat-rate forwarding, and adds XKB-fixture-driven tests.
src/key_handler.rs Annotates KeyHandler::update as intentionally unused in Wayland (Wayland uses the split phases directly).
Review details

Suppressed comments (1)

src/os/posix/wayland.rs:1485

  • In the test fixture, xkb_state_new can return null. If that happens, later FFI calls with self.state (and the Drop impl) can invoke libxkbcommon with a null pointer, which is UB; assert state is non-null after creation.
                assert!(!keymap.is_null(), "test keymap failed to compile");
                let state = ffi_dispatch!(XKBH, xkb_state_new, keymap);
                Keymap {
                    context,
                    keymap,
                    state,
                }
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/os/posix/wayland.rs
Comment on lines +1466 to +1478
let context = ffi_dispatch!(
XKBH,
xkb_context_new,
xkb_ffi::xkb_context_flags::XKB_CONTEXT_NO_FLAGS
);
let keymap = ffi_dispatch!(
XKBH,
xkb_keymap_new_from_string,
context,
text.as_ptr(),
xkb_ffi::xkb_keymap_format::XKB_KEYMAP_FORMAT_TEXT_V1,
xkb_ffi::xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS
);
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 7cd68a6 — asserts on context after xkb_context_new and on state after xkb_state_new, matching the existing keymap assert.

@emoon
emoon force-pushed the wayland-level0-keysym branch from fa00aec to 7cd68a6 Compare August 29, 2026 08:02
@emoon
emoon requested a balanced review from Copilot August 29, 2026 08:05
Copilot AI left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Layout-group rollover can still leave keys stuck, and level-0 lookup drops the keypad decimal key.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread src/os/posix/wayland.rs
keymap_state: *mut xkb_ffi::xkb_state,
key: u32,
) -> Option<u32> {
let layout = unsafe { ffi_dispatch!(XKBH, xkb_state_key_get_layout, keymap_state, key) };
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed against a real us,ru keymap — level 0 of group 0 is q, of group 1 is Cyrillic_shorti, so the release did resolve to a different Key.

Fixed in c4e80e2 by recording the Key each keycode resolved to on press and clearing that on release, rather than pinning the layout — pinning to group 0 would break users whose primary layout is non-Latin. Added group_change_while_held_leaves_no_key_held, with a second group in the fixture; it fails without the fix.

Comment thread src/os/posix/wayland.rs
}
}

if let Some(key_xkb) = Self::keysym_at_level_0(keymap, keymap_state, key) {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, and it was the only keypad key affected — I probed all 17 against a us keymap, and every other level-0 name (KP_Home, KP_End, KP_Divide, …) was already in the table. KPDL is the one whose level-0 is KP_Delete while the table only had KP_Decimal at level 1.

Fixed in c4e80e2: added the KP_Delete keysym mapped to Key::NumPadDot, plus <KPDL> in the fixture and a keypad_decimal_registers test that fails without it.

@emoon
emoon force-pushed the wayland-level0-keysym branch from 7cd68a6 to c4e80e2 Compare August 29, 2026 08:14
@emoon
emoon requested a balanced review from Copilot August 29, 2026 08:16
Copilot AI left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The central German Shift+2 mapping needs a direct regression assertion.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/os/posix/wayland.rs Outdated
Comment on lines +1644 to +1653
let mut unshifted = KeyHandler::new();
km.set_mods(0, 0);
km.press(&mut unshifted, AD01);

let mut shifted = KeyHandler::new();
km.set_mods(SHIFT, 0);
km.press(&mut shifted, AD01);

assert_eq!(unshifted.get_keys(), vec![Key::Q]);
assert_eq!(unshifted.get_keys(), shifted.get_keys());
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right — q/Q passes under the old table too, so that test wasn't discriminating. Fixed in 401ebde: it now runs both <AE02> (asserting Key::Key2 shifted and unshifted) and <AD01>.

Checked it by simulating #429's behaviour — active-level keysym plus the US shifted arms for these two keys — and the strengthened test fails where the old one passed.

That also surfaced something worth noting: with the press/release cache added for the group-rollover fix, shift_rollover_leaves_no_key_held now passes under the old mapping too, since the cache clears the release regardless. So this test is now the only one guarding the level-0 mapping itself. Good catch.

The shifted-keysym table from #429 hardcodes US pairings. On a German
layout Shift+2 is quotedbl, so the press sets Key::Apostrophe while the
release after Shift is up arrives as 2 and clears Key::Key2, leaving
Apostrophe held.

Take Key from level 0 of the active layout, as x11.rs does with
XLookupKeysym(&ev.key, 0). Character input keeps the state-resolved
keysym.

Level 0 alone is not enough: the compositor can switch layout group
while a key is held, resolving the release through a different group.
Record the Key each keycode resolved to on press and clear that on
release.

Also fixes the numpad with NumLock on, where the active keysym is
KP_1..KP_0 and was dropped; the keypad decimal key, whose level-0 name
is KP_Delete rather than KP_Decimal; and set_key_repeat_rate, which
forwarded to set_key_repeat_delay.

Tests drive handle_key through an embedded keymap fixture; each case
fails without its fix.
@emoon
emoon force-pushed the wayland-level0-keysym branch from c4e80e2 to 401ebde Compare August 29, 2026 08:21
@emoon
emoon requested a balanced review from Copilot August 29, 2026 08:22
Copilot AI left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The implementation addresses the reported regressions with consistent resource handling and focused test coverage.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@emoon
emoon merged commit 9b5c9c5 into master Aug 29, 2026
9 checks passed
@emoon
emoon deleted the wayland-level0-keysym branch August 29, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0