Skip to main content

kozan_core/input/
keyboard.rs

1//! Keyboard event types.
2//!
3//! Like Chrome's `WebKeyboardEvent` — a dedicated struct carrying key code,
4//! modifiers, text input, repeat state, and timestamp.
5//!
6//! Chrome equivalent: `third_party/blink/public/common/input/web_keyboard_event.h`
7
8use std::time::Instant;
9
10use super::modifiers::Modifiers;
11use super::mouse::ButtonState;
12
13/// Keyboard key press or release event.
14///
15/// Chrome equivalent: `WebKeyboardEvent`.
16///
17/// # Fields
18///
19/// - `key`: Physical key code (which key on the keyboard).
20///   Chrome: `dom_code` (physical) + `dom_key` (logical).
21///   We start with physical only — logical keys added when IME support lands.
22///
23/// - `state`: Pressed or Released.
24///   Chrome: encoded in the event type (`kKeyDown` vs `kKeyUp`).
25///
26/// - `modifiers`: Includes `is_auto_repeat` flag for held keys.
27///   Chrome: `modifiers_ & kIsAutoRepeat`.
28///
29/// - `text`: The character(s) produced by this key press, if any.
30///   Chrome: `WebKeyboardEvent::text[4]` (UTF-16).
31///   We use `Option<String>` (UTF-8) — Rust native.
32///
33/// - `timestamp`: When this event was received from the OS.
34///   Chrome: `WebInputEvent::time_stamp_`.
35#[derive(Debug, Clone)]
36pub struct KeyboardEvent {
37    /// Physical key code — which key was pressed.
38    pub key: KeyCode,
39    /// Whether the key was pressed or released.
40    pub state: ButtonState,
41    /// Modifier keys and auto-repeat flag.
42    pub modifiers: Modifiers,
43    /// Text input produced by this key press (if any).
44    /// None for modifier keys, function keys, etc.
45    pub text: Option<String>,
46    /// When this event was received from the OS.
47    pub timestamp: Instant,
48}
49
50/// Physical key code — identifies which key on the keyboard.
51///
52/// Chrome equivalent: `ui::DomCode` (physical key position) mapped from
53/// `ui::KeyboardCode` (Windows virtual key code).
54///
55/// Starts minimal — extended incrementally as needed. Chrome has hundreds
56/// of key codes; we add them as features require them.
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
58pub enum KeyCode {
59    // ---- Letters ----
60    KeyA,
61    KeyB,
62    KeyC,
63    KeyD,
64    KeyE,
65    KeyF,
66    KeyG,
67    KeyH,
68    KeyI,
69    KeyJ,
70    KeyK,
71    KeyL,
72    KeyM,
73    KeyN,
74    KeyO,
75    KeyP,
76    KeyQ,
77    KeyR,
78    KeyS,
79    KeyT,
80    KeyU,
81    KeyV,
82    KeyW,
83    KeyX,
84    KeyY,
85    KeyZ,
86
87    // ---- Digits ----
88    Digit0,
89    Digit1,
90    Digit2,
91    Digit3,
92    Digit4,
93    Digit5,
94    Digit6,
95    Digit7,
96    Digit8,
97    Digit9,
98
99    // ---- Function keys ----
100    F1,
101    F2,
102    F3,
103    F4,
104    F5,
105    F6,
106    F7,
107    F8,
108    F9,
109    F10,
110    F11,
111    F12,
112
113    // ---- Navigation ----
114    ArrowUp,
115    ArrowDown,
116    ArrowLeft,
117    ArrowRight,
118    Home,
119    End,
120    PageUp,
121    PageDown,
122
123    // ---- Editing ----
124    Backspace,
125    Delete,
126    Enter,
127    Tab,
128    Escape,
129    Space,
130
131    // ---- Modifiers (as physical keys) ----
132    ShiftLeft,
133    ShiftRight,
134    ControlLeft,
135    ControlRight,
136    AltLeft,
137    AltRight,
138    SuperLeft,
139    SuperRight,
140
141    // ---- Not yet mapped ----
142    Unknown,
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn keyboard_event_with_text() {
151        let evt = KeyboardEvent {
152            key: KeyCode::KeyA,
153            state: ButtonState::Pressed,
154            modifiers: Modifiers::EMPTY,
155            text: Some("a".to_string()),
156            timestamp: Instant::now(),
157        };
158        assert_eq!(evt.key, KeyCode::KeyA);
159        assert_eq!(evt.text.as_deref(), Some("a"));
160    }
161
162    #[test]
163    fn keyboard_event_auto_repeat() {
164        let evt = KeyboardEvent {
165            key: KeyCode::KeyA,
166            state: ButtonState::Pressed,
167            modifiers: Modifiers::EMPTY.with_auto_repeat(),
168            text: Some("a".to_string()),
169            timestamp: Instant::now(),
170        };
171        assert!(evt.modifiers.is_auto_repeat());
172    }
173
174    #[test]
175    fn keyboard_event_with_modifiers() {
176        let evt = KeyboardEvent {
177            key: KeyCode::KeyC,
178            state: ButtonState::Pressed,
179            modifiers: Modifiers::EMPTY.with_ctrl(),
180            text: None,
181            timestamp: Instant::now(),
182        };
183        assert!(evt.modifiers.ctrl());
184        assert!(evt.text.is_none());
185    }
186
187    #[test]
188    fn modifier_key_has_no_text() {
189        let evt = KeyboardEvent {
190            key: KeyCode::ShiftLeft,
191            state: ButtonState::Pressed,
192            modifiers: Modifiers::EMPTY.with_shift(),
193            text: None,
194            timestamp: Instant::now(),
195        };
196        assert_eq!(evt.key, KeyCode::ShiftLeft);
197        assert!(evt.text.is_none());
198    }
199}