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 has_text(&self) -> bool {
216 !self.text.is_empty()
217 }
218}
219
220impl fmt::Display for KeyEvent {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 write!(
223 f,
224 "KeyEvent({:?}, text=\"{}\", {:?})",
225 self.key_code, self.text, self.event_type
226 )
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn key_event_creation() {
236 let event = KeyEvent::key_down(KeyCode::A, "a");
237 assert_eq!(event.key_code, KeyCode::A);
238 assert_eq!(event.text, "a");
239 assert!(event.is_key_down());
240 assert!(event.has_text());
241 }
242
243 #[test]
244 fn key_event_with_modifiers() {
245 let modifiers = Modifiers {
246 shift: true,
247 ctrl: false,
248 alt: false,
249 meta: false,
250 };
251 let event = KeyEvent::key_down_with_modifiers(KeyCode::A, "A", modifiers);
252 assert_eq!(event.text, "A");
253 assert!(event.modifiers.shift);
254 }
255
256 #[test]
257 fn backspace_has_no_text() {
258 let event = KeyEvent::key_down(KeyCode::Backspace, "");
259 assert!(!event.has_text());
260 }
261
262 #[test]
263 fn modifiers_any() {
264 assert!(!Modifiers::NONE.any());
265 assert!(Modifiers {
266 shift: true,
267 ..Modifiers::NONE
268 }
269 .any());
270 }
271}