Skip to main content

retroglyph/
event.rs

1//! Input event system.
2
3use crate::grid::Pos;
4use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
7/// Keyboard modifier flags.
8///
9/// Implemented as a manual bitflag over `u8` rather than using the
10/// [`bitflags`](https://crates.io/crates/bitflags) crate to keep the
11/// dependency surface minimal for `no_std` environments. Combine with `|`.
12pub struct KeyModifiers(u8);
13
14impl KeyModifiers {
15    /// No modifiers.
16    pub const NONE: Self = Self(0);
17    /// Shift key.
18    pub const SHIFT: Self = Self(1 << 0);
19    /// Control key.
20    pub const CONTROL: Self = Self(1 << 1);
21    /// Alt key.
22    pub const ALT: Self = Self(1 << 2);
23
24    /// Returns `true` if all bits in `other` are set in `self`.
25    #[must_use]
26    pub const fn contains(self, other: Self) -> bool {
27        (self.0 & other.0) == other.0
28    }
29
30    /// Returns `true` if no modifiers are set.
31    #[must_use]
32    pub const fn is_empty(self) -> bool {
33        self.0 == 0
34    }
35}
36
37impl BitOr for KeyModifiers {
38    type Output = Self;
39    fn bitor(self, rhs: Self) -> Self {
40        Self(self.0 | rhs.0)
41    }
42}
43
44impl BitOrAssign for KeyModifiers {
45    fn bitor_assign(&mut self, rhs: Self) {
46        self.0 |= rhs.0;
47    }
48}
49
50impl BitAnd for KeyModifiers {
51    type Output = Self;
52    fn bitand(self, rhs: Self) -> Self {
53        Self(self.0 & rhs.0)
54    }
55}
56
57impl BitAndAssign for KeyModifiers {
58    fn bitand_assign(&mut self, rhs: Self) {
59        self.0 &= rhs.0;
60    }
61}
62
63impl Not for KeyModifiers {
64    type Output = Self;
65    fn not(self) -> Self {
66        Self(!self.0)
67    }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
71/// Keyboard key codes.
72pub enum KeyCode {
73    /// A character key.
74    Char(char),
75    /// A function key.
76    F(u8),
77    /// Backspace.
78    Backspace,
79    /// Enter.
80    Enter,
81    /// Left arrow.
82    Left,
83    /// Right arrow.
84    Right,
85    /// Up arrow.
86    Up,
87    /// Down arrow.
88    Down,
89    /// Home.
90    Home,
91    /// End.
92    End,
93    /// Page Up.
94    PageUp,
95    /// Page Down.
96    PageDown,
97    /// Tab.
98    Tab,
99    /// Backtab.
100    BackTab,
101    /// Delete.
102    Delete,
103    /// Insert.
104    Insert,
105    /// Escape.
106    Escape,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
110/// Keyboard input event.
111pub struct KeyEvent {
112    /// The key code.
113    pub code: KeyCode,
114    /// Modifiers held down when the key was pressed.
115    pub modifiers: KeyModifiers,
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
119/// Mouse button identifiers.
120pub enum MouseButton {
121    /// Left mouse button.
122    Left,
123    /// Right mouse button.
124    Right,
125    /// Middle mouse button.
126    Middle,
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
130/// Kinds of mouse events.
131pub enum MouseEventKind {
132    /// Mouse button pressed.
133    Down(MouseButton),
134    /// Mouse button released.
135    Up(MouseButton),
136    /// Mouse moved.
137    Moved,
138    /// Mouse wheel scrolled up.
139    ScrollUp,
140    /// Mouse wheel scrolled down.
141    ScrollDown,
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
145/// Mouse input event.
146pub struct MouseEvent {
147    /// The kind of mouse event.
148    pub kind: MouseEventKind,
149    /// The position of the mouse.
150    pub position: Pos,
151    /// Modifiers held down during the event.
152    pub modifiers: KeyModifiers,
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
156/// Terminal input event.
157pub enum Event {
158    /// Keyboard event.
159    Key(KeyEvent),
160    /// Mouse event.
161    Mouse(MouseEvent),
162    /// Terminal window resized.
163    Resize(u16, u16),
164    /// Window closed.
165    Close,
166}
167
168#[cfg(test)]
169mod tests {
170    use super::*;
171
172    #[test]
173    fn test_key_modifiers() {
174        let mods = KeyModifiers::SHIFT | KeyModifiers::CONTROL;
175        assert!(mods.contains(KeyModifiers::SHIFT));
176        assert!(mods.contains(KeyModifiers::CONTROL));
177        assert!(!mods.contains(KeyModifiers::ALT));
178        assert!(!mods.is_empty());
179
180        let inverse = !mods;
181        assert!(inverse.contains(KeyModifiers::ALT));
182        assert!(!inverse.contains(KeyModifiers::SHIFT));
183        assert!(!inverse.contains(KeyModifiers::CONTROL));
184    }
185
186    #[test]
187    fn test_event_construction() {
188        let key_event = KeyEvent {
189            code: KeyCode::Char('a'),
190            modifiers: KeyModifiers::SHIFT,
191        };
192        let event = Event::Key(key_event);
193
194        if let Event::Key(ke) = event {
195            assert_eq!(ke.code, KeyCode::Char('a'));
196            assert!(ke.modifiers.contains(KeyModifiers::SHIFT));
197        } else {
198            panic!("Expected Event::Key");
199        }
200    }
201
202    #[test]
203    fn test_mouse_event() {
204        let mouse_event = MouseEvent {
205            kind: MouseEventKind::Down(MouseButton::Left),
206            position: Pos { x: 10, y: 5 },
207            modifiers: KeyModifiers::NONE,
208        };
209        let event = Event::Mouse(mouse_event);
210
211        assert!(matches!(event, Event::Mouse(_)));
212    }
213}