11//! Keyboard-related types for smithay's input abstraction
22
3- use crate :: backend:: input:: KeyState ;
3+ use crate :: backend:: input:: { KeyEvent , KeyState } ;
4+ use crate :: input:: WeakSeat ;
45use crate :: utils:: { IsAlive , Serial , SERIAL_COUNTER } ;
6+ use calloop:: RegistrationToken ;
57use downcast_rs:: { impl_downcast, Downcast } ;
68use std:: collections:: HashSet ;
9+ use std:: time:: Duration ;
710#[ cfg( feature = "wayland_frontend" ) ]
811use std:: sync:: RwLock ;
912use std:: {
@@ -12,7 +15,7 @@ use std::{
1215 sync:: { Arc , Mutex } ,
1316} ;
1417use thiserror:: Error ;
15- use tracing:: { debug, error, info, info_span, instrument, trace} ;
18+ use tracing:: { debug, error, info, info_span, instrument, trace, warn } ;
1619
1720use xkbcommon:: xkb:: ffi:: XKB_STATE_LAYOUT_EFFECTIVE ;
1821pub use xkbcommon:: xkb:: { self , keysyms, Keycode , Keysym } ;
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,17 @@ pub(crate) struct KbdInternal<D: SeatHandler> {
215218 led_mapping : LedMapping ,
216219 pub ( crate ) led_state : LedState ,
217220 grab : GrabStatus < dyn KeyboardGrab < D > > ,
221+ /// Warning: the token cannot unregister itself when the object is dropped, because it can't hold a reference to the event loop. This object is Send, but the event loop is not.
222+ pub ( crate ) key_repeat_timer : Option < RegistrationToken > ,
223+ }
224+
225+ #[ cfg( feature = "wayland_frontend" ) ]
226+ impl < D : SeatHandler > Drop for KbdInternal < D > {
227+ fn drop ( & mut self ) {
228+ if self . key_repeat_timer . is_some ( ) {
229+ error ! ( "A keyboard was dropped without unregistering a repeat handler. This is a bug in smithay or in the compositor." ) ;
230+ }
231+ }
218232}
219233
220234// focus_hook does not implement debug, so we have to impl Debug manually
@@ -229,6 +243,7 @@ impl<D: SeatHandler> fmt::Debug for KbdInternal<D> {
229243 . field ( "xkb" , & self . xkb )
230244 . field ( "repeat_rate" , & self . repeat_rate )
231245 . field ( "repeat_delay" , & self . repeat_delay )
246+ . field ( "key_repeat_timer" , & self . key_repeat_timer )
232247 . finish ( )
233248 }
234249}
@@ -266,6 +281,7 @@ impl<D: SeatHandler + 'static> KbdInternal<D> {
266281 led_mapping,
267282 led_state,
268283 grab : GrabStatus :: None ,
284+ key_repeat_timer : None ,
269285 } )
270286 }
271287
@@ -602,10 +618,10 @@ pub trait KeyboardGrab<D: SeatHandler>: Downcast {
602618 data : & mut D ,
603619 handle : & mut KeyboardInnerHandle < ' _ , D > ,
604620 keycode : Keycode ,
605- state : KeyState ,
621+ event : KeyEvent ,
606622 modifiers : Option < ModifiersState > ,
607623 serial : Serial ,
608- time : u32 ,
624+ time_ms : u32 ,
609625 ) ;
610626
611627 /// A focus change was requested.
@@ -1016,10 +1032,74 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
10161032 keycode : Keycode ,
10171033 state : KeyState ,
10181034 serial : Serial ,
1019- time : u32 ,
1035+ time_ms : u32 ,
10201036 mods_changed : bool ,
10211037 ) {
10221038 let mut guard = self . arc . internal . lock ( ) . unwrap ( ) ;
1039+ if let Some ( token) = guard. key_repeat_timer . take ( ) {
1040+ // Releasing a key press obviously stops the repeat.
1041+ // But also, pressing another key stops the repeat of the previous key and starts it for the newly pressed key.
1042+ // TODO: this may had odd consequences when a modifier is pressed as the second key. But is that worth worrying about?
1043+ data. clear_timeout ( token) ;
1044+ } ;
1045+ match state {
1046+ KeyState :: Pressed => {
1047+ let seat = self . get_seat ( data) ;
1048+ let delay = guard. repeat_delay ;
1049+ let rate = guard. repeat_rate ;
1050+ let mut time_ms = time_ms;
1051+
1052+ fn issue_repeat < D : SeatHandler + ' static > ( data : & mut D , time_ms : u32 , kbd : & Arc < KbdRc < D > > , mods_changed : bool , weak_seat : & WeakSeat < D > , keycode : Keycode , serial : Serial ) {
1053+ let mut guard = kbd. internal . lock ( ) . unwrap ( ) ;
1054+ let modifiers = mods_changed. then_some ( guard. mods_state ) ;
1055+ let seat = weak_seat. upgrade ( ) . unwrap ( ) ;
1056+ guard. with_grab ( data, & seat, |data, handle, grab| {
1057+ grab. input ( data, handle, keycode, KeyEvent :: Repeated , modifiers, serial, time_ms) ;
1058+ } ) ;
1059+ if guard. focus . is_some ( ) {
1060+ trace ! ( "Input forwarded to client" ) ;
1061+ } else {
1062+ trace ! ( "No client currently focused" ) ;
1063+ }
1064+ }
1065+
1066+ // This closure-in-closure business is somewhat ugly.
1067+ // 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.
1068+ // 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.
1069+ let kbd = self . arc . clone ( ) ;
1070+ let weak_seat = seat. downgrade ( ) ;
1071+ guard. key_repeat_timer = Some ( data. set_timeout (
1072+ Duration :: from_millis ( delay as _ ) ,
1073+ move |data| {
1074+ time_ms += delay as u32 ;
1075+ issue_repeat ( data, time_ms, & kbd, mods_changed, & weak_seat, keycode, serial) ;
1076+ let mut guard = kbd. internal . lock ( ) . unwrap ( ) ;
1077+
1078+ match guard. key_repeat_timer {
1079+ // Can the repeat timer fire again if this handler is stalled before the cancel?
1080+ Some ( token) => data. clear_timeout ( token) ,
1081+ // This is a bug currently where all repeat cancelling is handled on key press/release. This might not be a bug in the future when other events can cancel key repeat.
1082+ None => warn ! ( "Key starts repeating but there is no delay timer. This might be a bug." ) ,
1083+ } ;
1084+
1085+ // This implementation doesn't take into account changes to the repeat rate after repeating begins.
1086+ let kbd = kbd. clone ( ) ;
1087+ let weak_seat = weak_seat. clone ( ) ;
1088+ guard. key_repeat_timer = Some ( data. set_timeout (
1089+ Duration :: from_millis ( rate as _ ) ,
1090+ move |data| {
1091+ time_ms += rate as u32 ;
1092+ issue_repeat ( data, time_ms, & kbd, mods_changed, & weak_seat, keycode, serial) ;
1093+ } ,
1094+ ) ) ;
1095+ } ,
1096+ ) ) ;
1097+ } ,
1098+ KeyState :: Released => {
1099+ // Nothing to do; timer is released for both in the common path.
1100+ }
1101+ }
1102+
10231103 match state {
10241104 KeyState :: Pressed => {
10251105 guard. forwarded_pressed_keys . insert ( keycode) ;
@@ -1028,12 +1108,14 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
10281108 guard. forwarded_pressed_keys . remove ( & keycode) ;
10291109 }
10301110 } ;
1111+
1112+ let event = state. into ( ) ;
10311113
10321114 // forward to client if no keybinding is triggered
10331115 let seat = self . get_seat ( data) ;
10341116 let modifiers = mods_changed. then_some ( guard. mods_state ) ;
10351117 guard. with_grab ( data, & seat, |data, handle, grab| {
1036- grab. input ( data, handle, keycode, state , modifiers, serial, time ) ;
1118+ grab. input ( data, handle, keycode, event , modifiers, serial, time_ms ) ;
10371119 } ) ;
10381120 if guard. focus . is_some ( ) {
10391121 trace ! ( "Input forwarded to client" ) ;
@@ -1151,6 +1233,11 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
11511233 continue ;
11521234 } ;
11531235 if kbd. version ( ) >= 4 {
1236+ let rate = if kbd. version ( ) >= 10 {
1237+ 0 // Enables compositor-side key repeat. See wl_keyboard key event
1238+ } else {
1239+ rate
1240+ } ;
11541241 kbd. repeat_info ( rate, delay) ;
11551242 }
11561243 }
@@ -1266,7 +1353,7 @@ impl<D: SeatHandler + 'static> KeyboardInnerHandle<'_, D> {
12661353 & mut self ,
12671354 data : & mut D ,
12681355 keycode : Keycode ,
1269- key_state : KeyState ,
1356+ key_state : KeyEvent ,
12701357 modifiers : Option < ModifiersState > ,
12711358 serial : Serial ,
12721359 time : u32 ,
@@ -1377,7 +1464,7 @@ impl<D: SeatHandler + 'static> KeyboardGrab<D> for DefaultGrab {
13771464 data : & mut D ,
13781465 handle : & mut KeyboardInnerHandle < ' _ , D > ,
13791466 keycode : Keycode ,
1380- state : KeyState ,
1467+ state : KeyEvent ,
13811468 modifiers : Option < ModifiersState > ,
13821469 serial : Serial ,
13831470 time : u32 ,
0 commit comments