Skip to main content

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