1 //! Utilities for keymap interpretation of keyboard input
2 //!
3 //! This module provides an implementation for `wl_keyboard`
4 //! objects using `libxkbcommon` to interpret the keyboard input
5 //! given the user keymap.
6 //!
7 //! The entry point of this module is the [`map_keyboard`](fn.map_keyboard.html)
8 //! function which, given a `wl_seat` and a callback, setup keymap interpretation
9 //! and key repetition for the `wl_keyboard` of this seat.
10 //!
11 //! Key repetition relies on an event source, that needs to be inserted in your
12 //! calloop event loop. Not doing so will prevent key repetition to work
13 //! (but the rest of the functionnality will not be affected).
14 
15 #[cfg(feature = "calloop")]
16 use std::num::NonZeroU32;
17 #[cfg(feature = "calloop")]
18 use std::time::Duration;
19 use std::{
20     cell::RefCell,
21     convert::TryInto,
22     fs::File,
23     os::unix::io::{FromRawFd, RawFd},
24     rc::Rc,
25 };
26 
27 pub use wayland_client::protocol::wl_keyboard::KeyState;
28 use wayland_client::{
29     protocol::{wl_keyboard, wl_seat, wl_surface},
30     Attached,
31 };
32 
33 #[rustfmt::skip]
34 mod ffi;
35 mod state;
36 #[rustfmt::skip]
37 pub mod keysyms;
38 
39 use self::state::KbState;
40 pub use self::state::{ModifiersState, RMLVO};
41 
42 #[cfg(feature = "calloop")]
43 const MICROS_IN_SECOND: u32 = 1000000;
44 
45 /// Possible kinds of key repetition
46 pub enum RepeatKind {
47     /// keys will be repeated at a set rate and delay
48     Fixed {
49         /// The number of repetitions per second that should occur.
50         rate: u32,
51         /// delay (in milliseconds) between a key press and the start of repetition
52         delay: u32,
53     },
54     /// keys will be repeated at a rate and delay set by the wayland server
55     System,
56 }
57 
58 #[derive(Debug)]
59 /// An error that occurred while trying to initialize a mapped keyboard
60 pub enum Error {
61     /// libxkbcommon is not available
62     XKBNotFound,
63     /// Provided RMLVO specified a keymap that would not be loaded
64     BadNames,
65     /// The provided seat does not have the keyboard capability
66     NoKeyboard,
67     /// Failed to init timers for repetition
68     TimerError(std::io::Error),
69 }
70 
71 /// Events received from a mapped keyboard
72 pub enum Event<'a> {
73     /// The keyboard focus has entered a surface
74     Enter {
75         /// serial number of the event
76         serial: u32,
77         /// surface that was entered
78         surface: wl_surface::WlSurface,
79         /// raw values of the currently pressed keys
80         rawkeys: &'a [u32],
81         /// interpreted symbols of the currently pressed keys
82         keysyms: &'a [u32],
83     },
84     /// The keyboard focus has left a surface
85     Leave {
86         /// serial number of the event
87         serial: u32,
88         /// surface that was left
89         surface: wl_surface::WlSurface,
90     },
91     /// The key modifiers have changed state
92     Modifiers {
93         /// current state of the modifiers
94         modifiers: ModifiersState,
95     },
96     /// A key event occurred
97     Key {
98         /// serial number of the event
99         serial: u32,
100         /// time at which the keypress occurred
101         time: u32,
102         /// raw value of the key
103         rawkey: u32,
104         /// interpreted symbol of the key
105         keysym: u32,
106         /// new state of the key
107         state: KeyState,
108         /// utf8 interpretation of the entered text
109         ///
110         /// will always be `None` on key release events
111         utf8: Option<String>,
112     },
113     /// A key repetition event
114     Repeat {
115         /// time at which the repetition occured
116         time: u32,
117         /// raw value of the key
118         rawkey: u32,
119         /// interpreted symbol of the key
120         keysym: u32,
121         /// utf8 interpretation of the entered text
122         utf8: Option<String>,
123     },
124 }
125 
126 /// Implement a keyboard for keymap translation with key repetition
127 ///
128 /// This requires you to provide a callback to receive the events after they
129 /// have been interpreted with the keymap.
130 ///
131 /// The keymap will be loaded from the provided RMLVO rules, or from the compositor
132 /// provided keymap if `None`.
133 ///
134 /// Returns an error if xkbcommon could not be initialized, the RMLVO specification
135 /// contained invalid values, or if the provided seat does not have keyboard capability.
136 ///
137 /// **Note:** This adapter does not handle key repetition. See `map_keyboard_repeat` for that.
map_keyboard<F>( seat: &Attached<wl_seat::WlSeat>, rmlvo: Option<RMLVO>, callback: F, ) -> Result<wl_keyboard::WlKeyboard, Error> where F: FnMut(Event<'_>, wl_keyboard::WlKeyboard, wayland_client::DispatchData<'_>) + 'static,138 pub fn map_keyboard<F>(
139     seat: &Attached<wl_seat::WlSeat>,
140     rmlvo: Option<RMLVO>,
141     callback: F,
142 ) -> Result<wl_keyboard::WlKeyboard, Error>
143 where
144     F: FnMut(Event<'_>, wl_keyboard::WlKeyboard, wayland_client::DispatchData<'_>) + 'static,
145 {
146     let has_kbd = super::with_seat_data(seat, |data| data.has_keyboard).unwrap_or(false);
147     let keyboard = if has_kbd {
148         seat.get_keyboard()
149     } else {
150         return Err(Error::NoKeyboard);
151     };
152 
153     let state = Rc::new(RefCell::new(rmlvo.map(KbState::from_rmlvo).unwrap_or_else(KbState::new)?));
154 
155     let callback = Rc::new(RefCell::new(callback));
156 
157     // prepare the handler
158     let mut kbd_handler = KbdHandler {
159         callback,
160         state,
161         #[cfg(feature = "calloop")]
162         repeat: None,
163     };
164 
165     keyboard.quick_assign(move |keyboard, event, data| {
166         kbd_handler.event(keyboard.detach(), event, data)
167     });
168 
169     Ok(keyboard.detach())
170 }
171 
172 /// Implement a keyboard for keymap translation with key repetition
173 ///
174 /// This requires you to provide a callback to receive the events after they
175 /// have been interpreted with the keymap.
176 ///
177 /// The keymap will be loaded from the provided RMLVO rules, or from the compositor
178 /// provided keymap if `None`.
179 ///
180 /// Returns an error if xkbcommon could not be initialized, the RMLVO specification
181 /// contained invalid values, or if the provided seat does not have keyboard capability.
182 ///
183 /// **Note:** The keyboard repetition handling requires the `calloop` cargo feature.
184 #[cfg(feature = "calloop")]
map_keyboard_repeat<F, Data: 'static>( loop_handle: calloop::LoopHandle<Data>, seat: &Attached<wl_seat::WlSeat>, rmlvo: Option<RMLVO>, repeatkind: RepeatKind, callback: F, ) -> Result<(wl_keyboard::WlKeyboard, calloop::Source<RepeatSource>), Error> where F: FnMut(Event<'_>, wl_keyboard::WlKeyboard, wayland_client::DispatchData<'_>) + 'static,185 pub fn map_keyboard_repeat<F, Data: 'static>(
186     loop_handle: calloop::LoopHandle<Data>,
187     seat: &Attached<wl_seat::WlSeat>,
188     rmlvo: Option<RMLVO>,
189     repeatkind: RepeatKind,
190     callback: F,
191 ) -> Result<(wl_keyboard::WlKeyboard, calloop::Source<RepeatSource>), Error>
192 where
193     F: FnMut(Event<'_>, wl_keyboard::WlKeyboard, wayland_client::DispatchData<'_>) + 'static,
194 {
195     let has_kbd = super::with_seat_data(seat, |data| data.has_keyboard).unwrap_or(false);
196     let keyboard = if has_kbd {
197         seat.get_keyboard()
198     } else {
199         return Err(Error::NoKeyboard);
200     };
201 
202     let state = Rc::new(RefCell::new(rmlvo.map(KbState::from_rmlvo).unwrap_or_else(KbState::new)?));
203 
204     let callback = Rc::new(RefCell::new(callback));
205 
206     let repeat = match repeatkind {
207         RepeatKind::System => RepeatDetails { locked: false, gap: None, delay: 200 },
208         RepeatKind::Fixed { rate, delay } => {
209             let gap = rate_to_gap(rate as i32);
210             RepeatDetails { locked: true, gap, delay }
211         }
212     };
213 
214     // Prepare the repetition handling.
215     let (mut kbd_handler, source) = {
216         let current_repeat = Rc::new(RefCell::new(None));
217 
218         let source = RepeatSource {
219             timer: calloop::timer::Timer::new().map_err(Error::TimerError)?,
220             state: state.clone(),
221             current_repeat: current_repeat.clone(),
222         };
223 
224         let timer_handle = source.timer.handle();
225 
226         let handler = KbdHandler {
227             callback: callback.clone(),
228             state,
229             repeat: Some(KbdRepeat { timer_handle, current_repeat, details: repeat }),
230         };
231         (handler, source)
232     };
233 
234     let source = loop_handle
235         .insert_source(source, move |event, kbd, ddata| {
236             (&mut *callback.borrow_mut())(
237                 event,
238                 kbd.clone(),
239                 wayland_client::DispatchData::wrap(ddata),
240             )
241         })
242         .map_err(|e| Error::TimerError(e.error))?;
243 
244     keyboard.quick_assign(move |keyboard, event, data| {
245         kbd_handler.event(keyboard.detach(), event, data)
246     });
247 
248     Ok((keyboard.detach(), source))
249 }
250 
251 #[cfg(feature = "calloop")]
rate_to_gap(rate: i32) -> Option<NonZeroU32>252 fn rate_to_gap(rate: i32) -> Option<NonZeroU32> {
253     if rate <= 0 {
254         None
255     } else if MICROS_IN_SECOND < rate as u32 {
256         NonZeroU32::new(1)
257     } else {
258         NonZeroU32::new(MICROS_IN_SECOND / rate as u32)
259     }
260 }
261 
262 /*
263  * Classic handling
264  */
265 
266 type KbdCallback = dyn FnMut(Event<'_>, wl_keyboard::WlKeyboard, wayland_client::DispatchData<'_>);
267 
268 #[cfg(feature = "calloop")]
269 struct RepeatDetails {
270     locked: bool,
271     /// Gap between key presses in microseconds.
272     ///
273     /// If the `gap` is `None`, it means that repeat is disabled.
274     gap: Option<NonZeroU32>,
275     /// Delay before starting key repeat in milliseconds.
276     delay: u32,
277 }
278 
279 struct KbdHandler {
280     state: Rc<RefCell<KbState>>,
281     callback: Rc<RefCell<KbdCallback>>,
282     #[cfg(feature = "calloop")]
283     repeat: Option<KbdRepeat>,
284 }
285 
286 #[cfg(feature = "calloop")]
287 struct KbdRepeat {
288     timer_handle: calloop::timer::TimerHandle<()>,
289     current_repeat: Rc<RefCell<Option<RepeatData>>>,
290     details: RepeatDetails,
291 }
292 
293 #[cfg(feature = "calloop")]
294 impl KbdRepeat {
start_repeat(&self, key: u32, keyboard: wl_keyboard::WlKeyboard, time: u32)295     fn start_repeat(&self, key: u32, keyboard: wl_keyboard::WlKeyboard, time: u32) {
296         // Start a new repetition, overwriting the previous ones
297         self.timer_handle.cancel_all_timeouts();
298 
299         // Handle disabled repeat rate.
300         let gap = match self.details.gap {
301             Some(gap) => gap.get() as u64,
302             None => return,
303         };
304 
305         *self.current_repeat.borrow_mut() = Some(RepeatData {
306             keyboard,
307             keycode: key,
308             gap,
309             time: (time + self.details.delay) as u64 * 1000,
310         });
311         self.timer_handle.add_timeout(Duration::from_micros(self.details.delay as u64 * 1000), ());
312     }
313 
stop_repeat(&self, key: u32)314     fn stop_repeat(&self, key: u32) {
315         // only cancel if the released key is the currently repeating key
316         let mut guard = self.current_repeat.borrow_mut();
317         let stop = (*guard).as_ref().map(|d| d.keycode == key).unwrap_or(false);
318         if stop {
319             self.timer_handle.cancel_all_timeouts();
320             *guard = None;
321         }
322     }
323 
stop_all_repeat(&self)324     fn stop_all_repeat(&self) {
325         self.timer_handle.cancel_all_timeouts();
326         *self.current_repeat.borrow_mut() = None;
327     }
328 }
329 
330 impl KbdHandler {
event( &mut self, kbd: wl_keyboard::WlKeyboard, event: wl_keyboard::Event, dispatch_data: wayland_client::DispatchData, )331     fn event(
332         &mut self,
333         kbd: wl_keyboard::WlKeyboard,
334         event: wl_keyboard::Event,
335         dispatch_data: wayland_client::DispatchData,
336     ) {
337         use wl_keyboard::Event;
338 
339         match event {
340             Event::Keymap { format, fd, size } => self.keymap(kbd, format, fd, size),
341             Event::Enter { serial, surface, keys } => {
342                 self.enter(kbd, serial, surface, keys, dispatch_data)
343             }
344             Event::Leave { serial, surface } => self.leave(kbd, serial, surface, dispatch_data),
345             Event::Key { serial, time, key, state } => {
346                 self.key(kbd, serial, time, key, state, dispatch_data)
347             }
348             Event::Modifiers { mods_depressed, mods_latched, mods_locked, group, .. } => {
349                 self.modifiers(kbd, mods_depressed, mods_latched, mods_locked, group, dispatch_data)
350             }
351             Event::RepeatInfo { rate, delay } => self.repeat_info(kbd, rate, delay),
352             _ => {}
353         }
354     }
355 
keymap( &mut self, _: wl_keyboard::WlKeyboard, format: wl_keyboard::KeymapFormat, fd: RawFd, size: u32, )356     fn keymap(
357         &mut self,
358         _: wl_keyboard::WlKeyboard,
359         format: wl_keyboard::KeymapFormat,
360         fd: RawFd,
361         size: u32,
362     ) {
363         let fd = unsafe { File::from_raw_fd(fd) };
364         let mut state = self.state.borrow_mut();
365         if state.locked() {
366             // state is locked, ignore keymap updates
367             return;
368         }
369         if state.ready() {
370             // new keymap, we first deinit to free resources
371             unsafe {
372                 state.de_init();
373             }
374         }
375         match format {
376             wl_keyboard::KeymapFormat::XkbV1 => unsafe {
377                 state.init_with_fd(fd, size as usize);
378             },
379             wl_keyboard::KeymapFormat::NoKeymap => {
380                 // TODO: how to handle this (hopefully never occuring) case?
381             }
382             _ => unreachable!(),
383         }
384     }
385 
enter( &mut self, object: wl_keyboard::WlKeyboard, serial: u32, surface: wl_surface::WlSurface, keys: Vec<u8>, dispatch_data: wayland_client::DispatchData, )386     fn enter(
387         &mut self,
388         object: wl_keyboard::WlKeyboard,
389         serial: u32,
390         surface: wl_surface::WlSurface,
391         keys: Vec<u8>,
392         dispatch_data: wayland_client::DispatchData,
393     ) {
394         let mut state = self.state.borrow_mut();
395         let rawkeys = keys
396             .chunks_exact(4)
397             .map(|c| u32::from_ne_bytes(c.try_into().unwrap()))
398             .collect::<Vec<_>>();
399         let keys: Vec<u32> = rawkeys.iter().map(|k| state.get_one_sym_raw(*k)).collect();
400         (&mut *self.callback.borrow_mut())(
401             Event::Enter { serial, surface, rawkeys: &rawkeys, keysyms: &keys },
402             object,
403             dispatch_data,
404         );
405     }
406 
leave( &mut self, object: wl_keyboard::WlKeyboard, serial: u32, surface: wl_surface::WlSurface, dispatch_data: wayland_client::DispatchData, )407     fn leave(
408         &mut self,
409         object: wl_keyboard::WlKeyboard,
410         serial: u32,
411         surface: wl_surface::WlSurface,
412         dispatch_data: wayland_client::DispatchData,
413     ) {
414         #[cfg(feature = "calloop")]
415         {
416             if let Some(ref mut repeat) = self.repeat {
417                 repeat.stop_all_repeat();
418             }
419         }
420         (&mut *self.callback.borrow_mut())(Event::Leave { serial, surface }, object, dispatch_data);
421     }
422 
423     #[cfg_attr(not(feature = "calloop"), allow(unused_variables))]
key( &mut self, object: wl_keyboard::WlKeyboard, serial: u32, time: u32, key: u32, key_state: wl_keyboard::KeyState, dispatch_data: wayland_client::DispatchData, )424     fn key(
425         &mut self,
426         object: wl_keyboard::WlKeyboard,
427         serial: u32,
428         time: u32,
429         key: u32,
430         key_state: wl_keyboard::KeyState,
431         dispatch_data: wayland_client::DispatchData,
432     ) {
433         let (sym, utf8, repeats) = {
434             let mut state = self.state.borrow_mut();
435             // Get the values to generate a key event
436             let sym = state.get_one_sym_raw(key);
437             let utf8 = if key_state == wl_keyboard::KeyState::Pressed {
438                 match state.compose_feed(sym) {
439                     Some(ffi::xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED) => {
440                         if let Some(status) = state.compose_status() {
441                             match status {
442                                 ffi::xkb_compose_status::XKB_COMPOSE_COMPOSED => {
443                                     state.compose_get_utf8()
444                                 }
445                                 ffi::xkb_compose_status::XKB_COMPOSE_NOTHING => {
446                                     state.get_utf8_raw(key)
447                                 }
448                                 _ => None,
449                             }
450                         } else {
451                             state.get_utf8_raw(key)
452                         }
453                     }
454                     Some(_) => {
455                         // XKB_COMPOSE_FEED_IGNORED
456                         None
457                     }
458                     None => {
459                         // XKB COMPOSE is not initialized
460                         state.get_utf8_raw(key)
461                     }
462                 }
463             } else {
464                 None
465             };
466             let repeats = unsafe { state.key_repeats(key + 8) };
467             (sym, utf8, repeats)
468         };
469 
470         #[cfg(feature = "calloop")]
471         {
472             if let Some(ref mut repeat_handle) = self.repeat {
473                 if repeats {
474                     if key_state == wl_keyboard::KeyState::Pressed {
475                         repeat_handle.start_repeat(key, object.clone(), time);
476                     } else {
477                         repeat_handle.stop_repeat(key);
478                     }
479                 }
480             }
481         }
482 
483         (&mut *self.callback.borrow_mut())(
484             Event::Key { serial, time, rawkey: key, keysym: sym, state: key_state, utf8 },
485             object,
486             dispatch_data,
487         );
488     }
489 
modifiers( &mut self, object: wl_keyboard::WlKeyboard, mods_depressed: u32, mods_latched: u32, mods_locked: u32, group: u32, dispatch_data: wayland_client::DispatchData, )490     fn modifiers(
491         &mut self,
492         object: wl_keyboard::WlKeyboard,
493         mods_depressed: u32,
494         mods_latched: u32,
495         mods_locked: u32,
496         group: u32,
497         dispatch_data: wayland_client::DispatchData,
498     ) {
499         {
500             let mut state = self.state.borrow_mut();
501             state.update_modifiers(mods_depressed, mods_latched, mods_locked, group);
502             (&mut *self.callback.borrow_mut())(
503                 Event::Modifiers { modifiers: state.mods_state() },
504                 object,
505                 dispatch_data,
506             );
507         }
508     }
509 
510     #[cfg_attr(not(feature = "calloop"), allow(unused_variables))]
repeat_info(&mut self, _: wl_keyboard::WlKeyboard, rate: i32, delay: i32)511     fn repeat_info(&mut self, _: wl_keyboard::WlKeyboard, rate: i32, delay: i32) {
512         #[cfg(feature = "calloop")]
513         {
514             if let Some(ref mut repeat_handle) = self.repeat {
515                 if !repeat_handle.details.locked {
516                     repeat_handle.details.gap = rate_to_gap(rate);
517                     repeat_handle.details.delay = delay as u32;
518                 }
519             }
520         }
521     }
522 }
523 
524 /*
525  * Repeat handling
526  */
527 
528 #[cfg(feature = "calloop")]
529 struct RepeatData {
530     keyboard: wl_keyboard::WlKeyboard,
531     keycode: u32,
532     /// Gap between key presses in microseconds.
533     gap: u64,
534     /// Time of the last event in microseconds.
535     time: u64,
536 }
537 
538 /// An event source managing the key repetition of a keyboard
539 ///
540 /// It is given to you from [`map_keyboard`](fn.map_keyboard.html), and you need to
541 /// insert it in your calloop event loop if you want to have functionning key repetition.
542 ///
543 /// If don't want key repetition you can just drop it.
544 ///
545 /// This source will not directly generate calloop events, and the callback provided to
546 /// `EventLoopHandle::insert_source()` will be ignored. Instead it triggers the
547 /// callback you provided to [`map_keyboard`](fn.map_keyboard.html).
548 #[cfg(feature = "calloop")]
549 pub struct RepeatSource {
550     timer: calloop::timer::Timer<()>,
551     state: Rc<RefCell<KbState>>,
552     current_repeat: Rc<RefCell<Option<RepeatData>>>,
553 }
554 
555 #[cfg(feature = "calloop")]
556 impl calloop::EventSource for RepeatSource {
557     type Event = Event<'static>;
558     type Metadata = wl_keyboard::WlKeyboard;
559     type Ret = ();
560 
process_events<F>( &mut self, readiness: calloop::Readiness, token: calloop::Token, mut callback: F, ) -> std::io::Result<()> where F: FnMut(Event<'static>, &mut wl_keyboard::WlKeyboard),561     fn process_events<F>(
562         &mut self,
563         readiness: calloop::Readiness,
564         token: calloop::Token,
565         mut callback: F,
566     ) -> std::io::Result<()>
567     where
568         F: FnMut(Event<'static>, &mut wl_keyboard::WlKeyboard),
569     {
570         let current_repeat = &self.current_repeat;
571         let state = &self.state;
572         self.timer.process_events(readiness, token, |(), timer_handle| {
573             if let Some(ref mut data) = *current_repeat.borrow_mut() {
574                 // there is something to repeat
575                 let mut state = state.borrow_mut();
576                 let keysym = state.get_one_sym_raw(data.keycode);
577                 let utf8 = state.get_utf8_raw(data.keycode);
578                 let new_time = data.gap + data.time;
579                 // Notify the callback.
580                 callback(
581                     Event::Repeat {
582                         time: (new_time / 1000) as u32,
583                         rawkey: data.keycode,
584                         keysym,
585                         utf8,
586                     },
587                     &mut data.keyboard,
588                 );
589                 // Update the time of last event.
590                 data.time = new_time;
591                 // Schedule the next timeout.
592                 timer_handle.add_timeout(Duration::from_micros(data.gap), ());
593             }
594         })
595     }
596 
register(&mut self, poll: &mut calloop::Poll, token: calloop::Token) -> std::io::Result<()>597     fn register(&mut self, poll: &mut calloop::Poll, token: calloop::Token) -> std::io::Result<()> {
598         self.timer.register(poll, token)
599     }
600 
reregister( &mut self, poll: &mut calloop::Poll, token: calloop::Token, ) -> std::io::Result<()>601     fn reregister(
602         &mut self,
603         poll: &mut calloop::Poll,
604         token: calloop::Token,
605     ) -> std::io::Result<()> {
606         self.timer.reregister(poll, token)
607     }
608 
unregister(&mut self, poll: &mut calloop::Poll) -> std::io::Result<()>609     fn unregister(&mut self, poll: &mut calloop::Poll) -> std::io::Result<()> {
610         self.timer.unregister(poll)
611     }
612 }
613