Skip to content

fix(wayland): handle the wl_keyboard v10 repeated key state instead of aborting - #1774

Open
nikicat wants to merge 1 commit into
raphamorim:mainfrom
nikicat:fix/wayland-key-repeat
Open

fix(wayland): handle the wl_keyboard v10 repeated key state instead of aborting#1774
nikicat wants to merge 1 commit into
raphamorim:mainfrom
nikicat:fix/wayland-key-repeat

Conversation

@nikicat

@nikicat nikicat commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Problem

wl_keyboard v10 lets the compositor take over key repeat. It signals this by sending repeat_info { rate: 0 } (disabling client-side repeat), then delivers held keys as key { state: repeated } — a third key_state value added in that version.

The Wayland keyboard dispatch matches only Pressed and Released:

WlKeyboardEvent::Key { key, state: WEnum::Value(WlKeyState::Pressed), .. } => { ... }
WlKeyboardEvent::Key { key, state: WEnum::Value(WlKeyState::Released), .. } => { ... }
...
_ => unreachable!(),

so anything else aborts the process. That arm is reachable from compositor-supplied data in two ways — the new Repeated state, and any WEnum::Unknown state — which makes it a panic on untrusted input rather than an invariant.

Impact

main is not affected today: sctk 0.19 caps the wl_seat bind at v7, so no compositor will send repeated. It becomes a hard crash the moment rio-window moves to sctk 0.20, which binds wl_seat up to v10.

I hit it on a fork carrying that bump, on mutter 50.3 (advertises wl_seat v10). Holding any key killed the terminal:

thread 'main' panicked at rio-window/src/platform_impl/linux/wayland/seat/keyboard/mod.rs:305:18:
internal error: entered unreachable code

Fix

  • Handle WlKeyState::Repeated as a repeat key press. No repeat-timer bookkeeping is needed: per the protocol the compositor only sends it after repeat_info { rate: 0 }, so client-side repeat is already disabled and the two paths are mutually exclusive.
  • Downgrade the remaining catch-all — and its twin on the keymap format — from unreachable!() to warn!, so unknown protocol values degrade instead of aborting.

Verification

Rebuilt with the sctk 0.20 bump on mutter 50.3 and held a key via ydotool with WAYLAND_DEBUG=1:

--- key events (key, state) ---
      2 105 1)
    104 105 2)
RESULT: ALIVE
--- panics: 0 ---

104 state: repeated events delivered, key repeat works, process survives. Before the change the first one aborted. Also cargo check -p rio-window on this branch's base (sctk 0.19) — clean.

🤖 Generated with Claude Code

`wl_keyboard` v10 lets the compositor take over key repeat: it sends
`repeat_info { rate: 0 }` to disable client side repeat, then delivers
held keys as `key { state: repeated }`. The dispatch only matched
`Pressed` and `Released`, so every other value fell into
`_ => unreachable!()` and aborted the process.

That arm is reachable from compositor supplied data in two ways — the
new `Repeated` state, and any `WEnum::Unknown` state — so it is a panic
on untrusted input rather than an invariant. Handle `Repeated` as a
repeat key press (the compositor only sends it once client side repeat
is off, so there is no repeat timer to keep in sync) and downgrade the
remaining catch-all, plus its twin on the keymap format, to a warning.

Reproduced on mutter 50.3, which advertises `wl_seat` v10: holding any
key aborted the terminal with "internal error: entered unreachable
code". Needs sctk >= 0.20 to trigger, since 0.19 caps the `wl_seat` bind
at v7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant