1use std::fmt;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum KeyEventType {
11 KeyDown,
13 KeyUp,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
19pub struct Modifiers {
20 pub shift: bool,
22 pub ctrl: bool,
24 pub alt: bool,
26 pub meta: bool,
28}
29
30impl Modifiers {
31 pub const NONE: Modifiers = Modifiers {
33 shift: false,
34 ctrl: false,
35 alt: false,
36 meta: false,
37 };
38
39 pub fn any(&self) -> bool {
41 self.shift || self.ctrl || self.alt || self.meta
42 }
43
44 pub fn command_or_ctrl(&self) -> bool {
46 #[cfg(target_os = "macos")]
47 {
48 self.meta
49 }
50 #[cfg(not(target_os = "macos"))]
51 {
52 self.ctrl
53 }
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62pub enum KeyCode {
63 A,
65 B,
66 C,
67 D,
68 E,
69 F,
70 G,
71 H,
72 I,
73 J,
74 K,
75 L,
76 M,
77 N,
78 O,
79 P,
80 Q,
81 R,
82 S,
83 T,
84 U,
85 V,
86 W,
87 X,
88 Y,
89 Z,
90
91 Digit0,
93 Digit1,
94 Digit2,
95 Digit3,
96 Digit4,
97 Digit5,
98 Digit6,
99 Digit7,
100 Digit8,
101 Digit9,
102
103 F1,
105 F2,
106 F3,
107 F4,
108 F5,
109 F6,
110 F7,
111 F8,
112 F9,
113 F10,
114 F11,
115 F12,
116
117 ArrowUp,
119 ArrowDown,
120 ArrowLeft,
121 ArrowRight,
122 Home,
123 End,
124 PageUp,
125 PageDown,
126
127 Backspace,
129 Delete,
130 Enter,
131 Tab,
132 Space,
133 Escape,
134
135 ShiftLeft,
137 ShiftRight,
138 ControlLeft,
139 ControlRight,
140 AltLeft,
141 AltRight,
142 MetaLeft,
143 MetaRight,
144
145 Minus,
147 Equal,
148 BracketLeft,
149 BracketRight,
150 Backslash,
151 Semicolon,
152 Quote,
153 Comma,
154 Period,
155 Slash,
156 Backquote,
157
158 Unknown,
160}
161
162#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct KeyEvent {
168 pub key_code: KeyCode,
170 pub text: String,
173 pub modifiers: Modifiers,
175 pub event_type: KeyEventType,
177}
178
179impl KeyEvent {
180 pub fn new(
182 key_code: KeyCode,
183 text: impl Into<String>,
184 modifiers: Modifiers,
185 event_type: KeyEventType,
186 ) -> Self {
187 Self {
188 key_code,
189 text: text.into(),
190 modifiers,
191 event_type,
192 }
193 }
194
195 pub fn key_down(key_code: KeyCode, text: impl Into<String>) -> Self {
197 Self::new(key_code, text, Modifiers::NONE, KeyEventType::KeyDown)
198 }
199
200 pub fn key_down_with_modifiers(
202 key_code: KeyCode,
203 text: impl Into<String>,
204 modifiers: Modifiers,
205 ) -> Self {
206 Self::new(key_code, text, modifiers, KeyEventType::KeyDown)
207 }
208
209 pub fn is_key_down(&self) -> bool {
211 self.event_type == KeyEventType::KeyDown
212 }
213
214 pub fn is_key_up(&self) -> bool {
216 self.event_type == KeyEventType::KeyUp
217 }
218
219 pub fn has_text(&self) -> bool {
221 !self.text.is_empty()
222 }
223}
224
225impl fmt::Display for KeyEvent {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 write!(
228 f,
229 "KeyEvent({:?}, text=\"{}\", {:?})",
230 self.key_code, self.text, self.event_type
231 )
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn key_event_creation() {
241 let event = KeyEvent::key_down(KeyCode::A, "a");
242 assert_eq!(event.key_code, KeyCode::A);
243 assert_eq!(event.text, "a");
244 assert!(event.is_key_down());
245 assert!(event.has_text());
246 }
247
248 #[test]
249 fn key_event_with_modifiers() {
250 let modifiers = Modifiers {
251 shift: true,
252 ctrl: false,
253 alt: false,
254 meta: false,
255 };
256 let event = KeyEvent::key_down_with_modifiers(KeyCode::A, "A", modifiers);
257 assert_eq!(event.text, "A");
258 assert!(event.modifiers.shift);
259 }
260
261 #[test]
262 fn backspace_has_no_text() {
263 let event = KeyEvent::key_down(KeyCode::Backspace, "");
264 assert!(!event.has_text());
265 }
266
267 #[test]
268 fn modifiers_any() {
269 assert!(!Modifiers::NONE.any());
270 assert!(Modifiers {
271 shift: true,
272 ..Modifiers::NONE
273 }
274 .any());
275 }
276}