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 ;
45use crate :: utils:: { IsAlive , Serial , SERIAL_COUNTER } ;
6+ use calloop:: RegistrationToken ;
57use downcast_rs:: { impl_downcast, Downcast } ;
68use std:: collections:: HashSet ;
79#[ cfg( feature = "wayland_frontend" ) ]
810use std:: sync:: RwLock ;
11+ use std:: time:: Duration ;
912use std:: {
1013 default:: Default ,
1114 fmt, io,
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,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