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            .and_then(|v| if v.is_empty() { None } else { Some(v) })
461            .or_else(|| env::var_os("LC_CTYPE"))
462            .and_then(|v| if v.is_empty() { None } else { Some(v) })
463            .or_else(|| env::var_os("LANG"))
464            .and_then(|v| if v.is_empty() { None } else { Some(v) })
465            .unwrap_or_else(|| "C".into())
466            .to_str()
467        {
468            // TODO: Pending new release of xkbcommon to use new_from_locale with OsStr
469            if let Ok(table) = xkb::compose::Table::new_from_locale(
470                &xkb_context,
471                locale.as_ref(),
472                xkb::compose::COMPILE_NO_FLAGS,
473            ) {
474                let compose_state =
475                    xkb::compose::State::new(&table, xkb::compose::COMPILE_NO_FLAGS);
476                *self.xkb_compose.lock().unwrap() = Some(compose_state);
477            }
478        }
479    }
480
481    fn update_modifiers(&self) -> Modifiers {
482        let guard = self.xkb_state.lock().unwrap();
483        let state = guard.as_ref().unwrap();
484
485        Modifiers {
486            ctrl: state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE),
487            alt: state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE),
488            shift: state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE),
489            caps_lock: state.mod_name_is_active(xkb::MOD_NAME_CAPS, xkb::STATE_MODS_EFFECTIVE),
490            logo: state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE),
491            num_lock: state.mod_name_is_active(xkb::MOD_NAME_NUM, xkb::STATE_MODS_EFFECTIVE),
492        }
493    }
494}
495
496impl<D, U> Dispatch2<wl_keyboard::WlKeyboard, D> for KeyboardData<D, U>
497where
498    D: KeyboardHandler + 'static,
499{
500    fn event(
501        &self,
502        data: &mut D,
503        keyboard: &wl_keyboard::WlKeyboard,
504        event: wl_keyboard::Event,
505        conn: &Connection,
506        qh: &QueueHandle<D>,
507    ) {
508        // The compositor has no way to tell clients if the seat is not version 4 or above.
509        // In this case, send a synthetic repeat info event using the default repeat values used by the X
510        // server.
511        if keyboard.version() < 4 && self.first_event.load(Ordering::SeqCst) {
512            self.first_event.store(true, Ordering::SeqCst);
513
514            data.update_repeat_info(
515                conn,
516                qh,
517                keyboard,
518                RepeatInfo::Repeat { rate: NonZeroU32::new(200).unwrap(), delay: 200 },
519            );
520        }
521
522        match event {
523            wl_keyboard::Event::Keymap { format, fd, size } => {
524                match format {
525                    WEnum::Value(format) => match format {
526                        wl_keyboard::KeymapFormat::NoKeymap => {
527                            log::warn!(target: "sctk", "non-xkb compatible keymap");
528                        }
529
530                        wl_keyboard::KeymapFormat::XkbV1 => {
531                            if self.user_specified_rmlvo {
532                                // state is locked, ignore keymap updates
533                                return;
534                            }
535
536                            let context = self.xkb_context.lock().unwrap();
537
538                            // 0.5.0-beta.0 does not mark this function as unsafe but upstream rightly makes
539                            // this function unsafe.
540                            //
541                            // Version 7 of wl_keyboard requires the file descriptor to be mapped using
542                            // MAP_PRIVATE. xkbcommon-rs does mmap the file descriptor properly.
543                            //
544                            // SAFETY:
545                            // - wayland-client guarantees we have received a valid file descriptor.
546                            #[allow(unused_unsafe)] // Upstream release will change this
547                            match unsafe {
548                                xkb::Keymap::new_from_fd(
549                                    &context,
550                                    fd,
551                                    size as usize,
552                                    xkb::KEYMAP_FORMAT_TEXT_V1,
553                                    xkb::COMPILE_NO_FLAGS,
554                                )
555                            } {
556                                Ok(Some(keymap)) => {
557                                    let state = xkb::State::new(&keymap);
558                                    {
559                                        let mut state_guard = self.xkb_state.lock().unwrap();
560                                        *state_guard = Some(state);
561                                    }
562                                    data.update_keymap(conn, qh, keyboard, Keymap(&keymap));
563                                }
564
565                                Ok(None) => {
566                                    log::error!(target: "sctk", "invalid keymap");
567                                }
568
569                                Err(err) => {
570                                    log::error!(target: "sctk", "{}", err);
571                                }
572                            }
573                        }
574
575                        _ => unreachable!(),
576                    },
577
578                    WEnum::Unknown(value) => {
579                        log::warn!(target: "sctk", "unknown keymap format 0x{:x}", value)
580                    }
581                }
582            }
583
584            wl_keyboard::Event::Enter { serial, surface, keys } => {
585                let state_guard = self.xkb_state.lock().unwrap();
586
587                if let Some(guard) = state_guard.as_ref() {
588                    // Keysyms are encoded as an array of u32
589                    let raw = keys
590                        .chunks_exact(4)
591                        .flat_map(TryInto::<[u8; 4]>::try_into)
592                        .map(u32::from_le_bytes)
593                        .collect::<Vec<_>>();
594
595                    let keysyms = raw
596                        .iter()
597                        .copied()
598                        // We must add 8 to the keycode for any functions we pass the raw keycode into per
599                        // wl_keyboard protocol.
600                        .map(|raw| guard.key_get_one_sym(KeyCode::new(raw + 8)))
601                        .collect::<Vec<_>>();
602
603                    // Drop guard before calling user code.
604                    drop(state_guard);
605
606                    data.enter(
607                        conn,
608                        qh,
609                        keyboard,
610                        &surface,
611                        serial,
612                        &raw,
613                        bytemuck::cast_slice(&keysyms),
614                    );
615                }
616
617                *self.focus.lock().unwrap() = Some(surface);
618            }
619
620            wl_keyboard::Event::Leave { serial, surface } => {
621                // We can send this event without any other checks in the protocol will guarantee a leave is
622                // sent before entering a new surface.
623                #[cfg(feature = "calloop")]
624                {
625                    if let Some(repeat_data) = self.repeat_data.lock().unwrap().as_mut() {
626                        repeat_data.current_repeat.take();
627                    }
628                }
629
630                data.leave(conn, qh, keyboard, &surface, serial);
631
632                *self.focus.lock().unwrap() = None;
633            }
634
635            wl_keyboard::Event::Key { serial, time, key, state } => match state {
636                WEnum::Value(state) => {
637                    let state_guard = self.xkb_state.lock().unwrap();
638
639                    if let Some(guard) = state_guard.as_ref() {
640                        // We must add 8 to the keycode for any functions we pass the raw keycode into per
641                        // wl_keyboard protocol.
642                        let keycode = KeyCode::new(key + 8);
643                        let keysym = guard.key_get_one_sym(keycode);
644                        let utf8 = if state == wl_keyboard::KeyState::Pressed {
645                            let mut compose = self.xkb_compose.lock().unwrap();
646
647                            match compose.as_mut() {
648                                Some(compose) => match compose.feed(keysym) {
649                                    xkb::FeedResult::Ignored => None,
650                                    xkb::FeedResult::Accepted => match compose.status() {
651                                        xkb::Status::Composed => compose.utf8(),
652                                        xkb::Status::Nothing => Some(guard.key_get_utf8(keycode)),
653                                        _ => None,
654                                    },
655                                },
656
657                                // No compose
658                                None => Some(guard.key_get_utf8(keycode)),
659                            }
660                        } else {
661                            None
662                        };
663
664                        // Drop guard before calling user code.
665                        drop(state_guard);
666
667                        let event = KeyEvent { time, raw_code: key, keysym, utf8 };
668
669                        match state {
670                            wl_keyboard::KeyState::Released => {
671                                #[cfg(feature = "calloop")]
672                                {
673                                    if let Some(repeat_data) =
674                                        self.repeat_data.lock().unwrap().as_mut()
675                                    {
676                                        if Some(event.raw_code)
677                                            == repeat_data
678                                                .current_repeat
679                                                .as_ref()
680                                                .map(|r| r.key.raw_code)
681                                        {
682                                            repeat_data.current_repeat = None;
683                                        }
684                                    }
685                                }
686                                data.release_key(conn, qh, keyboard, serial, event);
687                            }
688
689                            wl_keyboard::KeyState::Repeated => {
690                                data.repeat_key(conn, qh, keyboard, serial, event);
691                            }
692
693                            wl_keyboard::KeyState::Pressed => {
694                                data.press_key(conn, qh, keyboard, serial, event.clone());
695                                #[cfg(feature = "calloop")]
696                                {
697                                    if let Some(repeat_data) =
698                                        self.repeat_data.lock().unwrap().as_mut()
699                                    {
700                                        let loop_handle = &mut repeat_data.loop_handle;
701                                        let state_guard = self.xkb_state.lock().unwrap();
702                                        let key_repeats = state_guard
703                                            .as_ref()
704                                            .map(|guard| {
705                                                guard
706                                                    .get_keymap()
707                                                    .key_repeats(KeyCode::new(event.raw_code + 8))
708                                            })
709                                            .unwrap_or_default();
710                                        if key_repeats {
711                                            // Cancel the previous timer / repeat.
712                                            if let Some(token) = repeat_data.repeat_token.take() {
713                                                loop_handle.remove(token);
714                                            }
715
716                                            let surface = match self
717                                                .focus
718                                                .lock()
719                                                .unwrap()
720                                                .as_ref()
721                                                .cloned()
722                                            {
723                                                Some(surface) => surface,
724
725                                                None => {
726                                                    log::warn!(
727                                                        "wl_keyboard::key with no focused surface"
728                                                    );
729                                                    return;
730                                                }
731                                            };
732
733                                            // Update the current repeat key.
734                                            repeat_data.current_repeat.replace(RepeatedKey {
735                                                key: event.clone(),
736                                                is_first: true,
737                                                surface,
738                                            });
739
740                                            let (delay, rate) = match repeat_data.repeat_info {
741                                                RepeatInfo::Disable => return,
742                                                RepeatInfo::Repeat { delay, rate } => (delay, rate),
743                                            };
744                                            let gap = Duration::from_micros(
745                                                1_000_000 / rate.get() as u64,
746                                            );
747                                            let timer = Timer::from_duration(
748                                                Duration::from_millis(delay as u64),
749                                            );
750                                            let repeat_data2 = self.repeat_data.clone();
751
752                                            // Start the timer.
753                                            let kbd = keyboard.clone();
754                                            if let Ok(token) = loop_handle.insert_source(
755                                                timer,
756                                                move |_, _, state| {
757                                                    let mut repeat_data =
758                                                        repeat_data2.lock().unwrap();
759                                                    let repeat_data = match repeat_data.as_mut() {
760                                                        Some(repeat_data) => repeat_data,
761                                                        None => return TimeoutAction::Drop,
762                                                    };
763
764                                                    let callback = &mut repeat_data.callback;
765                                                    let key = &mut repeat_data.current_repeat;
766                                                    if key.is_none() {
767                                                        return TimeoutAction::Drop;
768                                                    }
769                                                    let key = key.as_mut().unwrap();
770                                                    // If surface was closed while focused, no `Leave`
771                                                    // event occurred.
772                                                    if !key.surface.is_alive() {
773                                                        return TimeoutAction::Drop;
774                                                    }
775                                                    key.key.time += if key.is_first {
776                                                        key.is_first = false;
777                                                        delay
778                                                    } else {
779                                                        gap.as_millis() as u32
780                                                    };
781                                                    callback(state, &kbd, key.key.clone());
782                                                    TimeoutAction::ToDuration(gap)
783                                                },
784                                            ) {
785                                                repeat_data.repeat_token = Some(token);
786                                            }
787                                        }
788                                    }
789                                }
790                            }
791
792                            _ => unreachable!(),
793                        }
794                    };
795                }
796
797                WEnum::Unknown(unknown) => {
798                    log::warn!(target: "sctk", "{}: compositor sends invalid key state: {:x}", keyboard.id(), unknown);
799                }
800            },
801
802            wl_keyboard::Event::Modifiers {
803                serial,
804                mods_depressed,
805                mods_latched,
806                mods_locked,
807                group,
808            } => {
809                let mut guard = self.xkb_state.lock().unwrap();
810
811                let state = match guard.as_mut() {
812                    Some(state) => state,
813                    None => return,
814                };
815
816                // Apply the new xkb state with the new modifiers.
817                let _ = state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
818
819                // Update the currently repeating key if any.
820                #[cfg(feature = "calloop")]
821                if let Some(repeat_data) = self.repeat_data.lock().unwrap().as_mut() {
822                    if let Some(mut event) = repeat_data.current_repeat.take() {
823                        // Apply new modifiers to get new utf8.
824                        event.key.utf8 = {
825                            let mut compose = self.xkb_compose.lock().unwrap();
826
827                            match compose.as_mut() {
828                                Some(compose) => match compose.feed(event.key.keysym) {
829                                    xkb::FeedResult::Ignored => None,
830                                    xkb::FeedResult::Accepted => match compose.status() {
831                                        xkb::Status::Composed => compose.utf8(),
832                                        xkb::Status::Nothing => Some(
833                                            state
834                                                .key_get_utf8(KeyCode::new(event.key.raw_code + 8)),
835                                        ),
836                                        _ => None,
837                                    },
838                                },
839
840                                // No compose.
841                                None => {
842                                    Some(state.key_get_utf8(KeyCode::new(event.key.raw_code + 8)))
843                                }
844                            }
845                        };
846
847                        // Update the stored event.
848                        repeat_data.current_repeat = Some(event);
849                    }
850                }
851
852                // Drop guard before calling user code.
853                drop(guard);
854
855                let raw_modifiers = RawModifiers {
856                    depressed: mods_depressed,
857                    latched: mods_latched,
858                    locked: mods_locked,
859                };
860
861                // Always issue the modifiers update for the user.
862                let modifiers = self.update_modifiers();
863                data.update_modifiers(conn, qh, keyboard, serial, modifiers, raw_modifiers, group);
864            }
865
866            wl_keyboard::Event::RepeatInfo { rate, delay } => {
867                let info = if rate != 0 {
868                    RepeatInfo::Repeat {
869                        rate: NonZeroU32::new(rate as u32).unwrap(),
870                        delay: delay as u32,
871                    }
872                } else {
873                    RepeatInfo::Disable
874                };
875
876                #[cfg(feature = "calloop")]
877                {
878                    if let Some(repeat_data) = self.repeat_data.lock().unwrap().as_mut() {
879                        repeat_data.repeat_info = info;
880                    }
881                }
882                data.update_repeat_info(conn, qh, keyboard, info);
883            }
884
885            _ => unreachable!(),
886        }
887    }
888}