1use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::str::FromStr;
6
7use crate::error::{Error, Result};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[non_exhaustive]
12pub enum Key {
13 A,
15 B,
16 C,
17 D,
18 E,
19 F,
20 G,
21 H,
22 I,
23 J,
24 K,
25 L,
26 M,
27 N,
28 O,
29 P,
30 Q,
31 R,
32 S,
33 T,
34 U,
35 V,
36 W,
37 X,
38 Y,
39 Z,
40
41 Num0,
43 Num1,
44 Num2,
45 Num3,
46 Num4,
47 Num5,
48 Num6,
49 Num7,
50 Num8,
51 Num9,
52
53 PlayPause,
55 Stop,
56 PrevTrack,
57 NextTrack,
58
59 F1,
61 F2,
62 F3,
63 F4,
64 F5,
65 F6,
66 F7,
67 F8,
68 F9,
69 F10,
70 F11,
71 F12,
72 F13,
73 F14,
74 F15,
75 F16,
76 F17,
77 F18,
78 F19,
79 F20,
80 F21,
83 F22,
84 F23,
85 F24,
86
87 Space,
89 Return,
90 Tab,
91 Escape,
92 Delete,
93 ForwardDelete,
94 Insert,
95 Pause,
107 Home,
108 End,
109 PageUp,
110 PageDown,
111
112 LeftArrow,
114 RightArrow,
115 UpArrow,
116 DownArrow,
117
118 Minus,
120 Equal,
121 LeftBracket,
122 RightBracket,
123 Backslash,
124 Semicolon,
125 Quote,
126 Comma,
127 Period,
128 Slash,
129 Grave,
130 Section,
131 JisYen,
133 JisUnderscore,
134 JisEisu,
135 JisKana,
136
137 Keypad0,
139 Keypad1,
140 Keypad2,
141 Keypad3,
142 Keypad4,
143 Keypad5,
144 Keypad6,
145 Keypad7,
146 Keypad8,
147 Keypad9,
148 KeypadDecimal,
149 KeypadMultiply,
150 KeypadPlus,
151 KeypadClear,
152 KeypadDivide,
153 KeypadEnter,
154 KeypadMinus,
155 KeypadEquals,
156 KeypadComma,
157
158 CapsLock,
160 ScrollLock,
161 NumLock,
162
163 PrintScreen,
167
168 ContextMenu,
172
173 Dictation,
186
187 MouseLeft,
189 MouseRight,
190 MouseMiddle,
191 MouseX1,
193 MouseX2,
195}
196
197impl fmt::Display for Key {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 match self {
200 Key::A => write!(f, "A"),
201 Key::B => write!(f, "B"),
202 Key::C => write!(f, "C"),
203 Key::D => write!(f, "D"),
204 Key::E => write!(f, "E"),
205 Key::F => write!(f, "F"),
206 Key::G => write!(f, "G"),
207 Key::H => write!(f, "H"),
208 Key::I => write!(f, "I"),
209 Key::J => write!(f, "J"),
210 Key::K => write!(f, "K"),
211 Key::L => write!(f, "L"),
212 Key::M => write!(f, "M"),
213 Key::N => write!(f, "N"),
214 Key::O => write!(f, "O"),
215 Key::P => write!(f, "P"),
216 Key::Q => write!(f, "Q"),
217 Key::R => write!(f, "R"),
218 Key::S => write!(f, "S"),
219 Key::T => write!(f, "T"),
220 Key::U => write!(f, "U"),
221 Key::V => write!(f, "V"),
222 Key::W => write!(f, "W"),
223 Key::X => write!(f, "X"),
224 Key::Y => write!(f, "Y"),
225 Key::Z => write!(f, "Z"),
226 Key::Num0 => write!(f, "0"),
227 Key::Num1 => write!(f, "1"),
228 Key::Num2 => write!(f, "2"),
229 Key::Num3 => write!(f, "3"),
230 Key::Num4 => write!(f, "4"),
231 Key::Num5 => write!(f, "5"),
232 Key::Num6 => write!(f, "6"),
233 Key::Num7 => write!(f, "7"),
234 Key::Num8 => write!(f, "8"),
235 Key::Num9 => write!(f, "9"),
236 Key::PlayPause => write!(f, "PlayPause"),
237 Key::Stop => write!(f, "Stop"),
238 Key::PrevTrack => write!(f, "PrevTrack"),
239 Key::NextTrack => write!(f, "NextTrack"),
240 Key::F1 => write!(f, "F1"),
241 Key::F2 => write!(f, "F2"),
242 Key::F3 => write!(f, "F3"),
243 Key::F4 => write!(f, "F4"),
244 Key::F5 => write!(f, "F5"),
245 Key::F6 => write!(f, "F6"),
246 Key::F7 => write!(f, "F7"),
247 Key::F8 => write!(f, "F8"),
248 Key::F9 => write!(f, "F9"),
249 Key::F10 => write!(f, "F10"),
250 Key::F11 => write!(f, "F11"),
251 Key::F12 => write!(f, "F12"),
252 Key::F13 => write!(f, "F13"),
253 Key::F14 => write!(f, "F14"),
254 Key::F15 => write!(f, "F15"),
255 Key::F16 => write!(f, "F16"),
256 Key::F17 => write!(f, "F17"),
257 Key::F18 => write!(f, "F18"),
258 Key::F19 => write!(f, "F19"),
259 Key::F20 => write!(f, "F20"),
260 Key::F21 => write!(f, "F21"),
261 Key::F22 => write!(f, "F22"),
262 Key::F23 => write!(f, "F23"),
263 Key::F24 => write!(f, "F24"),
264 Key::Space => write!(f, "Space"),
265 Key::Return => write!(f, "Return"),
266 Key::Tab => write!(f, "Tab"),
267 Key::Escape => write!(f, "Escape"),
268 Key::Delete => write!(f, "Delete"),
269 Key::ForwardDelete => write!(f, "ForwardDelete"),
270 Key::Insert => write!(f, "Insert"),
271 Key::Pause => write!(f, "Pause"),
272 Key::Home => write!(f, "Home"),
273 Key::End => write!(f, "End"),
274 Key::PageUp => write!(f, "PageUp"),
275 Key::PageDown => write!(f, "PageDown"),
276 Key::LeftArrow => write!(f, "Left"),
277 Key::RightArrow => write!(f, "Right"),
278 Key::UpArrow => write!(f, "Up"),
279 Key::DownArrow => write!(f, "Down"),
280 Key::Minus => write!(f, "-"),
281 Key::Equal => write!(f, "="),
282 Key::LeftBracket => write!(f, "["),
283 Key::RightBracket => write!(f, "]"),
284 Key::Backslash => write!(f, "\\"),
285 Key::Semicolon => write!(f, ";"),
286 Key::Quote => write!(f, "'"),
287 Key::Comma => write!(f, ","),
288 Key::Period => write!(f, "."),
289 Key::Slash => write!(f, "/"),
290 Key::Grave => write!(f, "`"),
291 Key::Section => write!(f, "§"),
292 Key::JisYen => write!(f, "¥"),
293 Key::JisUnderscore => write!(f, "JisUnderscore"),
294 Key::JisEisu => write!(f, "Eisu"),
295 Key::JisKana => write!(f, "Kana"),
296 Key::Keypad0 => write!(f, "Keypad0"),
297 Key::Keypad1 => write!(f, "Keypad1"),
298 Key::Keypad2 => write!(f, "Keypad2"),
299 Key::Keypad3 => write!(f, "Keypad3"),
300 Key::Keypad4 => write!(f, "Keypad4"),
301 Key::Keypad5 => write!(f, "Keypad5"),
302 Key::Keypad6 => write!(f, "Keypad6"),
303 Key::Keypad7 => write!(f, "Keypad7"),
304 Key::Keypad8 => write!(f, "Keypad8"),
305 Key::Keypad9 => write!(f, "Keypad9"),
306 Key::KeypadDecimal => write!(f, "KeypadDecimal"),
307 Key::KeypadMultiply => write!(f, "KeypadMultiply"),
308 Key::KeypadPlus => write!(f, "KeypadPlus"),
309 Key::KeypadClear => write!(f, "KeypadClear"),
310 Key::KeypadDivide => write!(f, "KeypadDivide"),
311 Key::KeypadEnter => write!(f, "KeypadEnter"),
312 Key::KeypadMinus => write!(f, "KeypadMinus"),
313 Key::KeypadEquals => write!(f, "KeypadEquals"),
314 Key::KeypadComma => write!(f, "KeypadComma"),
315 Key::CapsLock => write!(f, "CapsLock"),
316 Key::ScrollLock => write!(f, "ScrollLock"),
317 Key::NumLock => write!(f, "NumLock"),
318 Key::PrintScreen => write!(f, "PrintScreen"),
319 Key::ContextMenu => write!(f, "ContextMenu"),
320 Key::MouseLeft => write!(f, "MouseLeft"),
321 Key::MouseRight => write!(f, "MouseRight"),
322 Key::MouseMiddle => write!(f, "MouseMiddle"),
323 Key::MouseX1 => write!(f, "MouseX1"),
324 Key::MouseX2 => write!(f, "MouseX2"),
325 Key::Dictation => write!(f, "Dictation"),
326 }
327 }
328}
329
330impl FromStr for Key {
331 type Err = Error;
332
333 fn from_str(s: &str) -> Result<Self> {
335 let s = s.trim();
336 match s.to_lowercase().as_str() {
337 "a" => Ok(Key::A),
339 "b" => Ok(Key::B),
340 "c" => Ok(Key::C),
341 "d" => Ok(Key::D),
342 "e" => Ok(Key::E),
343 "f" => Ok(Key::F),
344 "g" => Ok(Key::G),
345 "h" => Ok(Key::H),
346 "i" => Ok(Key::I),
347 "j" => Ok(Key::J),
348 "k" => Ok(Key::K),
349 "l" => Ok(Key::L),
350 "m" => Ok(Key::M),
351 "n" => Ok(Key::N),
352 "o" => Ok(Key::O),
353 "p" => Ok(Key::P),
354 "q" => Ok(Key::Q),
355 "r" => Ok(Key::R),
356 "s" => Ok(Key::S),
357 "t" => Ok(Key::T),
358 "u" => Ok(Key::U),
359 "v" => Ok(Key::V),
360 "w" => Ok(Key::W),
361 "x" => Ok(Key::X),
362 "y" => Ok(Key::Y),
363 "z" => Ok(Key::Z),
364
365 "0" | "num0" => Ok(Key::Num0),
367 "1" | "num1" => Ok(Key::Num1),
368 "2" | "num2" => Ok(Key::Num2),
369 "3" | "num3" => Ok(Key::Num3),
370 "4" | "num4" => Ok(Key::Num4),
371 "5" | "num5" => Ok(Key::Num5),
372 "6" | "num6" => Ok(Key::Num6),
373 "7" | "num7" => Ok(Key::Num7),
374 "8" | "num8" => Ok(Key::Num8),
375 "9" | "num9" => Ok(Key::Num9),
376
377 "playpause" => Ok(Key::PlayPause),
379 "stop" => Ok(Key::Stop),
380 "prevtrack" => Ok(Key::PrevTrack),
381 "nexttrack" => Ok(Key::NextTrack),
382
383 "f1" => Ok(Key::F1),
385 "f2" => Ok(Key::F2),
386 "f3" => Ok(Key::F3),
387 "f4" => Ok(Key::F4),
388 "f5" => Ok(Key::F5),
389 "f6" => Ok(Key::F6),
390 "f7" => Ok(Key::F7),
391 "f8" => Ok(Key::F8),
392 "f9" => Ok(Key::F9),
393 "f10" => Ok(Key::F10),
394 "f11" => Ok(Key::F11),
395 "f12" => Ok(Key::F12),
396 "f13" => Ok(Key::F13),
397 "f14" => Ok(Key::F14),
398 "f15" => Ok(Key::F15),
399 "f16" => Ok(Key::F16),
400 "f17" => Ok(Key::F17),
401 "f18" => Ok(Key::F18),
402 "f19" => Ok(Key::F19),
403 "f20" => Ok(Key::F20),
404 "f21" => Ok(Key::F21),
405 "f22" => Ok(Key::F22),
406 "f23" => Ok(Key::F23),
407 "f24" => Ok(Key::F24),
408
409 "space" | " " => Ok(Key::Space),
411 "return" | "enter" => Ok(Key::Return),
412 "tab" => Ok(Key::Tab),
413 "escape" | "esc" => Ok(Key::Escape),
414 "delete" | "backspace" => Ok(Key::Delete),
415 "forwarddelete" | "del" => Ok(Key::ForwardDelete),
416 "insert" | "ins" => Ok(Key::Insert),
417 "pause" | "break" => Ok(Key::Pause),
418 "home" => Ok(Key::Home),
419 "end" => Ok(Key::End),
420 "pageup" => Ok(Key::PageUp),
421 "pagedown" => Ok(Key::PageDown),
422
423 "left" | "leftarrow" => Ok(Key::LeftArrow),
425 "right" | "rightarrow" => Ok(Key::RightArrow),
426 "up" | "uparrow" => Ok(Key::UpArrow),
427 "down" | "downarrow" => Ok(Key::DownArrow),
428
429 "-" | "minus" => Ok(Key::Minus),
431 "=" | "equal" | "equals" => Ok(Key::Equal),
432 "[" | "leftbracket" => Ok(Key::LeftBracket),
433 "]" | "rightbracket" => Ok(Key::RightBracket),
434 "\\" | "backslash" => Ok(Key::Backslash),
435 ";" | "semicolon" => Ok(Key::Semicolon),
436 "'" | "quote" => Ok(Key::Quote),
437 "," | "comma" => Ok(Key::Comma),
438 "." | "period" => Ok(Key::Period),
439 "/" | "slash" => Ok(Key::Slash),
440 "`" | "grave" | "backtick" => Ok(Key::Grave),
441 "§" | "section" => Ok(Key::Section),
442 "¥" | "jisyen" | "yen" => Ok(Key::JisYen),
443 "jisunderscore" => Ok(Key::JisUnderscore),
444 "eisu" | "jiseisu" | "英数" => Ok(Key::JisEisu),
445 "kana" | "jiskana" | "かな" => Ok(Key::JisKana),
446
447 "keypad0" => Ok(Key::Keypad0),
449 "keypad1" => Ok(Key::Keypad1),
450 "keypad2" => Ok(Key::Keypad2),
451 "keypad3" => Ok(Key::Keypad3),
452 "keypad4" => Ok(Key::Keypad4),
453 "keypad5" => Ok(Key::Keypad5),
454 "keypad6" => Ok(Key::Keypad6),
455 "keypad7" => Ok(Key::Keypad7),
456 "keypad8" => Ok(Key::Keypad8),
457 "keypad9" => Ok(Key::Keypad9),
458 "keypad." | "keypaddecimal" => Ok(Key::KeypadDecimal),
459 "keypad*" | "keypadmultiply" => Ok(Key::KeypadMultiply),
460 "keypad+" | "keypadplus" => Ok(Key::KeypadPlus),
461 "keypadclear" => Ok(Key::KeypadClear),
462 "keypad/" | "keypaddivide" => Ok(Key::KeypadDivide),
463 "keypadenter" => Ok(Key::KeypadEnter),
464 "keypad-" | "keypadminus" => Ok(Key::KeypadMinus),
465 "keypad=" | "keypadequals" => Ok(Key::KeypadEquals),
466 "keypad," | "keypadcomma" => Ok(Key::KeypadComma),
467
468 "capslock" | "caps" => Ok(Key::CapsLock),
470 "scrolllock" | "scroll" => Ok(Key::ScrollLock),
471 "numlock" => Ok(Key::NumLock),
472
473 "printscreen" | "prtsc" | "sysrq" => Ok(Key::PrintScreen),
474 "contextmenu" | "menu" | "apps" | "application" => Ok(Key::ContextMenu),
475
476 "mouseleft" | "leftclick" | "lmb" | "mouse1" => Ok(Key::MouseLeft),
478 "mouseright" | "rightclick" | "rmb" | "mouse2" => Ok(Key::MouseRight),
479 "mousemiddle" | "middleclick" | "mmb" | "mouse3" => Ok(Key::MouseMiddle),
480 "mousex1" | "mouse4" | "back" | "xbutton1" => Ok(Key::MouseX1),
481 "mousex2" | "mouse5" | "forward" | "xbutton2" => Ok(Key::MouseX2),
482
483 "dictation" | "voice" | "globe" => Ok(Key::Dictation),
487
488 _ => Err(Error::UnknownKey(s.to_string())),
489 }
490 }
491}
492
493#[cfg(test)]
494mod tests {
495 use super::*;
496
497 #[test]
498 fn parse_letters() {
499 assert_eq!("a".parse::<Key>().unwrap(), Key::A);
500 assert_eq!("A".parse::<Key>().unwrap(), Key::A);
501 assert_eq!("z".parse::<Key>().unwrap(), Key::Z);
502 }
503
504 #[test]
505 fn parse_numbers() {
506 assert_eq!("0".parse::<Key>().unwrap(), Key::Num0);
507 assert_eq!("9".parse::<Key>().unwrap(), Key::Num9);
508 assert_eq!("num5".parse::<Key>().unwrap(), Key::Num5);
509 }
510
511 #[test]
512 fn parse_function_keys() {
513 assert_eq!("F1".parse::<Key>().unwrap(), Key::F1);
514 assert_eq!("f12".parse::<Key>().unwrap(), Key::F12);
515 assert_eq!("F20".parse::<Key>().unwrap(), Key::F20);
516 assert_eq!("f21".parse::<Key>().unwrap(), Key::F21);
517 assert_eq!("F24".parse::<Key>().unwrap(), Key::F24);
518 }
519
520 #[test]
521 fn parse_special_keys() {
522 assert_eq!("Space".parse::<Key>().unwrap(), Key::Space);
523 assert_eq!("return".parse::<Key>().unwrap(), Key::Return);
524 assert_eq!("enter".parse::<Key>().unwrap(), Key::Return);
525 assert_eq!("Tab".parse::<Key>().unwrap(), Key::Tab);
526 assert_eq!("Escape".parse::<Key>().unwrap(), Key::Escape);
527 assert_eq!("esc".parse::<Key>().unwrap(), Key::Escape);
528 assert_eq!("Delete".parse::<Key>().unwrap(), Key::Delete);
529 assert_eq!("backspace".parse::<Key>().unwrap(), Key::Delete);
530 }
531
532 #[test]
533 fn parse_arrow_keys() {
534 assert_eq!("Left".parse::<Key>().unwrap(), Key::LeftArrow);
535 assert_eq!("leftarrow".parse::<Key>().unwrap(), Key::LeftArrow);
536 assert_eq!("Right".parse::<Key>().unwrap(), Key::RightArrow);
537 assert_eq!("Up".parse::<Key>().unwrap(), Key::UpArrow);
538 assert_eq!("Down".parse::<Key>().unwrap(), Key::DownArrow);
539 }
540
541 #[test]
542 fn parse_punctuation() {
543 assert_eq!("-".parse::<Key>().unwrap(), Key::Minus);
544 assert_eq!("minus".parse::<Key>().unwrap(), Key::Minus);
545 assert_eq!("=".parse::<Key>().unwrap(), Key::Equal);
546 assert_eq!("[".parse::<Key>().unwrap(), Key::LeftBracket);
547 assert_eq!("]".parse::<Key>().unwrap(), Key::RightBracket);
548 assert_eq!("/".parse::<Key>().unwrap(), Key::Slash);
549 assert_eq!("`".parse::<Key>().unwrap(), Key::Grave);
550 }
551
552 #[test]
553 fn parse_unknown_key_fails() {
554 assert!("unknown".parse::<Key>().is_err());
555 assert!("".parse::<Key>().is_err());
556 }
557
558 #[test]
559 fn key_display_roundtrip() {
560 let keys = [
562 Key::A,
563 Key::Z,
564 Key::Num0,
565 Key::Num9,
566 Key::F1,
567 Key::F12,
568 Key::F21,
569 Key::F22,
570 Key::F23,
571 Key::F24,
572 Key::Space,
573 Key::Return,
574 Key::Tab,
575 Key::Escape,
576 Key::Pause,
577 Key::LeftArrow,
578 Key::RightArrow,
579 Key::KeypadPlus,
580 Key::KeypadMinus,
581 Key::KeypadMultiply,
582 Key::KeypadDivide,
583 Key::KeypadDecimal,
584 Key::KeypadEquals,
585 Key::KeypadEnter,
586 Key::KeypadClear,
587 Key::KeypadComma,
588 Key::JisYen,
589 Key::JisUnderscore,
590 Key::JisEisu,
591 Key::JisKana,
592 Key::Dictation,
593 Key::PlayPause,
594 Key::Stop,
595 Key::PrevTrack,
596 Key::NextTrack,
597 Key::PrintScreen,
598 Key::ContextMenu,
599 ];
600 for key in keys {
601 let displayed = format!("{}", key);
602 let parsed: Key = displayed.parse().unwrap();
603 assert_eq!(parsed, key, "Roundtrip failed for {:?}", key);
604 }
605 }
606
607 #[test]
608 fn parse_dictation_aliases() {
609 assert_eq!("dictation".parse::<Key>().unwrap(), Key::Dictation);
610 assert_eq!("voice".parse::<Key>().unwrap(), Key::Dictation);
611 assert_eq!("globe".parse::<Key>().unwrap(), Key::Dictation);
612 assert!("fn".parse::<Key>().is_err());
614 }
615
616 #[test]
617 fn parse_printscreen_and_context_menu() {
618 assert_eq!("printscreen".parse::<Key>().unwrap(), Key::PrintScreen);
619 assert_eq!("prtsc".parse::<Key>().unwrap(), Key::PrintScreen);
620 assert_eq!("sysrq".parse::<Key>().unwrap(), Key::PrintScreen);
621 assert_eq!("contextmenu".parse::<Key>().unwrap(), Key::ContextMenu);
622 assert_eq!("menu".parse::<Key>().unwrap(), Key::ContextMenu);
623 assert_eq!("apps".parse::<Key>().unwrap(), Key::ContextMenu);
624 assert_eq!("application".parse::<Key>().unwrap(), Key::ContextMenu);
625 }
626
627 #[test]
628 fn parse_media_keys() {
629 assert_eq!("playpause".parse::<Key>().unwrap(), Key::PlayPause);
631 assert_eq!("PlayPause".parse::<Key>().unwrap(), Key::PlayPause);
632 assert_eq!("stop".parse::<Key>().unwrap(), Key::Stop);
633 assert_eq!("prevtrack".parse::<Key>().unwrap(), Key::PrevTrack);
634 assert_eq!("nexttrack".parse::<Key>().unwrap(), Key::NextTrack);
635 }
636
637 #[test]
638 fn parse_pause_aliases() {
639 assert_eq!("pause".parse::<Key>().unwrap(), Key::Pause);
641 assert_eq!("Pause".parse::<Key>().unwrap(), Key::Pause);
642 assert_eq!("break".parse::<Key>().unwrap(), Key::Pause);
643 assert_eq!("playpause".parse::<Key>().unwrap(), Key::PlayPause);
645 }
646}