atagen

monolith

public
Star0
Watch0

Commit ec80bfaf4c68

tarball

atagen <boss@atagen.co>2026-10-19 07:54 UTC

1 file changed+45-11
nested: release keys when the host keyboard focus leaves

The host stops sending key releases once another window has focus, so a modifier held while alt-tabbing out stayed pressed in monolith. The host also lists keys already down on enter, which now seeds the held modifiers.
Modified file: crates/monolith/src/nested/input.rs+45 additions−11 deletions
@@ -89,17 +89,51 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
8989 _: &Connection,
9090 _: &QueueHandle<Self>,
9191 ) {
92- if let wl_keyboard::Event::Key {
93- key,
94- state: WEnum::Value(pressed),
95- ..
96- } = event
97- {
98- let pressed = match pressed {
99- wl_keyboard::KeyState::Pressed => KeyState::Pressed,
100- _ => KeyState::Released,
101- };
102- state.key(Keycode::new(key + 8), pressed, InputTime::now());
92+ match event {
93+ wl_keyboard::Event::Key {
94+ key,
95+ state: WEnum::Value(pressed),
96+ ..
97+ } => {
98+ let pressed = match pressed {
99+ wl_keyboard::KeyState::Pressed => KeyState::Pressed,
100+ _ => KeyState::Released,
101+ };
102+ state.key(Keycode::new(key + 8), pressed, InputTime::now());
103+ }
104+ wl_keyboard::Event::Enter { keys, .. } => {
105+ for key in keys
106+ .as_chunks::<4>()
107+ .0
108+ .iter()
109+ .map(|k| u32::from_ne_bytes(*k))
110+ .filter(|k| MODIFIER_KEYS.contains(k))
111+ {
112+ let code = Keycode::new(key + 8);
113+ if !state.pressed_keys().contains(&code) {
114+ state.key(code, KeyState::Pressed, InputTime::now());
115+ }
116+ }
117+ }
118+ wl_keyboard::Event::Leave { .. } => {
119+ for code in state.pressed_keys() {
120+ state.key(code, KeyState::Released, InputTime::now());
121+ }
122+ }
123+ _ => {}
103124 }
104125 }
105126 }
127+
128+/// Evdev codes of the control, shift, alt and logo keys, left then right.
129+const MODIFIER_KEYS: [u32; 8] = [29, 97, 42, 54, 56, 100, 125, 126];
130+
131+impl State {
132+ fn pressed_keys(&self) -> std::collections::HashSet<Keycode> {
133+ self.input
134+ .seat
135+ .get_keyboard()
136+ .map(|k| k.pressed_keys())
137+ .unwrap_or_default()
138+ }
139+}