Skip to main content

rmut_front/
key.rs

1//! Keys as a front end reports them, with no toolkit's type in the
2//! signature. Shaped like crossterm's so the terminal front end maps
3//! one to the other at its read site and nothing else notices.
4
5/// Which key.
6#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
7pub enum KeyCode {
8    Char(char),
9    Enter,
10    Esc,
11    Tab,
12    Backspace,
13    Delete,
14    Up,
15    Down,
16    Left,
17    Right,
18    PageUp,
19    PageDown,
20    Home,
21    End,
22    /// Anything a front end reports that rmut has no name for. Never
23    /// bound, never matched.
24    Other,
25}
26
27/// Which modifiers were held: a set of the three rmut cares about.
28#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)]
29pub struct KeyModifiers(u8);
30
31impl KeyModifiers {
32    pub const NONE: KeyModifiers = KeyModifiers(0);
33    pub const SHIFT: KeyModifiers = KeyModifiers(1);
34    pub const CONTROL: KeyModifiers = KeyModifiers(2);
35    pub const ALT: KeyModifiers = KeyModifiers(4);
36
37    pub fn contains(self, other: KeyModifiers) -> bool {
38        self.0 & other.0 == other.0
39    }
40
41    pub fn is_empty(self) -> bool {
42        self.0 == 0
43    }
44}
45
46impl std::ops::BitOr for KeyModifiers {
47    type Output = KeyModifiers;
48    fn bitor(self, rhs: KeyModifiers) -> KeyModifiers {
49        KeyModifiers(self.0 | rhs.0)
50    }
51}
52
53impl std::ops::BitOrAssign for KeyModifiers {
54    fn bitor_assign(&mut self, rhs: KeyModifiers) {
55        self.0 |= rhs.0;
56    }
57}
58
59impl std::ops::BitAnd for KeyModifiers {
60    type Output = KeyModifiers;
61    fn bitand(self, rhs: KeyModifiers) -> KeyModifiers {
62        KeyModifiers(self.0 & rhs.0)
63    }
64}
65
66/// One key press.
67#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
68pub struct KeyEvent {
69    pub code: KeyCode,
70    pub modifiers: KeyModifiers,
71}
72
73impl KeyEvent {
74    pub fn new(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent {
75        KeyEvent { code, modifiers }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn modifier_sets() {
85        let m = KeyModifiers::CONTROL | KeyModifiers::SHIFT;
86        assert!(m.contains(KeyModifiers::CONTROL));
87        assert!(m.contains(KeyModifiers::SHIFT));
88        assert!(!m.contains(KeyModifiers::ALT));
89        assert!(m.contains(KeyModifiers::NONE));
90        assert_eq!(
91            m & (KeyModifiers::CONTROL | KeyModifiers::ALT),
92            KeyModifiers::CONTROL
93        );
94        let mut n = KeyModifiers::NONE;
95        n |= KeyModifiers::ALT;
96        assert_eq!(n, KeyModifiers::ALT);
97    }
98}