Skip to content

Commit 22bd9b0

Browse files
author
dcz
committed
Implement compositor-side key repeating
This implements KeyState::Repeat from wayland-protocols seat version 10.
1 parent f1e34c9 commit 22bd9b0

File tree

17 files changed

+517
-309
lines changed

17 files changed

+517
-309
lines changed

anvil/src/focus.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::borrow::Cow;
33
#[cfg(feature = "xwayland")]
44
use smithay::xwayland::X11Surface;
55
pub use smithay::{
6-
backend::input::KeyState,
6+
backend::input::KeyEvent,
77
desktop::{LayerSurface, PopupKind},
88
input::{
99
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
@@ -311,7 +311,7 @@ impl<BackendData: Backend> KeyboardTarget<AnvilState<BackendData>> for KeyboardF
311311
seat: &Seat<AnvilState<BackendData>>,
312312
data: &mut AnvilState<BackendData>,
313313
key: KeysymHandle<'_>,
314-
state: KeyState,
314+
state: KeyEvent,
315315
serial: Serial,
316316
time: u32,
317317
) {

anvil/src/input_handler.rs

Lines changed: 310 additions & 247 deletions
Large diffs are not rendered by default.

examples/minimal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ pub fn run_winit() -> Result<(), Box<dyn std::error::Error>> {
180180
keyboard.input::<(), _>(
181181
&mut state,
182182
event.key_code(),
183-
event.state(),
183+
event.state().into(),
184184
0.into(),
185185
0,
186186
|_, _, _| {

examples/seat.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
6262
keyboard.input(
6363
&mut state,
6464
smithay::backend::input::Keycode::from(9u32),
65-
smithay::backend::input::KeyState::Pressed,
65+
smithay::backend::input::KeyEvent::Pressed,
6666
0.into(),
6767
0,
6868
|_, _, _| {

smallvil/src/input.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl Smallvil {
2323
self.seat.get_keyboard().unwrap().input::<(), _>(
2424
self,
2525
event.key_code(),
26-
event.state(),
26+
event.state().into(),
2727
serial,
2828
time,
2929
|_, _, _| FilterResult::Forward,

src/backend/input/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,26 @@ pub enum KeyState {
9696
Pressed,
9797
}
9898

99+
/// Keyboard key event. Modelled on the wl_keyboard KeyState.
100+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
101+
pub enum KeyEvent {
102+
/// Key was released
103+
Released,
104+
/// Key was pressed
105+
Pressed,
106+
/// Key is being held and repetition was triggered.
107+
Repeated,
108+
}
109+
110+
impl From<KeyState> for KeyEvent {
111+
fn from(k: KeyState) -> Self {
112+
match k {
113+
KeyState::Released => Self::Released,
114+
KeyState::Pressed => Self::Pressed,
115+
}
116+
}
117+
}
118+
99119
/// Trait for keyboard event
100120
pub trait KeyboardKeyEvent<B: InputBackend>: Event<B> {
101121
/// Returns the numerical button code of the keyboard button.

src/desktop/wayland/popup/grab.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{
66
use wayland_server::{protocol::wl_surface::WlSurface, Resource};
77

88
use crate::{
9-
backend::input::{ButtonState, KeyState, Keycode},
9+
backend::input::{ButtonState, KeyEvent, Keycode},
1010
input::{
1111
keyboard::{
1212
GrabStartData as KeyboardGrabStartData, KeyboardGrab, KeyboardHandle, KeyboardInnerHandle,
@@ -434,7 +434,7 @@ where
434434
data: &mut D,
435435
handle: &mut KeyboardInnerHandle<'_, D>,
436436
keycode: Keycode,
437-
state: KeyState,
437+
state: KeyEvent,
438438
modifiers: Option<ModifiersState>,
439439
serial: Serial,
440440
time: u32,

src/input/keyboard/mod.rs

Lines changed: 142 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
//! Keyboard-related types for smithay's input abstraction
22
3-
use crate::backend::input::KeyState;
3+
use crate::backend::input::{Event, InputBackend, KeyEvent, KeyState, KeyboardKeyEvent};
4+
use crate::reexports::calloop::LoopHandle;
45
use crate::utils::{IsAlive, Serial, SERIAL_COUNTER};
6+
use calloop::RegistrationToken;
57
use downcast_rs::{impl_downcast, Downcast};
68
use std::collections::HashSet;
79
#[cfg(feature = "wayland_frontend")]
810
use std::sync::RwLock;
11+
use std::time::Duration;
912
use std::{
1013
default::Default,
1114
fmt, io,
1215
sync::{Arc, Mutex},
1316
};
1417
use thiserror::Error;
15-
use tracing::{debug, error, info, info_span, instrument, trace};
18+
use tracing::{debug, error, info, info_span, instrument, trace, warn};
1619

1720
use xkbcommon::xkb::ffi::XKB_STATE_LAYOUT_EFFECTIVE;
1821
pub use xkbcommon::xkb::{self, keysyms, Keycode, Keysym};
@@ -47,7 +50,7 @@ where
4750
seat: &Seat<D>,
4851
data: &mut D,
4952
key: KeysymHandle<'_>,
50-
state: KeyState,
53+
state: KeyEvent,
5154
serial: Serial,
5255
time: u32,
5356
);
@@ -215,6 +218,19 @@ pub(crate) struct KbdInternal<D: SeatHandler> {
215218
led_mapping: LedMapping,
216219
pub(crate) led_state: LedState,
217220
grab: GrabStatus<dyn KeyboardGrab<D>>,
221+
/// Holds the token to cancel key repeat.
222+
/// The token gets cleared when the keyboard is dropped, to neutralize the repeat callback.
223+
pub(crate) key_repeat_timer: Arc<Mutex<Option<RegistrationToken>>>,
224+
}
225+
226+
#[cfg(feature = "wayland_frontend")]
227+
impl<D: SeatHandler> Drop for KbdInternal<D> {
228+
fn drop(&mut self) {
229+
let timer = self.key_repeat_timer.lock().unwrap().take();
230+
if timer.is_some() {
231+
error!("A keyboard was dropped without unregistering a repeat handler. This is a bug in smithay or in the compositor.");
232+
}
233+
}
218234
}
219235

220236
// focus_hook does not implement debug, so we have to impl Debug manually
@@ -229,6 +245,7 @@ impl<D: SeatHandler> fmt::Debug for KbdInternal<D> {
229245
.field("xkb", &self.xkb)
230246
.field("repeat_rate", &self.repeat_rate)
231247
.field("repeat_delay", &self.repeat_delay)
248+
.field("key_repeat_timer", &self.key_repeat_timer)
232249
.finish()
233250
}
234251
}
@@ -266,21 +283,25 @@ impl<D: SeatHandler + 'static> KbdInternal<D> {
266283
led_mapping,
267284
led_state,
268285
grab: GrabStatus::None,
286+
key_repeat_timer: Arc::new(Mutex::new(None)),
269287
})
270288
}
271289

272290
// returns whether the modifiers or led state has changed
273-
fn key_input(&mut self, keycode: Keycode, state: KeyState) -> (bool, bool) {
291+
fn key_input(&mut self, keycode: Keycode, state: KeyEvent) -> (bool, bool) {
274292
// track pressed keys as xkbcommon does not seem to expose it :(
275293
let direction = match state {
276-
KeyState::Pressed => {
294+
KeyEvent::Pressed => {
277295
self.pressed_keys.insert(keycode);
278296
xkb::KeyDirection::Down
279297
}
280-
KeyState::Released => {
298+
KeyEvent::Released => {
281299
self.pressed_keys.remove(&keycode);
282300
xkb::KeyDirection::Up
283301
}
302+
KeyEvent::Repeated => {
303+
return (false, false);
304+
}
284305
};
285306

286307
// update state
@@ -602,10 +623,10 @@ pub trait KeyboardGrab<D: SeatHandler>: Downcast {
602623
data: &mut D,
603624
handle: &mut KeyboardInnerHandle<'_, D>,
604625
keycode: Keycode,
605-
state: KeyState,
626+
event: KeyEvent,
606627
modifiers: Option<ModifiersState>,
607628
serial: Serial,
608-
time: u32,
629+
time_ms: u32,
609630
);
610631

611632
/// A focus change was requested.
@@ -931,6 +952,106 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
931952
}
932953
}
933954

955+
/// Processes the keyboard event, starting or stopping key repeat.
956+
/// If this method is used, it must receive all keyboard events.
957+
/// The `on_event` argument will be called with all events: the ones received directly and the generated repeats.
958+
pub fn key_register_repeat<B: InputBackend>(
959+
&self,
960+
data: &mut D,
961+
get_handle: impl Fn(&D) -> &LoopHandle<'static, D> + 'static,
962+
event: B::KeyboardKeyEvent,
963+
// event, timeout, code.
964+
// This is Clone because there are two closures in here...
965+
on_event: impl Fn(&mut D, KeyEvent, u32, Keycode) + Clone + 'static,
966+
) {
967+
let time_ms = event.time_msec();
968+
let keycode = event.key_code();
969+
let state = event.state();
970+
971+
// Forward initial hardware event as logical event
972+
on_event(data, state.into(), time_ms, keycode);
973+
974+
// Unregister preexisting repeating
975+
// Releasing a key press obviously stops the repeat.
976+
// But also, pressing another key stops the repeat of the previous key and starts it for the newly pressed key.
977+
// TODO: this may had odd consequences when a modifier is pressed as the second key. But is that worth worrying about?
978+
self.key_stop_repeat(data, &get_handle);
979+
980+
// Register repeating
981+
match event.state() {
982+
KeyState::Pressed => {
983+
let mut guard = self.arc.internal.lock().unwrap();
984+
let delay = guard.repeat_delay;
985+
let rate = guard.repeat_rate;
986+
let mut time_ms = time_ms;
987+
988+
// This closure-in-closure business is somewhat ugly.
989+
// The reason is that there are two timers needed: first, the delay timer, and after the delay, the repeat timer. Both of them receive different tokens for cancelling, so we have to swap the token after the delay.
990+
// The only comparable alternative I can think of is to wrap the key_repeat_timer in an Mutex<Arc<>> and change the token when delay turns into repeat. But locks are worse than nesting.
991+
let kbd = self.arc.clone();
992+
let duration = Duration::from_millis(delay as _);
993+
let handle = get_handle(data);
994+
let token = handle.insert_source(
995+
calloop::timer::Timer::from_duration(duration),
996+
move |_, _, data| {
997+
time_ms += delay as u32;
998+
on_event(data, KeyEvent::Repeated, time_ms, keycode);
999+
let mut guard = kbd.internal.lock().unwrap();
1000+
1001+
let handle = get_handle(data);
1002+
{
1003+
let timer = guard.key_repeat_timer.lock().unwrap();
1004+
match *timer {
1005+
Some(token) => handle.remove(token),
1006+
None => debug!("Key starts repeating but there is no delay timer. Was repeat already cancelled?"),
1007+
};
1008+
}
1009+
1010+
// This implementation doesn't take into account changes to the repeat rate after repeating begins.
1011+
let kbd = kbd.clone();
1012+
let on_event = on_event.clone();
1013+
let duration = Duration::from_millis(rate as _);
1014+
let token = handle.insert_source(
1015+
calloop::timer::Timer::from_duration(duration),
1016+
move |_, _, data| {
1017+
time_ms += rate as u32;
1018+
let guard = kbd.internal.lock().unwrap();
1019+
let timer = guard.key_repeat_timer.lock().unwrap();
1020+
1021+
// If the timer has been orphaned by dropping the keyboard, don't actually send the event, don't register a repeat.
1022+
if timer.is_some() {
1023+
drop(timer);
1024+
drop(guard);
1025+
on_event(data, KeyEvent::Repeated, time_ms, keycode);
1026+
calloop::timer::TimeoutAction::ToDuration(duration)
1027+
} else {
1028+
debug!("Cancelling an orphaned keyboard repeat.");
1029+
calloop::timer::TimeoutAction::Drop
1030+
}
1031+
},
1032+
).unwrap();
1033+
guard.key_repeat_timer = Arc::new(Mutex::new(Some(token)));
1034+
calloop::timer::TimeoutAction::Drop
1035+
}
1036+
).unwrap();
1037+
guard.key_repeat_timer = Arc::new(Mutex::new(Some(token)));
1038+
}
1039+
KeyState::Released => {
1040+
// Nothing to do; timer is released for both in the common path.
1041+
}
1042+
}
1043+
}
1044+
1045+
/// Cancels any ongoing key repeat
1046+
pub fn key_stop_repeat(&self, data: &mut D, get_handle: impl Fn(&D) -> &LoopHandle<'static, D>) {
1047+
let guard = self.arc.internal.lock().unwrap();
1048+
let mut timer = guard.key_repeat_timer.lock().unwrap();
1049+
if let Some(token) = timer.take() {
1050+
let handle = get_handle(data);
1051+
handle.remove(token);
1052+
};
1053+
}
1054+
9341055
/// Handle a keystroke
9351056
///
9361057
/// All keystrokes from the input backend should be fed _in order_ to this method of the
@@ -949,7 +1070,7 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
9491070
&self,
9501071
data: &mut D,
9511072
keycode: Keycode,
952-
state: KeyState,
1073+
state: KeyEvent,
9531074
serial: Serial,
9541075
time: u32,
9551076
filter: F,
@@ -979,13 +1100,13 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
9791100
&self,
9801101
data: &mut D,
9811102
keycode: Keycode,
982-
state: KeyState,
1103+
state: KeyEvent,
9831104
filter: F,
9841105
) -> (T, bool)
9851106
where
9861107
F: FnOnce(&mut D, &ModifiersState, KeysymHandle<'_>) -> T,
9871108
{
988-
trace!("Handling keystroke");
1109+
trace!("Handling key event");
9891110

9901111
let mut guard = self.arc.internal.lock().unwrap();
9911112
let (mods_changed, leds_changed) = guard.key_input(keycode, state);
@@ -1014,26 +1135,18 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
10141135
&self,
10151136
data: &mut D,
10161137
keycode: Keycode,
1017-
state: KeyState,
1138+
event: KeyEvent,
10181139
serial: Serial,
1019-
time: u32,
1140+
time_ms: u32,
10201141
mods_changed: bool,
10211142
) {
10221143
let mut guard = self.arc.internal.lock().unwrap();
1023-
match state {
1024-
KeyState::Pressed => {
1025-
guard.forwarded_pressed_keys.insert(keycode);
1026-
}
1027-
KeyState::Released => {
1028-
guard.forwarded_pressed_keys.remove(&keycode);
1029-
}
1030-
};
10311144

10321145
// forward to client if no keybinding is triggered
10331146
let seat = self.get_seat(data);
10341147
let modifiers = mods_changed.then_some(guard.mods_state);
10351148
guard.with_grab(data, &seat, |data, handle, grab| {
1036-
grab.input(data, handle, keycode, state, modifiers, serial, time);
1149+
grab.input(data, handle, keycode, event, modifiers, serial, time_ms);
10371150
});
10381151
if guard.focus.is_some() {
10391152
trace!("Input forwarded to client");
@@ -1151,6 +1264,11 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
11511264
continue;
11521265
};
11531266
if kbd.version() >= 4 {
1267+
let rate = if kbd.version() >= 10 {
1268+
0 // Enables compositor-side key repeat. See wl_keyboard key event
1269+
} else {
1270+
rate
1271+
};
11541272
kbd.repeat_info(rate, delay);
11551273
}
11561274
}
@@ -1266,7 +1384,7 @@ impl<D: SeatHandler + 'static> KeyboardInnerHandle<'_, D> {
12661384
&mut self,
12671385
data: &mut D,
12681386
keycode: Keycode,
1269-
key_state: KeyState,
1387+
key_state: KeyEvent,
12701388
modifiers: Option<ModifiersState>,
12711389
serial: Serial,
12721390
time: u32,
@@ -1377,7 +1495,7 @@ impl<D: SeatHandler + 'static> KeyboardGrab<D> for DefaultGrab {
13771495
data: &mut D,
13781496
handle: &mut KeyboardInnerHandle<'_, D>,
13791497
keycode: Keycode,
1380-
state: KeyState,
1498+
state: KeyEvent,
13811499
modifiers: Option<ModifiersState>,
13821500
serial: Serial,
13831501
time: u32,

0 commit comments

Comments
 (0)