evdevil/
keymap_entry.rs

1use std::{fmt, mem};
2
3use crate::{event::Key, raw::input::input_keymap_entry};
4
5/// A device keymap entry translates a scancode to a keycode.
6///
7/// **Note**: This is not the same as the *localized* keymap you use in applications (like QWERTZ or
8/// AZERTY), which is handled by the X server or Wayland compositor.
9/// Instead, this keymap exists to translate raw scancodes from the keyboard to a USB-HID keycode,
10/// which is defined as a US layout.
11///
12/// Returned by [`Evdev::keymap_entry`] and [`Evdev::keymap_entry_by_index`].
13///
14/// [`Evdev::keymap_entry`]: crate::Evdev::keymap_entry
15/// [`Evdev::keymap_entry_by_index`]: crate::Evdev::keymap_entry_by_index
16#[derive(Clone, Copy)]
17#[repr(transparent)]
18pub struct KeymapEntry(pub(crate) input_keymap_entry);
19
20impl KeymapEntry {
21    pub(crate) fn zeroed() -> Self {
22        unsafe { mem::zeroed() }
23    }
24
25    /// Zero-based index of this entry in the keymap.
26    pub fn index(&self) -> u16 {
27        self.0.index
28    }
29
30    /// Returns the [`Key`] associated with this scancode.
31    pub fn keycode(&self) -> Key {
32        let key = self.0.keycode as u16;
33        Key::from_raw(key)
34    }
35
36    /// Returns the [`Scancode`] of this entry.
37    ///
38    /// If the key that produces this [`Scancode`] is pressed, the [`Key`] returned by
39    /// [`KeymapEntry::keycode`] will be generated.
40    /// The OS will then typically translate that [`Key`] to the configured localized keyboard
41    /// layout.
42    pub fn scancode(&self) -> Scancode {
43        let len = self.0.len.min(32);
44        Scancode::from_ne_slice(&self.0.scancode[..len as usize])
45    }
46}
47
48impl fmt::Debug for KeymapEntry {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        f.debug_struct("KeymapEntry")
51            .field("index", &self.index())
52            .field("keycode", &self.keycode())
53            .field("scancode", &self.scancode())
54            .finish()
55    }
56}
57
58/*
59
60The Scripture states:
61
62switch (ke->len) {
63case 1:
64    *scancode = *((u8 *)ke->scancode);
65    break;
66
67case 2:
68    *scancode = *((u16 *)ke->scancode);
69    break;
70
71case 4:
72    *scancode = *((u32 *)ke->scancode);
73    break;
74
75default:
76    return -EINVAL;
77}
78
79Therefore we have to make sure that we only use lengths that have the divine blessing.
80
81*/
82
83/// A raw scancode emitted by a keyboard.
84///
85/// Can be constructed with [`From<u8>`], [`From<u16>`] and [`From<u32>`].
86#[derive(Clone, Copy)]
87pub struct Scancode {
88    // NOTE: not currently canonicalized; there may be leading zeroes
89    pub(crate) len: u8,
90    // In native byte order.
91    pub(crate) bytes: [u8; 32],
92}
93
94impl Scancode {
95    fn from_ne_slice(bytes: &[u8]) -> Self {
96        assert!(bytes.len() <= 32);
97        let mut a = [0; 32];
98        a[..bytes.len()].copy_from_slice(&bytes);
99        Self {
100            len: bytes.len() as u8,
101            bytes: a,
102        }
103    }
104
105    fn as_ne_bytes(&self) -> &[u8] {
106        &self.bytes[..self.len as usize]
107    }
108
109    fn iter_ne_bytes(&self) -> impl DoubleEndedIterator<Item = u8> {
110        self.as_ne_bytes().iter().copied()
111    }
112    fn iter_be_bytes(&self) -> impl Iterator<Item = u8> {
113        #[cfg(target_endian = "little")]
114        return self.iter_ne_bytes().rev();
115
116        #[cfg(target_endian = "big")]
117        return self.iter_ne_bytes();
118    }
119}
120
121impl From<u8> for Scancode {
122    fn from(value: u8) -> Self {
123        Self::from_ne_slice(&[value])
124    }
125}
126impl From<u16> for Scancode {
127    fn from(value: u16) -> Self {
128        Self::from_ne_slice(&value.to_ne_bytes())
129    }
130}
131impl From<u32> for Scancode {
132    fn from(value: u32) -> Self {
133        Self::from_ne_slice(&value.to_ne_bytes())
134    }
135}
136
137impl fmt::Debug for Scancode {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        for (i, byte) in self.iter_be_bytes().skip_while(|b| *b == 0).enumerate() {
140            if i == 0 {
141                write!(f, "{byte:x}")?;
142            } else {
143                write!(f, "{byte:02x}")?;
144            }
145        }
146        Ok(())
147    }
148}
149impl fmt::Display for Scancode {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        <Self as fmt::Debug>::fmt(self, f)
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    #[cfg_attr(target_endian = "big", ignore = "little-endian test")]
161    fn scancode_debug() {
162        let code = Scancode::from_ne_slice(&[0xe0, 0x00, 0x07]);
163        assert_eq!(format!("{code:?}"), "700e0");
164
165        let code = Scancode::from_ne_slice(&[0xe0, 0x00, 0x07, 0x00]);
166        assert_eq!(format!("{code:?}"), "700e0");
167    }
168}