1
1
//! Keyboard-related types for smithay's input abstraction
2
2
3
- use crate :: backend:: input:: KeyState ;
3
+ use crate :: backend:: input:: { KeyEvent , KeyState } ;
4
+ use crate :: input:: WeakSeat ;
4
5
use crate :: utils:: { IsAlive , Serial , SERIAL_COUNTER } ;
6
+ use calloop:: RegistrationToken ;
5
7
use downcast_rs:: { impl_downcast, Downcast } ;
6
8
use std:: collections:: HashSet ;
9
+ use std:: time:: Duration ;
7
10
#[ cfg( feature = "wayland_frontend" ) ]
8
11
use std:: sync:: RwLock ;
9
12
use std:: {
@@ -12,7 +15,7 @@ use std::{
12
15
sync:: { Arc , Mutex } ,
13
16
} ;
14
17
use thiserror:: Error ;
15
- use tracing:: { debug, error, info, info_span, instrument, trace} ;
18
+ use tracing:: { debug, error, info, info_span, instrument, trace, warn } ;
16
19
17
20
use xkbcommon:: xkb:: ffi:: XKB_STATE_LAYOUT_EFFECTIVE ;
18
21
pub use xkbcommon:: xkb:: { self , keysyms, Keycode , Keysym } ;
47
50
seat : & Seat < D > ,
48
51
data : & mut D ,
49
52
key : KeysymHandle < ' _ > ,
50
- state : KeyState ,
53
+ state : KeyEvent ,
51
54
serial : Serial ,
52
55
time : u32 ,
53
56
) ;
@@ -215,6 +218,17 @@ pub(crate) struct KbdInternal<D: SeatHandler> {
215
218
led_mapping : LedMapping ,
216
219
pub ( crate ) led_state : LedState ,
217
220
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
+ }
218
232
}
219
233
220
234
// 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> {
229
243
. field ( "xkb" , & self . xkb )
230
244
. field ( "repeat_rate" , & self . repeat_rate )
231
245
. field ( "repeat_delay" , & self . repeat_delay )
246
+ . field ( "key_repeat_timer" , & self . key_repeat_timer )
232
247
. finish ( )
233
248
}
234
249
}
@@ -266,6 +281,7 @@ impl<D: SeatHandler + 'static> KbdInternal<D> {
266
281
led_mapping,
267
282
led_state,
268
283
grab : GrabStatus :: None ,
284
+ key_repeat_timer : None ,
269
285
} )
270
286
}
271
287
@@ -602,10 +618,10 @@ pub trait KeyboardGrab<D: SeatHandler>: Downcast {
602
618
data : & mut D ,
603
619
handle : & mut KeyboardInnerHandle < ' _ , D > ,
604
620
keycode : Keycode ,
605
- state : KeyState ,
621
+ event : KeyEvent ,
606
622
modifiers : Option < ModifiersState > ,
607
623
serial : Serial ,
608
- time : u32 ,
624
+ time_ms : u32 ,
609
625
) ;
610
626
611
627
/// A focus change was requested.
@@ -1016,10 +1032,74 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
1016
1032
keycode : Keycode ,
1017
1033
state : KeyState ,
1018
1034
serial : Serial ,
1019
- time : u32 ,
1035
+ time_ms : u32 ,
1020
1036
mods_changed : bool ,
1021
1037
) {
1022
1038
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
+
1023
1103
match state {
1024
1104
KeyState :: Pressed => {
1025
1105
guard. forwarded_pressed_keys . insert ( keycode) ;
@@ -1028,12 +1108,14 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
1028
1108
guard. forwarded_pressed_keys . remove ( & keycode) ;
1029
1109
}
1030
1110
} ;
1111
+
1112
+ let event = state. into ( ) ;
1031
1113
1032
1114
// forward to client if no keybinding is triggered
1033
1115
let seat = self . get_seat ( data) ;
1034
1116
let modifiers = mods_changed. then_some ( guard. mods_state ) ;
1035
1117
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 ) ;
1037
1119
} ) ;
1038
1120
if guard. focus . is_some ( ) {
1039
1121
trace ! ( "Input forwarded to client" ) ;
@@ -1151,6 +1233,11 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
1151
1233
continue ;
1152
1234
} ;
1153
1235
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
+ } ;
1154
1241
kbd. repeat_info ( rate, delay) ;
1155
1242
}
1156
1243
}
@@ -1266,7 +1353,7 @@ impl<D: SeatHandler + 'static> KeyboardInnerHandle<'_, D> {
1266
1353
& mut self ,
1267
1354
data : & mut D ,
1268
1355
keycode : Keycode ,
1269
- key_state : KeyState ,
1356
+ key_state : KeyEvent ,
1270
1357
modifiers : Option < ModifiersState > ,
1271
1358
serial : Serial ,
1272
1359
time : u32 ,
@@ -1377,7 +1464,7 @@ impl<D: SeatHandler + 'static> KeyboardGrab<D> for DefaultGrab {
1377
1464
data : & mut D ,
1378
1465
handle : & mut KeyboardInnerHandle < ' _ , D > ,
1379
1466
keycode : Keycode ,
1380
- state : KeyState ,
1467
+ state : KeyEvent ,
1381
1468
modifiers : Option < ModifiersState > ,
1382
1469
serial : Serial ,
1383
1470
time : u32 ,
0 commit comments