Skip to main content

cranpose_ui/
key_event.rs

1//! Keyboard input event types for Cranpose.
2//!
3//! This module provides platform-independent keyboard event types
4//! that are used to route keyboard input to focused components.
5
6use std::fmt;
7
8pub use cranpose_foundation::Modifiers;
9
10/// Type of keyboard event.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum KeyEventType {
13    /// Key was pressed down.
14    KeyDown,
15    /// Key was released.
16    KeyUp,
17}
18
19/// Physical key codes for keyboard input.
20///
21/// These represent physical keys on the keyboard, independent of
22/// the character they produce (which depends on keyboard layout).
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub enum KeyCode {
25    /// The A key.
26    A,
27    /// The B key.
28    B,
29    /// The C key.
30    C,
31    /// The D key.
32    D,
33    /// The E key.
34    E,
35    /// The F key.
36    F,
37    /// The G key.
38    G,
39    /// The H key.
40    H,
41    /// The I key.
42    I,
43    /// The J key.
44    J,
45    /// The K key.
46    K,
47    /// The L key.
48    L,
49    /// The M key.
50    M,
51    /// The N key.
52    N,
53    /// The O key.
54    O,
55    /// The P key.
56    P,
57    /// The Q key.
58    Q,
59    /// The R key.
60    R,
61    /// The S key.
62    S,
63    /// The T key.
64    T,
65    /// The U key.
66    U,
67    /// The V key.
68    V,
69    /// The W key.
70    W,
71    /// The X key.
72    X,
73    /// The Y key.
74    Y,
75    /// The Z key.
76    Z,
77
78    /// The 0 key on the main number row.
79    Digit0,
80    /// The 1 key on the main number row.
81    Digit1,
82    /// The 2 key on the main number row.
83    Digit2,
84    /// The 3 key on the main number row.
85    Digit3,
86    /// The 4 key on the main number row.
87    Digit4,
88    /// The 5 key on the main number row.
89    Digit5,
90    /// The 6 key on the main number row.
91    Digit6,
92    /// The 7 key on the main number row.
93    Digit7,
94    /// The 8 key on the main number row.
95    Digit8,
96    /// The 9 key on the main number row.
97    Digit9,
98
99    /// The F1 function key.
100    F1,
101    /// The F2 function key.
102    F2,
103    /// The F3 function key.
104    F3,
105    /// The F4 function key.
106    F4,
107    /// The F5 function key.
108    F5,
109    /// The F6 function key.
110    F6,
111    /// The F7 function key.
112    F7,
113    /// The F8 function key.
114    F8,
115    /// The F9 function key.
116    F9,
117    /// The F10 function key.
118    F10,
119    /// The F11 function key.
120    F11,
121    /// The F12 function key.
122    F12,
123
124    /// The up arrow key.
125    ArrowUp,
126    /// The down arrow key.
127    ArrowDown,
128    /// The left arrow key.
129    ArrowLeft,
130    /// The right arrow key.
131    ArrowRight,
132    /// The Home key.
133    Home,
134    /// The End key.
135    End,
136    /// The Page Up key.
137    PageUp,
138    /// The Page Down key.
139    PageDown,
140
141    /// The Backspace key, which deletes backward.
142    Backspace,
143    /// The Delete key, which deletes forward.
144    Delete,
145    /// The main Enter or Return key.
146    Enter,
147    /// The Tab key.
148    Tab,
149    /// The space bar.
150    Space,
151    /// The Escape key.
152    Escape,
153
154    /// The left Shift key.
155    ShiftLeft,
156    /// The right Shift key.
157    ShiftRight,
158    /// The left Control key.
159    ControlLeft,
160    /// The right Control key.
161    ControlRight,
162    /// The left Alt key, called Option on macOS.
163    AltLeft,
164    /// The right Alt key, called Option on macOS.
165    AltRight,
166    /// The left Meta key: Command on macOS, the Windows key elsewhere.
167    MetaLeft,
168    /// The right Meta key: Command on macOS, the Windows key elsewhere.
169    MetaRight,
170
171    /// The minus and underscore key on US layouts.
172    Minus,
173    /// The equals and plus key on US layouts.
174    Equal,
175    /// The left square bracket key on US layouts.
176    BracketLeft,
177    /// The right square bracket key on US layouts.
178    BracketRight,
179    /// The backslash key on US layouts.
180    Backslash,
181    /// The semicolon and colon key on US layouts.
182    Semicolon,
183    /// The apostrophe and quotation mark key on US layouts.
184    Quote,
185    /// The comma key on US layouts.
186    Comma,
187    /// The period key on US layouts.
188    Period,
189    /// The forward slash key on US layouts.
190    Slash,
191    /// The grave accent and tilde key on US layouts, left of the 1 key.
192    Backquote,
193
194    /// Key not recognized or not mapped.
195    Unknown,
196}
197
198const DOM_KEY_CODES: [(&str, KeyCode); 82] = [
199    ("KeyA", KeyCode::A),
200    ("KeyB", KeyCode::B),
201    ("KeyC", KeyCode::C),
202    ("KeyD", KeyCode::D),
203    ("KeyE", KeyCode::E),
204    ("KeyF", KeyCode::F),
205    ("KeyG", KeyCode::G),
206    ("KeyH", KeyCode::H),
207    ("KeyI", KeyCode::I),
208    ("KeyJ", KeyCode::J),
209    ("KeyK", KeyCode::K),
210    ("KeyL", KeyCode::L),
211    ("KeyM", KeyCode::M),
212    ("KeyN", KeyCode::N),
213    ("KeyO", KeyCode::O),
214    ("KeyP", KeyCode::P),
215    ("KeyQ", KeyCode::Q),
216    ("KeyR", KeyCode::R),
217    ("KeyS", KeyCode::S),
218    ("KeyT", KeyCode::T),
219    ("KeyU", KeyCode::U),
220    ("KeyV", KeyCode::V),
221    ("KeyW", KeyCode::W),
222    ("KeyX", KeyCode::X),
223    ("KeyY", KeyCode::Y),
224    ("KeyZ", KeyCode::Z),
225    ("Digit0", KeyCode::Digit0),
226    ("Digit1", KeyCode::Digit1),
227    ("Digit2", KeyCode::Digit2),
228    ("Digit3", KeyCode::Digit3),
229    ("Digit4", KeyCode::Digit4),
230    ("Digit5", KeyCode::Digit5),
231    ("Digit6", KeyCode::Digit6),
232    ("Digit7", KeyCode::Digit7),
233    ("Digit8", KeyCode::Digit8),
234    ("Digit9", KeyCode::Digit9),
235    ("F1", KeyCode::F1),
236    ("F2", KeyCode::F2),
237    ("F3", KeyCode::F3),
238    ("F4", KeyCode::F4),
239    ("F5", KeyCode::F5),
240    ("F6", KeyCode::F6),
241    ("F7", KeyCode::F7),
242    ("F8", KeyCode::F8),
243    ("F9", KeyCode::F9),
244    ("F10", KeyCode::F10),
245    ("F11", KeyCode::F11),
246    ("F12", KeyCode::F12),
247    ("ArrowUp", KeyCode::ArrowUp),
248    ("ArrowDown", KeyCode::ArrowDown),
249    ("ArrowLeft", KeyCode::ArrowLeft),
250    ("ArrowRight", KeyCode::ArrowRight),
251    ("Home", KeyCode::Home),
252    ("End", KeyCode::End),
253    ("PageUp", KeyCode::PageUp),
254    ("PageDown", KeyCode::PageDown),
255    ("Backspace", KeyCode::Backspace),
256    ("Delete", KeyCode::Delete),
257    ("Enter", KeyCode::Enter),
258    ("NumpadEnter", KeyCode::Enter),
259    ("Tab", KeyCode::Tab),
260    ("Space", KeyCode::Space),
261    ("Escape", KeyCode::Escape),
262    ("ShiftLeft", KeyCode::ShiftLeft),
263    ("ShiftRight", KeyCode::ShiftRight),
264    ("ControlLeft", KeyCode::ControlLeft),
265    ("ControlRight", KeyCode::ControlRight),
266    ("AltLeft", KeyCode::AltLeft),
267    ("AltRight", KeyCode::AltRight),
268    ("MetaLeft", KeyCode::MetaLeft),
269    ("MetaRight", KeyCode::MetaRight),
270    ("Minus", KeyCode::Minus),
271    ("Equal", KeyCode::Equal),
272    ("BracketLeft", KeyCode::BracketLeft),
273    ("BracketRight", KeyCode::BracketRight),
274    ("Backslash", KeyCode::Backslash),
275    ("Semicolon", KeyCode::Semicolon),
276    ("Quote", KeyCode::Quote),
277    ("Comma", KeyCode::Comma),
278    ("Period", KeyCode::Period),
279    ("Slash", KeyCode::Slash),
280    ("Backquote", KeyCode::Backquote),
281];
282
283impl KeyCode {
284    /// The key a W3C `KeyboardEvent.code` value names, such as `"KeyA"`,
285    /// `"ArrowUp"` or `"ShiftLeft"`; `"NumpadEnter"` is [`KeyCode::Enter`]. A
286    /// code with no counterpart here is [`KeyCode::Unknown`].
287    pub fn from_dom_code(code: &str) -> Self {
288        DOM_KEY_CODES
289            .iter()
290            .find(|(name, _)| *name == code)
291            .map_or(Self::Unknown, |(_, key)| *key)
292    }
293}
294
295/// A keyboard input event.
296///
297/// Contains information about which key was pressed/released,
298/// the text it produces (if any), and modifier state.
299#[derive(Debug, Clone, PartialEq, Eq)]
300pub struct KeyEvent {
301    /// The physical key that was pressed.
302    pub key_code: KeyCode,
303    /// The text produced by this key press (may be empty for non-character keys).
304    /// This accounts for keyboard layout and modifiers (e.g., Shift+A = "A").
305    pub text: String,
306    /// Current state of modifier keys.
307    pub modifiers: Modifiers,
308    /// Type of event (down or up).
309    pub event_type: KeyEventType,
310}
311
312impl KeyEvent {
313    /// Creates a new key event.
314    pub fn new(
315        key_code: KeyCode,
316        text: impl Into<String>,
317        modifiers: Modifiers,
318        event_type: KeyEventType,
319    ) -> Self {
320        Self {
321            key_code,
322            text: text.into(),
323            modifiers,
324            event_type,
325        }
326    }
327
328    /// Creates a key down event with the given key code and text.
329    pub fn key_down(key_code: KeyCode, text: impl Into<String>) -> Self {
330        Self::new(key_code, text, Modifiers::NONE, KeyEventType::KeyDown)
331    }
332
333    /// Creates a key down event with modifiers.
334    pub fn key_down_with_modifiers(
335        key_code: KeyCode,
336        text: impl Into<String>,
337        modifiers: Modifiers,
338    ) -> Self {
339        Self::new(key_code, text, modifiers, KeyEventType::KeyDown)
340    }
341
342    /// Returns true if this is a key down event.
343    pub fn is_key_down(&self) -> bool {
344        self.event_type == KeyEventType::KeyDown
345    }
346
347    /// Returns true if this key produces printable text.
348    pub fn has_text(&self) -> bool {
349        !self.text.is_empty()
350    }
351}
352
353impl fmt::Display for KeyEvent {
354    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355        write!(
356            f,
357            "KeyEvent({:?}, text=\"{}\", {:?})",
358            self.key_code, self.text, self.event_type
359        )
360    }
361}
362
363#[cfg(test)]
364#[path = "tests/key_event_tests.rs"]
365mod tests;