smithay_client_toolkit/seat/keyboard/
mod.rs

1use std::{
2    convert::TryInto,
3    env,
4    fmt::Debug,
5    marker::PhantomData,
6    num::NonZeroU32,
7    sync::{
8        atomic::{AtomicBool, Ordering},
9        Arc, Mutex,
10    },
11    time::Duration,
12};
13
14#[doc(inline)]
15pub use xkeysym::{KeyCode, Keysym};
16
17#[cfg(feature = "calloop")]
18use calloop::timer::{TimeoutAction, Timer};
19use wayland_client::{
20    protocol::{wl_keyboard, wl_seat, wl_surface},
21    Connection, Dispatch, Proxy, QueueHandle, WEnum,
22};
23
24use xkbcommon::xkb;
25
26#[cfg(feature = "calloop")]
27use repeat::{RepeatData, RepeatedKey};
28
29use super::{Capability, SeatError, SeatHandler, SeatState};
30
31#[cfg(feature = "calloop")]
32pub mod repeat;
33
34/// Error when creating a keyboard.
35#[must_use]
36#[derive(Debug, thiserror::Error)]
37pub enum KeyboardError {
38    /// Seat error.
39    #[error(transparent)]
40    Seat(#[from] SeatError),
41
42    /// The specified keymap (RMLVO) is not valid.
43    #[error("invalid keymap was specified")]
44    InvalidKeymap,
45}
46
47impl SeatState {
48    /// Creates a keyboard from a seat.
49    ///
50    /// This keyboard implementation uses libxkbcommon for the keymap.
51    ///
52    /// Typically the compositor will provide a keymap, but you may specify your own keymap using the `rmlvo`
53    /// field.
54    ///
55    /// ## Errors
56    ///
57    /// This will return [`SeatError::UnsupportedCapability`] if the seat does not support a keyboard.
58    pub fn get_keyboard<D, T: 'static>(
59        &mut self,
60        qh: &QueueHandle<D>,
61        seat: &wl_seat::WlSeat,
62        rmlvo: Option<RMLVO>,
63    ) -> Result<wl_keyboard::WlKeyboard, KeyboardError>
64    where
65        D: Dispatch<wl_keyboard::WlKeyboard, KeyboardData<T>>
66            + SeatHandler
67            + KeyboardHandler
68            + 'static,
69    {
70        let udata = match rmlvo {
71            Some(rmlvo) => KeyboardData::from_rmlvo(seat.clone(), rmlvo)?,
72            None => KeyboardData::new(seat.clone()),
73        };
74
75        self.get_keyboard_with_data(qh, seat, udata)
76    }
77
78    /// Creates a keyboard from a seat.
79    ///
80    /// This keyboard implementation uses libxkbcommon for the keymap.
81    ///
82    /// Typically the compositor will provide a keymap, but you may specify your own keymap using the `rmlvo`
83    /// field.
84    ///
85    /// ## Errors
86    ///
87    /// This will return [`SeatError::UnsupportedCapability`] if the seat does not support a keyboard.
88    pub fn get_keyboard_with_data<D, U>(
89        &mut self,
90        qh: &QueueHandle<D>,
91        seat: &wl_seat::WlSeat,
92        udata: U,
93    ) -> Result<wl_keyboard::WlKeyboard, KeyboardError>
94    where
95        D: Dispatch<wl_keyboard::WlKeyboard, U> + SeatHandler + KeyboardHandler + 'static,
96        U: KeyboardDataExt + 'static,
97    {
98        let inner =
99            self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?;
100
101        if !inner.data.has_keyboard.load(Ordering::SeqCst) {
102            return Err(SeatError::UnsupportedCapability(Capability::Keyboard).into());
103        }
104
105        Ok(seat.get_keyboard(qh, udata))
106    }
107}
108
109/// Wrapper around a libxkbcommon keymap
110#[allow(missing_debug_implementations)]
111pub struct Keymap<'a>(&'a xkb::Keymap);
112
113impl<'a> Keymap<'a> {
114    /// Get keymap as string in text format. The keymap should always be valid.
115    pub fn as_string(&self) -> String {
116        self.0.get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1)
117    }
118}
119
120/// Handler trait for keyboard input.
121///
122/// The functions defined in this trait are called as keyboard events are received from the compositor.
123pub trait KeyboardHandler: Sized {
124    /// The keyboard has entered a surface.
125    ///
126    /// When called, you may assume the specified surface has keyboard focus.
127    ///
128    /// When a keyboard enters a surface, the `raw` and `keysym` fields indicate which keys are currently
129    /// pressed.
130    #[allow(clippy::too_many_arguments)]
131    fn enter(
132        &mut self,
133        conn: &Connection,
134        qh: &QueueHandle<Self>,
135        keyboard: &wl_keyboard::WlKeyboard,
136        surface: &wl_surface::WlSurface,
137        serial: u32,
138        raw: &[u32],
139        keysyms: &[Keysym],
140    );
141
142    /// The keyboard has left a surface.
143    ///
144    /// When called, keyboard focus leaves the specified surface.
145    ///
146    /// All currently held down keys are released when this event occurs.
147    fn leave(
148        &mut self,
149        conn: &Connection,
150        qh: &QueueHandle<Self>,
151        keyboard: &wl_keyboard::WlKeyboard,
152        surface: &wl_surface::WlSurface,
153        serial: u32,
154    );
155
156    /// A key has been pressed on the keyboard.
157    ///
158    /// The key will repeat if there is no other press event afterwards or the key is released.
159    fn press_key(
160        &mut self,
161        conn: &Connection,
162        qh: &QueueHandle<Self>,
163        keyboard: &wl_keyboard::WlKeyboard,
164        serial: u32,
165        event: KeyEvent,
166    );
167
168    /// A key has been released.
169    ///
170    /// This stops the key from being repeated if the key is the last key which was pressed.
171    fn release_key(
172        &mut self,
173        conn: &Connection,
174        qh: &QueueHandle<Self>,
175        keyboard: &wl_keyboard::WlKeyboard,
176        serial: u32,
177        event: KeyEvent,
178    );
179
180    /// Keyboard modifiers have been updated.
181    ///
182    /// This happens when one of the modifier keys, such as "Shift", "Control" or "Alt" is pressed or
183    /// released.
184    fn update_modifiers(
185        &mut self,
186        conn: &Connection,
187        qh: &QueueHandle<Self>,
188        keyboard: &wl_keyboard::WlKeyboard,
189        serial: u32,
190        modifiers: Modifiers,
191        layout: u32,
192    );
193
194    /// The keyboard has updated the rate and delay between repeating key inputs.
195    ///
196    /// This function does nothing by default but is provided if a repeat mechanism outside of calloop is\
197    /// used.
198    fn update_repeat_info(
199        &mut self,
200        _conn: &Connection,
201        _qh: &QueueHandle<Self>,
202        _keyboard: &wl_keyboard::WlKeyboard,
203        _info: RepeatInfo,
204    ) {
205    }
206
207    /// Keyboard keymap has been updated.
208    ///
209    /// `keymap.as_string()` can be used get the keymap as a string. It cannot be exposed directly
210    /// as an `xkbcommon::xkb::Keymap` due to the fact xkbcommon uses non-thread-safe reference
211    /// counting. But can be used to create an independent `Keymap`.
212    ///
213    /// This is called after the default handler for keymap changes and does nothing by default.
214    fn update_keymap(
215        &mut self,
216        _conn: &Connection,
217        _qh: &QueueHandle<Self>,
218        _keyboard: &wl_keyboard::WlKeyboard,
219        _keymap: Keymap<'_>,
220    ) {
221    }
222}
223
224/// The rate at which a pressed key is repeated.
225#[derive(Debug, Clone, Copy)]
226pub enum RepeatInfo {
227    /// Keys will be repeated at the specified rate and delay.
228    Repeat {
229        /// The number of repetitions per second that should occur.
230        rate: NonZeroU32,
231
232        /// Delay (in milliseconds) between a key press and the start of repetition.
233        delay: u32,
234    },
235
236    /// Keys should not be repeated.
237    Disable,
238}
239
240/// Data associated with a key press or release event.
241#[derive(Debug, Clone)]
242pub struct KeyEvent {
243    /// Time at which the keypress occurred.
244    pub time: u32,
245
246    /// The raw value of the key.
247    pub raw_code: u32,
248
249    /// The interpreted symbol of the key.
250    ///
251    /// This corresponds to one of the assoiated values on the [`Keysym`] type.
252    pub keysym: Keysym,
253
254    /// UTF-8 interpretation of the entered text.
255    ///
256    /// This will always be [`None`] on release events.
257    pub utf8: Option<String>,
258}
259
260/// The state of keyboard modifiers
261///
262/// Each field of this indicates whether a specified modifier is active.
263///
264/// Depending on the modifier, the modifier key may currently be pressed or toggled.
265#[derive(Debug, Clone, Copy, Default)]
266pub struct Modifiers {
267    /// The "control" key
268    pub ctrl: bool,
269
270    /// The "alt" key
271    pub alt: bool,
272
273    /// The "shift" key
274    pub shift: bool,
275
276    /// The "Caps lock" key
277    pub caps_lock: bool,
278
279    /// The "logo" key
280    ///
281    /// Also known as the "windows" or "super" key on a keyboard.
282    #[doc(alias = "windows")]
283    #[doc(alias = "super")]
284    pub logo: bool,
285
286    /// The "Num lock" key
287    pub num_lock: bool,
288}
289
290/// The RMLVO description of a keymap
291///
292/// All fields are optional, and the system default
293/// will be used if set to `None`.
294#[derive(Debug)]
295#[allow(clippy::upper_case_acronyms)]
296pub struct RMLVO {
297    /// The rules file to use
298    pub rules: Option<String>,
299
300    /// The keyboard model by which to interpret keycodes and LEDs
301    pub model: Option<String>,
302
303    /// A comma separated list of layouts (languages) to include in the keymap
304    pub layout: Option<String>,
305
306    /// A comma separated list of variants, one per layout, which may modify or
307    /// augment the respective layout in various ways
308    pub variant: Option<String>,
309
310    /// A comma separated list of options, through which the user specifies
311    /// non-layout related preferences, like which key combinations are
312    /// used for switching layouts, or which key is the Compose key.
313    pub options: Option<String>,
314}
315
316pub struct KeyboardData<T> {
317    seat: wl_seat::WlSeat,
318    first_event: AtomicBool,
319    xkb_context: Mutex<xkb::Context>,
320    /// If the user manually specified the RMLVO to use.
321    user_specified_rmlvo: bool,
322    xkb_state: Mutex<Option<xkb::State>>,
323    xkb_compose: Mutex<Option<xkb::compose::State>>,
324    #[cfg(feature = "calloop")]
325    repeat_data: Arc<Mutex<Option<RepeatData<T>>>>,
326    focus: Mutex<Option<wl_surface::WlSurface>>,
327    _phantom_data: PhantomData<T>,
328}
329
330impl<T> Debug for KeyboardData<T> {
331    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332        f.debug_struct("KeyboardData").finish_non_exhaustive()
333    }
334}
335
336#[macro_export]
337macro_rules! delegate_keyboard {
338    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
339        $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
340            [
341                $crate::reexports::client::protocol::wl_keyboard::WlKeyboard: $crate::seat::keyboard::KeyboardData<$ty>
342            ] => $crate::seat::SeatState
343        );
344    };
345    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, keyboard: [$($udata:ty),* $(,)?]) => {
346        $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
347            [
348                $(
349                    $crate::reexports::client::protocol::wl_keyboard::WlKeyboard: $udata,
350                )*
351            ] => $crate::seat::SeatState
352        );
353    };
354}
355
356// SAFETY: The state does not share state with any other rust types.
357unsafe impl<T> Send for KeyboardData<T> {}
358// SAFETY: The state is guarded by a mutex since libxkbcommon has no internal synchronization.
359unsafe impl<T> Sync for KeyboardData<T> {}
360
361impl<T> KeyboardData<T> {
362    pub fn new(seat: wl_seat::WlSeat) -> Self {
363        let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
364        let udata = KeyboardData {
365            seat,
366            first_event: AtomicBool::new(false),
367            xkb_context: Mutex::new(xkb_context),
368            xkb_state: Mutex::new(None),
369            user_specified_rmlvo: false,
370            xkb_compose: Mutex::new(None),
371            #[cfg(feature = "calloop")]
372            repeat_data: Arc::new(Mutex::new(None)),
373            focus: Mutex::new(None),
374            _phantom_data: PhantomData,
375        };
376
377        udata.init_compose();
378
379        udata
380    }
381
382    pub fn seat(&self) -> &wl_seat::WlSeat {
383        &self.seat
384    }
385
386    pub fn from_rmlvo(seat: wl_seat::WlSeat, rmlvo: RMLVO) -> Result<Self, KeyboardError> {
387        let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
388        let keymap = xkb::Keymap::new_from_names(
389            &xkb_context,
390            &rmlvo.rules.unwrap_or_default(),
391            &rmlvo.model.unwrap_or_default(),
392            &rmlvo.layout.unwrap_or_default(),
393            &rmlvo.variant.unwrap_or_default(),
394            rmlvo.options,
395            xkb::COMPILE_NO_FLAGS,
396        );
397
398        if keymap.is_none() {
399            return Err(KeyboardError::InvalidKeymap);
400        }
401
402        let xkb_state = Some(xkb::State::new(&keymap.unwrap()));
403
404        let udata = KeyboardData {
405            seat,
406            first_event: AtomicBool::new(false),
407            xkb_context: Mutex::new(xkb_context),
408            xkb_state: Mutex::new(xkb_state),
409            user_specified_rmlvo: true,
410            xkb_compose: Mutex::new(None),
411            #[cfg(feature = "calloop")]
412            repeat_data: Arc::new(Mutex::new(None)),
413            focus: Mutex::new(None),
414            _phantom_data: PhantomData,
415        };
416
417        udata.init_compose();
418
419        Ok(udata)
420    }
421
422    fn init_compose(&self) {
423        let xkb_context = self.xkb_context.lock().unwrap();
424
425        if let Some(locale) = env::var_os("LC_ALL")
426            .and_then(|v| if v.is_empty() { None } else { Some(v) })
427            .or_else(|| env::var_os("LC_CTYPE"))
428            .and_then(|v| if v.is_empty() { None } else { Some(v) })
429            .or_else(|| env::var_os("LANG"))
430            .and_then(|v| if v.is_empty() { None } else { Some(v) })
431            .unwrap_or_else(|| "C".into())
432            .to_str()
433        {
434            // TODO: Pending new release of xkbcommon to use new_from_locale with OsStr
435            if let Ok(table) = xkb::compose::Table::new_from_locale(
436                &xkb_context,
437                locale.as_ref(),
438                xkb::compose::COMPILE_NO_FLAGS,
439            ) {
440                let compose_state =
441                    xkb::compose::State::new(&table, xkb::compose::COMPILE_NO_FLAGS);
442                *self.xkb_compose.lock().unwrap() = Some(compose_state);
443            }
444        }
445    }
446
447    fn update_modifiers(&self) -> Modifiers {
448        let guard = self.xkb_state.lock().unwrap();
449        let state = guard.as_ref().unwrap();
450
451        Modifiers {
452            ctrl: state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE),
453            alt: state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE),
454            shift: state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE),
455            caps_lock: state.mod_name_is_active(xkb::MOD_NAME_CAPS, xkb::STATE_MODS_EFFECTIVE),
456            logo: state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE),
457            num_lock: state.mod_name_is_active(xkb::MOD_NAME_NUM, xkb::STATE_MODS_EFFECTIVE),
458        }
459    }
460}
461
462pub trait KeyboardDataExt: Send + Sync {
463    type State: 'static;
464    fn keyboard_data(&self) -> &KeyboardData<Self::State>;
465    fn keyboard_data_mut(&mut self) -> &mut KeyboardData<Self::State>;
466}
467
468impl<T: 'static> KeyboardDataExt for KeyboardData<T> {
469    /// The type of the user defined state
470    type State = T;
471    fn keyboard_data(&self) -> &KeyboardData<T> {
472        self
473    }
474
475    fn keyboard_data_mut(&mut self) -> &mut KeyboardData<T> {
476        self
477    }
478}
479
480impl<D, U> Dispatch<wl_keyboard::WlKeyboard, U, D> for SeatState
481where
482    D: Dispatch<wl_keyboard::WlKeyboard, U> + KeyboardHandler,
483    U: KeyboardDataExt,
484{
485    fn event(
486        data: &mut D,
487        keyboard: &wl_keyboard::WlKeyboard,
488        event: wl_keyboard::Event,
489        udata: &U,
490        conn: &Connection,
491        qh: &QueueHandle<D>,
492    ) {
493        let udata = udata.keyboard_data();
494
495        // The compositor has no way to tell clients if the seat is not version 4 or above.
496        // In this case, send a synthetic repeat info event using the default repeat values used by the X
497        // server.
498        if keyboard.version() < 4 && udata.first_event.load(Ordering::SeqCst) {
499            udata.first_event.store(true, Ordering::SeqCst);
500
501            data.update_repeat_info(
502                conn,
503                qh,
504                keyboard,
505                RepeatInfo::Repeat { rate: NonZeroU32::new(200).unwrap(), delay: 200 },
506            );
507        }
508
509        match event {
510            wl_keyboard::Event::Keymap { format, fd, size } => {
511                match format {
512                    WEnum::Value(format) => match format {
513                        wl_keyboard::KeymapFormat::NoKeymap => {
514                            log::warn!(target: "sctk", "non-xkb compatible keymap");
515                        }
516
517                        wl_keyboard::KeymapFormat::XkbV1 => {
518                            if udata.user_specified_rmlvo {
519                                // state is locked, ignore keymap updates
520                                return;
521                            }
522
523                            let context = udata.xkb_context.lock().unwrap();
524
525                            // 0.5.0-beta.0 does not mark this function as unsafe but upstream rightly makes
526                            // this function unsafe.
527                            //
528                            // Version 7 of wl_keyboard requires the file descriptor to be mapped using
529                            // MAP_PRIVATE. xkbcommon-rs does mmap the file descriptor properly.
530                            //
531                            // SAFETY:
532                            // - wayland-client guarantees we have received a valid file descriptor.
533                            #[allow(unused_unsafe)] // Upstream release will change this
534                            match unsafe {
535                                xkb::Keymap::new_from_fd(
536                                    &context,
537                                    fd,
538                                    size as usize,
539                                    xkb::KEYMAP_FORMAT_TEXT_V1,
540                                    xkb::COMPILE_NO_FLAGS,
541                                )
542                            } {
543                                Ok(Some(keymap)) => {
544                                    let state = xkb::State::new(&keymap);
545                                    {
546                                        let mut state_guard = udata.xkb_state.lock().unwrap();
547                                        *state_guard = Some(state);
548                                    }
549                                    data.update_keymap(conn, qh, keyboard, Keymap(&keymap));
550                                }
551
552                                Ok(None) => {
553                                    log::error!(target: "sctk", "invalid keymap");
554                                }
555
556                                Err(err) => {
557                                    log::error!(target: "sctk", "{}", err);
558                                }
559                            }
560                        }
561
562                        _ => unreachable!(),
563                    },
564
565                    WEnum::Unknown(value) => {
566                        log::warn!(target: "sctk", "unknown keymap format 0x{:x}", value)
567                    }
568                }
569            }
570
571            wl_keyboard::Event::Enter { serial, surface, keys } => {
572                let state_guard = udata.xkb_state.lock().unwrap();
573
574                if let Some(guard) = state_guard.as_ref() {
575                    // Keysyms are encoded as an array of u32
576                    let raw = keys
577                        .chunks_exact(4)
578                        .flat_map(TryInto::<[u8; 4]>::try_into)
579                        .map(u32::from_le_bytes)
580                        .collect::<Vec<_>>();
581
582                    let keysyms = raw
583                        .iter()
584                        .copied()
585                        // We must add 8 to the keycode for any functions we pass the raw keycode into per
586                        // wl_keyboard protocol.
587                        .map(|raw| guard.key_get_one_sym(KeyCode::new(raw + 8)))
588                        .collect::<Vec<_>>();
589
590                    // Drop guard before calling user code.
591                    drop(state_guard);
592
593                    data.enter(
594                        conn,
595                        qh,
596                        keyboard,
597                        &surface,
598                        serial,
599                        &raw,
600                        bytemuck::cast_slice(&keysyms),
601                    );
602                }
603
604                *udata.focus.lock().unwrap() = Some(surface);
605            }
606
607            wl_keyboard::Event::Leave { serial, surface } => {
608                // We can send this event without any other checks in the protocol will guarantee a leave is
609                // sent before entering a new surface.
610                #[cfg(feature = "calloop")]
611                {
612                    if let Some(repeat_data) = udata.repeat_data.lock().unwrap().as_mut() {
613                        repeat_data.current_repeat.take();
614                    }
615                }
616
617                data.leave(conn, qh, keyboard, &surface, serial);
618
619                *udata.focus.lock().unwrap() = None;
620            }
621
622            wl_keyboard::Event::Key { serial, time, key, state } => match state {
623                WEnum::Value(state) => {
624                    let state_guard = udata.xkb_state.lock().unwrap();
625
626                    if let Some(guard) = state_guard.as_ref() {
627                        // We must add 8 to the keycode for any functions we pass the raw keycode into per
628                        // wl_keyboard protocol.
629                        let keycode = KeyCode::new(key + 8);
630                        let keysym = guard.key_get_one_sym(keycode);
631                        let utf8 = if state == wl_keyboard::KeyState::Pressed {
632                            let mut compose = udata.xkb_compose.lock().unwrap();
633
634                            match compose.as_mut() {
635                                Some(compose) => match compose.feed(keysym) {
636                                    xkb::FeedResult::Ignored => None,
637                                    xkb::FeedResult::Accepted => match compose.status() {
638                                        xkb::Status::Composed => compose.utf8(),
639                                        xkb::Status::Nothing => Some(guard.key_get_utf8(keycode)),
640                                        _ => None,
641                                    },
642                                },
643
644                                // No compose
645                                None => Some(guard.key_get_utf8(keycode)),
646                            }
647                        } else {
648                            None
649                        };
650
651                        // Drop guard before calling user code.
652                        drop(state_guard);
653
654                        let event = KeyEvent { time, raw_code: key, keysym, utf8 };
655
656                        match state {
657                            wl_keyboard::KeyState::Released => {
658                                #[cfg(feature = "calloop")]
659                                {
660                                    if let Some(repeat_data) =
661                                        udata.repeat_data.lock().unwrap().as_mut()
662                                    {
663                                        if Some(event.raw_code)
664                                            == repeat_data
665                                                .current_repeat
666                                                .as_ref()
667                                                .map(|r| r.key.raw_code)
668                                        {
669                                            repeat_data.current_repeat = None;
670                                        }
671                                    }
672                                }
673                                data.release_key(conn, qh, keyboard, serial, event);
674                            }
675
676                            wl_keyboard::KeyState::Pressed => {
677                                #[cfg(feature = "calloop")]
678                                {
679                                    if let Some(repeat_data) =
680                                        udata.repeat_data.lock().unwrap().as_mut()
681                                    {
682                                        let loop_handle = &mut repeat_data.loop_handle;
683                                        let state_guard = udata.xkb_state.lock().unwrap();
684                                        let key_repeats = state_guard
685                                            .as_ref()
686                                            .map(|guard| {
687                                                guard
688                                                    .get_keymap()
689                                                    .key_repeats(KeyCode::new(event.raw_code + 8))
690                                            })
691                                            .unwrap_or_default();
692                                        if key_repeats {
693                                            // Cancel the previous timer / repeat.
694                                            if let Some(token) = repeat_data.repeat_token.take() {
695                                                loop_handle.remove(token);
696                                            }
697
698                                            let surface =
699                                                match udata.focus.lock().unwrap().as_ref().cloned()
700                                                {
701                                                    Some(surface) => surface,
702
703                                                    None => {
704                                                        log::warn!(
705                                                "wl_keyboard::key with no focused surface");
706                                                        return;
707                                                    }
708                                                };
709
710                                            // Update the current repeat key.
711                                            repeat_data.current_repeat.replace(RepeatedKey {
712                                                key: event.clone(),
713                                                is_first: true,
714                                                surface,
715                                            });
716
717                                            let (delay, rate) = match repeat_data.repeat_info {
718                                                RepeatInfo::Disable => return,
719                                                RepeatInfo::Repeat { delay, rate } => (delay, rate),
720                                            };
721                                            let gap = Duration::from_micros(
722                                                1_000_000 / rate.get() as u64,
723                                            );
724                                            let timer = Timer::from_duration(
725                                                Duration::from_millis(delay as u64),
726                                            );
727                                            let repeat_data2 = udata.repeat_data.clone();
728
729                                            // Start the timer.
730                                            let kbd = keyboard.clone();
731                                            if let Ok(token) = loop_handle.insert_source(
732                                                timer,
733                                                move |_, _, state| {
734                                                    let mut repeat_data =
735                                                        repeat_data2.lock().unwrap();
736                                                    let repeat_data = match repeat_data.as_mut() {
737                                                        Some(repeat_data) => repeat_data,
738                                                        None => return TimeoutAction::Drop,
739                                                    };
740
741                                                    let callback = &mut repeat_data.callback;
742                                                    let key = &mut repeat_data.current_repeat;
743                                                    if key.is_none() {
744                                                        return TimeoutAction::Drop;
745                                                    }
746                                                    let key = key.as_mut().unwrap();
747                                                    // If surface was closed while focused, no `Leave`
748                                                    // event occurred.
749                                                    if !key.surface.is_alive() {
750                                                        return TimeoutAction::Drop;
751                                                    }
752                                                    key.key.time += if key.is_first {
753                                                        key.is_first = false;
754                                                        delay
755                                                    } else {
756                                                        gap.as_millis() as u32
757                                                    };
758                                                    callback(state, &kbd, key.key.clone());
759                                                    TimeoutAction::ToDuration(gap)
760                                                },
761                                            ) {
762                                                repeat_data.repeat_token = Some(token);
763                                            }
764                                        }
765                                    }
766                                }
767                                data.press_key(conn, qh, keyboard, serial, event);
768                            }
769
770                            _ => unreachable!(),
771                        }
772                    };
773                }
774
775                WEnum::Unknown(unknown) => {
776                    log::warn!(target: "sctk", "{}: compositor sends invalid key state: {:x}", keyboard.id(), unknown);
777                }
778            },
779
780            wl_keyboard::Event::Modifiers {
781                serial,
782                mods_depressed,
783                mods_latched,
784                mods_locked,
785                group,
786            } => {
787                let mut guard = udata.xkb_state.lock().unwrap();
788
789                let state = match guard.as_mut() {
790                    Some(state) => state,
791                    None => return,
792                };
793
794                // Apply the new xkb state with the new modifiers.
795                let _ = state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
796
797                // Update the currently repeating key if any.
798                #[cfg(feature = "calloop")]
799                if let Some(repeat_data) = udata.repeat_data.lock().unwrap().as_mut() {
800                    if let Some(mut event) = repeat_data.current_repeat.take() {
801                        // Apply new modifiers to get new utf8.
802                        event.key.utf8 = {
803                            let mut compose = udata.xkb_compose.lock().unwrap();
804
805                            match compose.as_mut() {
806                                Some(compose) => match compose.feed(event.key.keysym) {
807                                    xkb::FeedResult::Ignored => None,
808                                    xkb::FeedResult::Accepted => match compose.status() {
809                                        xkb::Status::Composed => compose.utf8(),
810                                        xkb::Status::Nothing => Some(
811                                            state
812                                                .key_get_utf8(KeyCode::new(event.key.raw_code + 8)),
813                                        ),
814                                        _ => None,
815                                    },
816                                },
817
818                                // No compose.
819                                None => {
820                                    Some(state.key_get_utf8(KeyCode::new(event.key.raw_code + 8)))
821                                }
822                            }
823                        };
824
825                        // Update the stored event.
826                        repeat_data.current_repeat = Some(event);
827                    }
828                }
829
830                // Drop guard before calling user code.
831                drop(guard);
832
833                // Always issue the modifiers update for the user.
834                let modifiers = udata.update_modifiers();
835                data.update_modifiers(conn, qh, keyboard, serial, modifiers, group);
836            }
837
838            wl_keyboard::Event::RepeatInfo { rate, delay } => {
839                let info = if rate != 0 {
840                    RepeatInfo::Repeat {
841                        rate: NonZeroU32::new(rate as u32).unwrap(),
842                        delay: delay as u32,
843                    }
844                } else {
845                    RepeatInfo::Disable
846                };
847
848                #[cfg(feature = "calloop")]
849                {
850                    if let Some(repeat_data) = udata.repeat_data.lock().unwrap().as_mut() {
851                        repeat_data.repeat_info = info;
852                    }
853                }
854                data.update_repeat_info(conn, qh, keyboard, info);
855            }
856
857            _ => unreachable!(),
858        }
859    }
860}