keyboard/state: handle repeat rate 0, let widgets see Escape

- wl_keyboard.repeat_info with rate 0 means "no repeat"; we divided by it.
- an unknown keymap format hit unreachable!() instead of being ignored.
- raw keycode 1 (Escape) returned before widgets were dispatched, so the
  launcher's Escape handler (which saves the prompt for Ctrl+R) never ran.
  Dispatch first, then fall back to quitting.
- always lay out on the first layer-surface configure, even when the
  compositor hands us exactly the placeholder dimensions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Bendik Aagaard Lynghaug
2026-10-03 09:15:56 +00:00
co-authored by Claude Fable 5.1
parent 450a20bf63
commit 8c319cffc6
3 changed files with 29 additions and 12 deletions
+5 -2
View File
@@ -14,7 +14,7 @@
use std::{ use std::{
default::Default, default::Default,
os::unix::io::{AsRawFd, OwnedFd}, os::unix::io::OwnedFd,
}; };
use wayland_client::{protocol::wl_keyboard, WEnum}; use wayland_client::{protocol::wl_keyboard, WEnum};
@@ -31,6 +31,7 @@ pub use self::state::ModifiersState;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct KeyEvent { pub struct KeyEvent {
#[allow(dead_code)]
pub rawkey: u32, pub rawkey: u32,
pub keysym: u32, pub keysym: u32,
pub state: WEnum<wl_keyboard::KeyState>, pub state: WEnum<wl_keyboard::KeyState>,
@@ -77,7 +78,9 @@ impl Keyboard {
WEnum::Value(wl_keyboard::KeymapFormat::NoKeymap) => { WEnum::Value(wl_keyboard::KeymapFormat::NoKeymap) => {
// TODO: how to handle this (hopefully never occuring) case? // TODO: how to handle this (hopefully never occuring) case?
} }
_ => unreachable!(), // Unknown format from a newer protocol version: ignore rather than
// abort the whole process.
_ => (),
} }
} }
+7
View File
@@ -89,6 +89,12 @@ impl EventSource for KeyRepeatSource {
_ => (), _ => (),
}, },
RepeatMessage::RepeatInfo((new_rate, new_delay)) => { RepeatMessage::RepeatInfo((new_rate, new_delay)) => {
// Per wl_keyboard.repeat_info, a rate of 0 disables
// key repeat entirely. Dividing by it would panic.
if new_rate == 0 {
*disabled = true;
key.take();
} else {
*rate = Duration::from_micros(1_000_000 / new_rate as u64); *rate = Duration::from_micros(1_000_000 / new_rate as u64);
*delay = Duration::from_millis(new_delay as u64); *delay = Duration::from_millis(new_delay as u64);
*disabled = false; *disabled = false;
@@ -96,6 +102,7 @@ impl EventSource for KeyRepeatSource {
timer.set_deadline(now + *delay); timer.set_deadline(now + *delay);
} }
} }
}
}, },
channel::Event::Closed => { channel::Event::Closed => {
+12 -5
View File
@@ -461,12 +461,15 @@ impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
(width, height) = (640, 480); (width, height) = (640, 480);
} }
layer_surface.ack_configure(serial); layer_surface.ack_configure(serial);
let first_configure = !state.configured;
state.configured = true; state.configured = true;
state.dirty = true; state.dirty = true;
let dim = (width as i32, height as i32); let dim = (width as i32, height as i32);
if state.configured && state.dimensions == dim { // Always lay out on the first configure, even if the
// compositor happens to hand us our placeholder dimensions.
if !first_configure && state.dimensions == dim {
return; return;
} }
state.bufmgr.clear_buffers(); state.bufmgr.clear_buffers();
@@ -656,17 +659,21 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
state: kbstate, state: kbstate,
.. ..
} => { } => {
if key == 1 {
state.running = false;
return;
}
state.keyboard.resolve(); state.keyboard.resolve();
let k = state.keyboard.key(key, kbstate); let k = state.keyboard.key(key, kbstate);
let repeats = k.repeats; let repeats = k.repeats;
let ev = Event::KeyEvent(k); let ev = Event::KeyEvent(k);
// Widgets see the key first so the launcher gets to save its
// prompt on Escape (the early-return used to swallow it).
for widget in state.widgets.iter_mut() { for widget in state.widgets.iter_mut() {
widget.event(&ev); widget.event(&ev);
} }
// Raw keycode 1 is KEY_ESC: fall back to quitting even when no
// keymap could be loaded and no widget handled it.
if key == 1 && kbstate == WEnum::Value(wl_keyboard::KeyState::Pressed) {
state.running = false;
return;
}
if repeats { if repeats {
if let Event::KeyEvent(k) = ev { if let Event::KeyEvent(k) = ev {
state state