1use crossterm::event::{self, KeyModifiers};
2use serde::{Deserialize, Serialize};
3use serde_json::{Map, Value};
4use std::fmt::{self, Display, Formatter};
5
6#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug, Serialize, Deserialize)]
7pub enum Key {
8 Alt(char),
9 AltShift(char),
10 AltBackspace,
11 AltDelete,
12 BackTab,
13 Backspace,
14 Char(char),
15 Ctrl(char),
16 CtrlAlt(char),
17 CtrlShift(char),
18 CtrlShiftRight,
19 CtrlShiftLeft,
20 CtrlShiftUp,
21 CtrlShiftDown,
22 CtrlAltShift(char),
23 CtrlAltDown,
24 CtrlAltShiftDown,
25 CtrlAltLeft,
26 CtrlAltShiftLeft,
27 CtrlAltRight,
28 CtrlAltShiftRight,
29 CtrlAltUp,
30 CtrlAltShiftUp,
31 CtrlDown,
32 CtrlLeft,
33 CtrlRight,
34 CtrlUp,
35 Delete,
36 Down,
37 End,
38 Enter,
39 Esc,
40 F0,
41 F1,
42 F10,
43 F11,
44 F12,
45 F2,
46 F3,
47 F4,
48 F5,
49 F6,
50 F7,
51 F8,
52 F9,
53 Home,
54 Ins,
55 Left,
56 PageDown,
57 ShiftPageDown,
58 PageUp,
59 ShiftPageUp,
60 Right,
61 ShiftHome,
62 ShiftEnd,
63 ShiftDown,
64 ShiftLeft,
65 ShiftRight,
66 ShiftUp,
67 Space,
68 Tab,
69 Unknown,
70 Up,
71}
72
73impl Key {
74 pub fn from_f(n: u8) -> Key {
75 match n {
76 0 => Key::F0,
77 1 => Key::F1,
78 2 => Key::F2,
79 3 => Key::F3,
80 4 => Key::F4,
81 5 => Key::F5,
82 6 => Key::F6,
83 7 => Key::F7,
84 8 => Key::F8,
85 9 => Key::F9,
86 10 => Key::F10,
87 11 => Key::F11,
88 12 => Key::F12,
89 _ => {
90 log::warn!("Unknown Function key: F{}", n);
91 Key::Unknown
92 }
93 }
94 }
95}
96
97impl Display for Key {
98 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
99 match *self {
100 Key::Alt(c) => write!(f, "<Alt+{}>", c),
101 Key::AltBackspace => write!(f, "<Alt+Backspace>"),
102 Key::AltDelete => write!(f, "<Alt+Delete>"),
103 Key::BackTab => write!(f, "<Shift+Tab>"),
104 Key::Backspace => write!(f, "<Backspace>"),
105 Key::Char(c) => write!(f, "<{}>", c),
106 Key::Ctrl(c) => write!(f, "<Ctrl+{}>", c),
107 Key::CtrlAlt(c) => write!(f, "<Ctrl+Alt+{}>", c),
108 Key::CtrlAltDown => write!(f, "<Ctrl+Alt+Down>"),
109 Key::CtrlAltLeft => write!(f, "<Ctrl+Alt+Left>"),
110 Key::CtrlAltRight => write!(f, "<Ctrl+Alt+Right>"),
111 Key::CtrlAltUp => write!(f, "<Ctrl+Alt+Up>"),
112 Key::CtrlDown => write!(f, "<Ctrl+Down>"),
113 Key::CtrlLeft => write!(f, "<Ctrl+Left>"),
114 Key::CtrlRight => write!(f, "<Ctrl+Right>"),
115 Key::CtrlUp => write!(f, "<Ctrl+Up>"),
116 Key::Delete => write!(f, "<Delete>"),
117 Key::Down => write!(f, "<Down>"),
118 Key::End => write!(f, "<End>"),
119 Key::Enter => write!(f, "<Enter>"),
120 Key::Esc => write!(f, "<Esc>"),
121 Key::Home => write!(f, "<Home>"),
122 Key::Ins => write!(f, "<Ins>"),
123 Key::Left => write!(f, "<Left>"),
124 Key::PageDown => write!(f, "<PageDown>"),
125 Key::PageUp => write!(f, "<PageUp>"),
126 Key::Right => write!(f, "<Right>"),
127 Key::ShiftDown => write!(f, "<Shift+Down>"),
128 Key::ShiftLeft => write!(f, "<Shift+Left>"),
129 Key::ShiftRight => write!(f, "<Shift+Right>"),
130 Key::ShiftUp => write!(f, "<Shift+Up>"),
131 Key::Space => write!(f, "<Space>"),
132 Key::Tab => write!(f, "<Tab>"),
133 Key::Unknown => write!(f, "<Unknown>"),
134 Key::Up => write!(f, "<Up>"),
135 _ => write!(f, "<{:?}>", self),
136 }
137 }
138}
139
140impl From<event::KeyEvent> for Key {
141 fn from(key_event: event::KeyEvent) -> Self {
142 let ctrl = key_event.modifiers.contains(KeyModifiers::CONTROL);
143 let alt = key_event.modifiers.contains(KeyModifiers::ALT);
144 let shift = key_event.modifiers.contains(KeyModifiers::SHIFT);
145 match key_event {
146 event::KeyEvent {
147 code: event::KeyCode::Esc,
148 kind: event::KeyEventKind::Press,
149 ..
150 } => Key::Esc,
151 event::KeyEvent {
152 code: event::KeyCode::Backspace,
153 kind: event::KeyEventKind::Press,
154 ..
155 } => {
156 if alt {
157 Key::AltBackspace
158 } else {
159 Key::Backspace
160 }
161 }
162 event::KeyEvent {
163 code: event::KeyCode::Up,
164 kind: event::KeyEventKind::Press,
165 ..
166 } => {
167 if ctrl && alt {
168 Key::CtrlAltUp
169 } else if ctrl {
170 Key::CtrlUp
171 } else if shift {
172 Key::ShiftUp
173 } else {
174 Key::Up
175 }
176 }
177 event::KeyEvent {
178 code: event::KeyCode::Down,
179 kind: event::KeyEventKind::Press,
180 ..
181 } => {
182 if ctrl && alt {
183 Key::CtrlAltDown
184 } else if ctrl {
185 Key::CtrlDown
186 } else if shift {
187 Key::ShiftDown
188 } else {
189 Key::Down
190 }
191 }
192 event::KeyEvent {
193 code: event::KeyCode::Left,
194 kind: event::KeyEventKind::Press,
195 ..
196 } => {
197 if ctrl && alt {
198 Key::CtrlAltLeft
199 } else if ctrl {
200 Key::CtrlLeft
201 } else if shift {
202 Key::ShiftLeft
203 } else {
204 Key::Left
205 }
206 }
207 event::KeyEvent {
208 code: event::KeyCode::Right,
209 kind: event::KeyEventKind::Press,
210 ..
211 } => {
212 if ctrl && alt {
213 Key::CtrlAltRight
214 } else if ctrl {
215 Key::CtrlRight
216 } else if shift {
217 Key::ShiftRight
218 } else {
219 Key::Right
220 }
221 }
222 event::KeyEvent {
223 code: event::KeyCode::Delete,
224 kind: event::KeyEventKind::Press,
225 ..
226 } => {
227 if alt {
228 Key::AltDelete
229 } else {
230 Key::Delete
231 }
232 }
233 event::KeyEvent {
234 code: event::KeyCode::Home,
235 kind: event::KeyEventKind::Press,
236 ..
237 } => Key::Home,
238 event::KeyEvent {
239 code: event::KeyCode::End,
240 kind: event::KeyEventKind::Press,
241 ..
242 } => Key::End,
243 event::KeyEvent {
244 code: event::KeyCode::PageUp,
245 kind: event::KeyEventKind::Press,
246 ..
247 } => Key::PageUp,
248 event::KeyEvent {
249 code: event::KeyCode::PageDown,
250 kind: event::KeyEventKind::Press,
251 ..
252 } => Key::PageDown,
253 event::KeyEvent {
254 code: event::KeyCode::Insert,
255 kind: event::KeyEventKind::Press,
256 ..
257 } => Key::Ins,
258 event::KeyEvent {
259 code: event::KeyCode::F(n),
260 kind: event::KeyEventKind::Press,
261 ..
262 } => Key::from_f(n),
263 event::KeyEvent {
264 code: event::KeyCode::Enter,
265 kind: event::KeyEventKind::Press,
266 ..
267 } => Key::Enter,
268 event::KeyEvent {
269 code: event::KeyCode::BackTab,
270 kind: event::KeyEventKind::Press,
271 ..
272 } => Key::BackTab,
273 event::KeyEvent {
274 code: event::KeyCode::Tab,
275 kind: event::KeyEventKind::Press,
276 ..
277 } => Key::Tab,
278 event::KeyEvent {
279 code: event::KeyCode::Char(c),
280 kind: event::KeyEventKind::Press,
281 ..
282 } => {
283 if ctrl && alt {
284 Key::CtrlAlt(c)
285 } else if ctrl {
286 Key::Ctrl(c)
287 } else if alt {
288 Key::Alt(c)
289 } else if shift {
290 Key::Char(c.to_ascii_uppercase())
291 } else {
292 Key::Char(c)
293 }
294 }
295 _ => Key::Unknown,
296 }
297 }
298}
299
300impl From<&str> for Key {
301 fn from(s: &str) -> Self {
302 if s.len() == 1 {
304 return Key::Char(s.chars().next().unwrap());
305 }
306 if s.len() == 6 && s.starts_with("<Alt+") && s.ends_with('>') {
308 return Key::Alt(s.chars().nth(5).unwrap());
309 }
310 if s.len() == 7 && s.starts_with("<Ctrl+") && s.ends_with('>') {
312 return Key::Ctrl(s.chars().nth(6).unwrap());
313 }
314 if s.len() == 10 && s.starts_with("<Ctrl+Alt+") && s.ends_with('>') {
316 return Key::CtrlAlt(s.chars().nth(9).unwrap());
317 }
318 match s {
319 "<Alt+Backspace>" => Key::AltBackspace,
320 "<Alt+Delete>" => Key::AltDelete,
321 "<Backspace>" => Key::Backspace,
322 "<Ctrl+Alt+Down>" => Key::CtrlAltDown,
323 "<Ctrl+Alt+Left>" => Key::CtrlAltLeft,
324 "<Ctrl+Alt+Right>" => Key::CtrlAltRight,
325 "<Ctrl+Alt+Up>" => Key::CtrlAltUp,
326 "<Ctrl+Down>" => Key::CtrlDown,
327 "<Ctrl+Left>" => Key::CtrlLeft,
328 "<Ctrl+Right>" => Key::CtrlRight,
329 "<Ctrl+Up>" => Key::CtrlUp,
330 "<Delete>" => Key::Delete,
331 "<Down>" => Key::Down,
332 "<End>" => Key::End,
333 "<Enter>" => Key::Enter,
334 "<Esc>" => Key::Esc,
335 "<Home>" => Key::Home,
336 "<Ins>" => Key::Ins,
337 "<Left>" => Key::Left,
338 "<PageDown>" => Key::PageDown,
339 "<PageUp>" => Key::PageUp,
340 "<Right>" => Key::Right,
341 "<Shift+Down>" => Key::ShiftDown,
342 "<Shift+Left>" => Key::ShiftLeft,
343 "<Shift+Right>" => Key::ShiftRight,
344 "<Shift+Up>" => Key::ShiftUp,
345 "<Space>" => Key::Space,
346 "<Tab>" => Key::Tab,
347 "<Unknown>" => Key::Unknown,
348 "<Up>" => Key::Up,
349 _ => Key::Unknown,
350 }
351 }
352}
353
354impl From<&Map<String, Value>> for Key {
355 fn from(value: &Map<String, Value>) -> Self {
357 fn char_from_value(val: &Value) -> char {
358 val.as_str().and_then(|s| s.chars().next()).unwrap()
359 }
360 if let Some(char_value) = value.get("Char") {
361 Key::Char(char_from_value(char_value))
362 } else if let Some(alt_value) = value.get("Alt") {
363 Key::Alt(char_from_value(alt_value))
364 } else if let Some(ctrl_value) = value.get("Ctrl") {
365 Key::Ctrl(char_from_value(ctrl_value))
366 } else {
367 Key::Unknown
368 }
369 }
370}