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