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    A,
26    B,
27    C,
28    D,
29    E,
30    F,
31    G,
32    H,
33    I,
34    J,
35    K,
36    L,
37    M,
38    N,
39    O,
40    P,
41    Q,
42    R,
43    S,
44    T,
45    U,
46    V,
47    W,
48    X,
49    Y,
50    Z,
51
52    Digit0,
53    Digit1,
54    Digit2,
55    Digit3,
56    Digit4,
57    Digit5,
58    Digit6,
59    Digit7,
60    Digit8,
61    Digit9,
62
63    F1,
64    F2,
65    F3,
66    F4,
67    F5,
68    F6,
69    F7,
70    F8,
71    F9,
72    F10,
73    F11,
74    F12,
75
76    ArrowUp,
77    ArrowDown,
78    ArrowLeft,
79    ArrowRight,
80    Home,
81    End,
82    PageUp,
83    PageDown,
84
85    Backspace,
86    Delete,
87    Enter,
88    Tab,
89    Space,
90    Escape,
91
92    ShiftLeft,
93    ShiftRight,
94    ControlLeft,
95    ControlRight,
96    AltLeft,
97    AltRight,
98    MetaLeft,
99    MetaRight,
100
101    Minus,
102    Equal,
103    BracketLeft,
104    BracketRight,
105    Backslash,
106    Semicolon,
107    Quote,
108    Comma,
109    Period,
110    Slash,
111    Backquote,
112
113    /// Key not recognized or not mapped.
114    Unknown,
115}
116
117const DOM_KEY_CODES: [(&str, KeyCode); 82] = [
118    ("KeyA", KeyCode::A),
119    ("KeyB", KeyCode::B),
120    ("KeyC", KeyCode::C),
121    ("KeyD", KeyCode::D),
122    ("KeyE", KeyCode::E),
123    ("KeyF", KeyCode::F),
124    ("KeyG", KeyCode::G),
125    ("KeyH", KeyCode::H),
126    ("KeyI", KeyCode::I),
127    ("KeyJ", KeyCode::J),
128    ("KeyK", KeyCode::K),
129    ("KeyL", KeyCode::L),
130    ("KeyM", KeyCode::M),
131    ("KeyN", KeyCode::N),
132    ("KeyO", KeyCode::O),
133    ("KeyP", KeyCode::P),
134    ("KeyQ", KeyCode::Q),
135    ("KeyR", KeyCode::R),
136    ("KeyS", KeyCode::S),
137    ("KeyT", KeyCode::T),
138    ("KeyU", KeyCode::U),
139    ("KeyV", KeyCode::V),
140    ("KeyW", KeyCode::W),
141    ("KeyX", KeyCode::X),
142    ("KeyY", KeyCode::Y),
143    ("KeyZ", KeyCode::Z),
144    ("Digit0", KeyCode::Digit0),
145    ("Digit1", KeyCode::Digit1),
146    ("Digit2", KeyCode::Digit2),
147    ("Digit3", KeyCode::Digit3),
148    ("Digit4", KeyCode::Digit4),
149    ("Digit5", KeyCode::Digit5),
150    ("Digit6", KeyCode::Digit6),
151    ("Digit7", KeyCode::Digit7),
152    ("Digit8", KeyCode::Digit8),
153    ("Digit9", KeyCode::Digit9),
154    ("F1", KeyCode::F1),
155    ("F2", KeyCode::F2),
156    ("F3", KeyCode::F3),
157    ("F4", KeyCode::F4),
158    ("F5", KeyCode::F5),
159    ("F6", KeyCode::F6),
160    ("F7", KeyCode::F7),
161    ("F8", KeyCode::F8),
162    ("F9", KeyCode::F9),
163    ("F10", KeyCode::F10),
164    ("F11", KeyCode::F11),
165    ("F12", KeyCode::F12),
166    ("ArrowUp", KeyCode::ArrowUp),
167    ("ArrowDown", KeyCode::ArrowDown),
168    ("ArrowLeft", KeyCode::ArrowLeft),
169    ("ArrowRight", KeyCode::ArrowRight),
170    ("Home", KeyCode::Home),
171    ("End", KeyCode::End),
172    ("PageUp", KeyCode::PageUp),
173    ("PageDown", KeyCode::PageDown),
174    ("Backspace", KeyCode::Backspace),
175    ("Delete", KeyCode::Delete),
176    ("Enter", KeyCode::Enter),
177    ("NumpadEnter", KeyCode::Enter),
178    ("Tab", KeyCode::Tab),
179    ("Space", KeyCode::Space),
180    ("Escape", KeyCode::Escape),
181    ("ShiftLeft", KeyCode::ShiftLeft),
182    ("ShiftRight", KeyCode::ShiftRight),
183    ("ControlLeft", KeyCode::ControlLeft),
184    ("ControlRight", KeyCode::ControlRight),
185    ("AltLeft", KeyCode::AltLeft),
186    ("AltRight", KeyCode::AltRight),
187    ("MetaLeft", KeyCode::MetaLeft),
188    ("MetaRight", KeyCode::MetaRight),
189    ("Minus", KeyCode::Minus),
190    ("Equal", KeyCode::Equal),
191    ("BracketLeft", KeyCode::BracketLeft),
192    ("BracketRight", KeyCode::BracketRight),
193    ("Backslash", KeyCode::Backslash),
194    ("Semicolon", KeyCode::Semicolon),
195    ("Quote", KeyCode::Quote),
196    ("Comma", KeyCode::Comma),
197    ("Period", KeyCode::Period),
198    ("Slash", KeyCode::Slash),
199    ("Backquote", KeyCode::Backquote),
200];
201
202impl KeyCode {
203    /// The key a W3C `KeyboardEvent.code` value names, such as `"KeyA"`,
204    /// `"ArrowUp"` or `"ShiftLeft"`; `"NumpadEnter"` is [`KeyCode::Enter`]. A
205    /// code with no counterpart here is [`KeyCode::Unknown`].
206    pub fn from_dom_code(code: &str) -> Self {
207        DOM_KEY_CODES
208            .iter()
209            .find(|(name, _)| *name == code)
210            .map_or(Self::Unknown, |(_, key)| *key)
211    }
212}
213
214/// A keyboard input event.
215///
216/// Contains information about which key was pressed/released,
217/// the text it produces (if any), and modifier state.
218#[derive(Debug, Clone, PartialEq, Eq)]
219pub struct KeyEvent {
220    /// The physical key that was pressed.
221    pub key_code: KeyCode,
222    /// The text produced by this key press (may be empty for non-character keys).
223    /// This accounts for keyboard layout and modifiers (e.g., Shift+A = "A").
224    pub text: String,
225    /// Current state of modifier keys.
226    pub modifiers: Modifiers,
227    /// Type of event (down or up).
228    pub event_type: KeyEventType,
229}
230
231impl KeyEvent {
232    /// Creates a new key event.
233    pub fn new(
234        key_code: KeyCode,
235        text: impl Into<String>,
236        modifiers: Modifiers,
237        event_type: KeyEventType,
238    ) -> Self {
239        Self {
240            key_code,
241            text: text.into(),
242            modifiers,
243            event_type,
244        }
245    }
246
247    /// Creates a key down event with the given key code and text.
248    pub fn key_down(key_code: KeyCode, text: impl Into<String>) -> Self {
249        Self::new(key_code, text, Modifiers::NONE, KeyEventType::KeyDown)
250    }
251
252    /// Creates a key down event with modifiers.
253    pub fn key_down_with_modifiers(
254        key_code: KeyCode,
255        text: impl Into<String>,
256        modifiers: Modifiers,
257    ) -> Self {
258        Self::new(key_code, text, modifiers, KeyEventType::KeyDown)
259    }
260
261    /// Returns true if this is a key down event.
262    pub fn is_key_down(&self) -> bool {
263        self.event_type == KeyEventType::KeyDown
264    }
265
266    /// Returns true if this key produces printable text.
267    pub fn has_text(&self) -> bool {
268        !self.text.is_empty()
269    }
270}
271
272impl fmt::Display for KeyEvent {
273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274        write!(
275            f,
276            "KeyEvent({:?}, text=\"{}\", {:?})",
277            self.key_code, self.text, self.event_type
278        )
279    }
280}
281
282#[cfg(test)]
283#[path = "tests/key_event_tests.rs"]
284mod tests;