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}