1use super::ModifiersKey;
2use crate::error::HotkeyError;
3use std::{fmt::Display, hash::Hash};
4
5#[derive(Debug, Clone, Copy)]
20pub enum VirtualKey {
21 Back,
23 Backspace,
25 Tab,
27 Clear,
29 Return,
31 Shift,
33 Control,
35 Menu,
37 Pause,
39 Capital,
41 Escape,
43 Space,
45 Prior,
47 Next,
49 End,
51 Home,
53 Left,
55 Up,
57 Right,
59 Down,
61 Select,
63 Print,
65 Execute,
67 Snapshot,
69 Insert,
71 Delete,
73 Help,
75
76 LWin,
78 RWin,
80 Apps,
82 Sleep,
84 Numpad0,
86 Numpad1,
88 Numpad2,
90 Numpad3,
92 Numpad4,
94 Numpad5,
96 Numpad6,
98 Numpad7,
100 Numpad8,
102 Numpad9,
104 NumpadMultiply,
106 NumpadAdd,
108 Separator,
110 NumpadSubtract,
112 NumpadDecimal,
114 NumpadDivide,
116 F1,
118 F2,
120 F3,
122 F4,
124 F5,
126 F6,
128 F7,
130 F8,
132 F9,
134 F10,
136 F11,
138 F12,
140 F13,
142 F14,
144 F15,
146 F16,
148 F17,
150 F18,
152 F19,
154 F20,
156 F21,
158 F22,
160 F23,
162 F24,
164 Numlock,
166 Scroll,
168 LShift,
170 RShift,
172 LControl,
174 RControl,
176 LMenu,
178 RMenu,
180 BrowserBack,
182 BrowserForward,
184 BrowserRefresh,
186 BrowserStop,
188 BrowserSearch,
190 BrowserFavorites,
192 BrowserHome,
194 VolumeMute,
196 VolumeDown,
198 VolumeUp,
200 MediaNextTrack,
202 MediaPrevTrack,
204 MediaStop,
206 MediaPlayPause,
208 LaunchMail,
210 LaunchMediaSelect,
212 LaunchApp1,
214 LaunchApp2,
216 Semicolon,
219 Plus,
221 Comma,
223 Minus,
225 Period,
227 Slash,
230 Backquote,
233 BracketLeft,
236 Backslash,
239 BracketRight,
242 Quote,
245 Oem8,
247 Oem102,
249 Attn,
251 Crsel,
253 Exsel,
255 Play,
257 Zoom,
259 Pa1,
261 OemClear,
263
264 Vk0,
266 Vk1,
268 Vk2,
270 Vk3,
272 Vk4,
274 Vk5,
276 Vk6,
278 Vk7,
280 Vk8,
282 Vk9,
284
285 A,
287 B,
289 C,
291 D,
293 E,
295 F,
297 G,
299 H,
301 I,
303 J,
305 K,
307 L,
309 M,
311 N,
313 O,
315 P,
317 Q,
319 R,
321 S,
323 T,
325 U,
327 V,
329 W,
331 X,
333 Y,
335 Z,
337
338 CustomKeyCode(u16),
344}
345
346impl TryFrom<&str> for VirtualKey {
347 type Error = HotkeyError;
348 fn try_from(val: &str) -> Result<Self, Self::Error> {
349 Self::from_keyname(val)
350 }
351}
352
353impl TryFrom<char> for VirtualKey {
354 type Error = HotkeyError;
355 fn try_from(ch: char) -> Result<Self, Self::Error> {
356 match ch.to_ascii_uppercase() {
357 ch @ ('A'..='Z' | '0'..='9') => Ok(Self::CustomKeyCode(ch as u16)),
358 ch => Err(HotkeyError::InvalidKeyChar(ch)),
359 }
360 }
361}
362
363impl VirtualKey {
364 pub const fn from_char(ch: char) -> Result<Self, HotkeyError> {
368 match ch.to_ascii_uppercase() {
369 ch @ ('A'..='Z' | '0'..='9') => Ok(Self::CustomKeyCode(ch as u16)),
370 ch => Err(HotkeyError::InvalidKeyChar(ch)),
371 }
372 }
373
374 pub const fn to_vk_code(&self) -> u16 {
377 use windows_sys::Win32::UI::Input::KeyboardAndMouse::*;
378 match self {
379 VirtualKey::Back | VirtualKey::Backspace => VK_BACK,
380 VirtualKey::Tab => VK_TAB,
381 VirtualKey::Clear => VK_CLEAR,
382 VirtualKey::Return => VK_RETURN,
383 VirtualKey::Shift => VK_SHIFT,
384 VirtualKey::Control => VK_CONTROL,
385 VirtualKey::Menu => VK_MENU,
386 VirtualKey::Pause => VK_PAUSE,
387 VirtualKey::Capital => VK_CAPITAL,
388 VirtualKey::Escape => VK_ESCAPE,
389 VirtualKey::Space => VK_SPACE,
390 VirtualKey::Prior => VK_PRIOR,
391 VirtualKey::Next => VK_NEXT,
392 VirtualKey::End => VK_END,
393 VirtualKey::Home => VK_HOME,
394 VirtualKey::Left => VK_LEFT,
395 VirtualKey::Up => VK_UP,
396 VirtualKey::Right => VK_RIGHT,
397 VirtualKey::Down => VK_DOWN,
398 VirtualKey::Select => VK_SELECT,
399 VirtualKey::Print => VK_PRINT,
400 VirtualKey::Execute => VK_EXECUTE,
401 VirtualKey::Snapshot => VK_SNAPSHOT,
402 VirtualKey::Insert => VK_INSERT,
403 VirtualKey::Delete => VK_DELETE,
404 VirtualKey::Help => VK_HELP,
405 VirtualKey::LWin => VK_LWIN,
406 VirtualKey::RWin => VK_RWIN,
407 VirtualKey::Apps => VK_APPS,
408 VirtualKey::Sleep => VK_SLEEP,
409 VirtualKey::Numpad0 => VK_NUMPAD0,
410 VirtualKey::Numpad1 => VK_NUMPAD1,
411 VirtualKey::Numpad2 => VK_NUMPAD2,
412 VirtualKey::Numpad3 => VK_NUMPAD3,
413 VirtualKey::Numpad4 => VK_NUMPAD4,
414 VirtualKey::Numpad5 => VK_NUMPAD5,
415 VirtualKey::Numpad6 => VK_NUMPAD6,
416 VirtualKey::Numpad7 => VK_NUMPAD7,
417 VirtualKey::Numpad8 => VK_NUMPAD8,
418 VirtualKey::Numpad9 => VK_NUMPAD9,
419 VirtualKey::NumpadMultiply => VK_MULTIPLY,
420 VirtualKey::NumpadAdd => VK_ADD,
421 VirtualKey::Separator => VK_SEPARATOR,
422 VirtualKey::NumpadSubtract => VK_SUBTRACT,
423 VirtualKey::NumpadDecimal => VK_DECIMAL,
424 VirtualKey::NumpadDivide => VK_DIVIDE,
425 VirtualKey::F1 => VK_F1,
426 VirtualKey::F2 => VK_F2,
427 VirtualKey::F3 => VK_F3,
428 VirtualKey::F4 => VK_F4,
429 VirtualKey::F5 => VK_F5,
430 VirtualKey::F6 => VK_F6,
431 VirtualKey::F7 => VK_F7,
432 VirtualKey::F8 => VK_F8,
433 VirtualKey::F9 => VK_F9,
434 VirtualKey::F10 => VK_F10,
435 VirtualKey::F11 => VK_F11,
436 VirtualKey::F12 => VK_F12,
437 VirtualKey::F13 => VK_F13,
438 VirtualKey::F14 => VK_F14,
439 VirtualKey::F15 => VK_F15,
440 VirtualKey::F16 => VK_F16,
441 VirtualKey::F17 => VK_F17,
442 VirtualKey::F18 => VK_F18,
443 VirtualKey::F19 => VK_F19,
444 VirtualKey::F20 => VK_F20,
445 VirtualKey::F21 => VK_F21,
446 VirtualKey::F22 => VK_F22,
447 VirtualKey::F23 => VK_F23,
448 VirtualKey::F24 => VK_F24,
449 VirtualKey::Numlock => VK_NUMLOCK,
450 VirtualKey::Scroll => VK_SCROLL,
451 VirtualKey::LShift => VK_LSHIFT,
452 VirtualKey::RShift => VK_RSHIFT,
453 VirtualKey::LControl => VK_LCONTROL,
454 VirtualKey::RControl => VK_RCONTROL,
455 VirtualKey::LMenu => VK_LMENU,
456 VirtualKey::RMenu => VK_RMENU,
457 VirtualKey::BrowserBack => VK_BROWSER_BACK,
458 VirtualKey::BrowserForward => VK_BROWSER_FORWARD,
459 VirtualKey::BrowserRefresh => VK_BROWSER_REFRESH,
460 VirtualKey::BrowserStop => VK_BROWSER_STOP,
461 VirtualKey::BrowserSearch => VK_BROWSER_SEARCH,
462 VirtualKey::BrowserFavorites => VK_BROWSER_FAVORITES,
463 VirtualKey::BrowserHome => VK_BROWSER_HOME,
464 VirtualKey::VolumeMute => VK_VOLUME_MUTE,
465 VirtualKey::VolumeDown => VK_VOLUME_DOWN,
466 VirtualKey::VolumeUp => VK_VOLUME_UP,
467 VirtualKey::MediaNextTrack => VK_MEDIA_NEXT_TRACK,
468 VirtualKey::MediaPrevTrack => VK_MEDIA_PREV_TRACK,
469 VirtualKey::MediaStop => VK_MEDIA_STOP,
470 VirtualKey::MediaPlayPause => VK_MEDIA_PLAY_PAUSE,
471 VirtualKey::LaunchMail => VK_LAUNCH_MAIL,
472 VirtualKey::LaunchMediaSelect => VK_LAUNCH_MEDIA_SELECT,
473 VirtualKey::LaunchApp1 => VK_LAUNCH_APP1,
474 VirtualKey::LaunchApp2 => VK_LAUNCH_APP2,
475 VirtualKey::Semicolon => VK_OEM_1,
476 VirtualKey::Plus => VK_OEM_PLUS,
477 VirtualKey::Comma => VK_OEM_COMMA,
478 VirtualKey::Minus => VK_OEM_MINUS,
479 VirtualKey::Period => VK_OEM_PERIOD,
480 VirtualKey::Slash => VK_OEM_2,
481 VirtualKey::Backquote => VK_OEM_3,
482 VirtualKey::BracketLeft => VK_OEM_4,
483 VirtualKey::Backslash => VK_OEM_5,
484 VirtualKey::BracketRight => VK_OEM_6,
485 VirtualKey::Quote => VK_OEM_7,
486 VirtualKey::Oem8 => VK_OEM_8,
487 VirtualKey::Oem102 => VK_OEM_102,
488 VirtualKey::Attn => VK_ATTN,
489 VirtualKey::Crsel => VK_CRSEL,
490 VirtualKey::Exsel => VK_EXSEL,
491 VirtualKey::Play => VK_PLAY,
492 VirtualKey::Zoom => VK_ZOOM,
493 VirtualKey::Pa1 => VK_PA1,
494 VirtualKey::OemClear => VK_OEM_CLEAR,
495
496 VirtualKey::Vk0 => b'0' as u16,
497 VirtualKey::Vk1 => b'1' as u16,
498 VirtualKey::Vk2 => b'2' as u16,
499 VirtualKey::Vk3 => b'3' as u16,
500 VirtualKey::Vk4 => b'4' as u16,
501 VirtualKey::Vk5 => b'5' as u16,
502 VirtualKey::Vk6 => b'6' as u16,
503 VirtualKey::Vk7 => b'7' as u16,
504 VirtualKey::Vk8 => b'8' as u16,
505 VirtualKey::Vk9 => b'9' as u16,
506 VirtualKey::A => b'A' as u16,
507 VirtualKey::B => b'B' as u16,
508 VirtualKey::C => b'C' as u16,
509 VirtualKey::D => b'D' as u16,
510 VirtualKey::E => b'E' as u16,
511 VirtualKey::F => b'F' as u16,
512 VirtualKey::G => b'G' as u16,
513 VirtualKey::H => b'H' as u16,
514 VirtualKey::I => b'I' as u16,
515 VirtualKey::J => b'J' as u16,
516 VirtualKey::K => b'K' as u16,
517 VirtualKey::L => b'L' as u16,
518 VirtualKey::M => b'M' as u16,
519 VirtualKey::N => b'N' as u16,
520 VirtualKey::O => b'O' as u16,
521 VirtualKey::P => b'P' as u16,
522 VirtualKey::Q => b'Q' as u16,
523 VirtualKey::R => b'R' as u16,
524 VirtualKey::S => b'S' as u16,
525 VirtualKey::T => b'T' as u16,
526 VirtualKey::U => b'U' as u16,
527 VirtualKey::V => b'V' as u16,
528 VirtualKey::W => b'W' as u16,
529 VirtualKey::X => b'X' as u16,
530 VirtualKey::Y => b'Y' as u16,
531 VirtualKey::Z => b'Z' as u16,
532
533 VirtualKey::CustomKeyCode(vk) => *vk,
534 }
535 }
536
537 pub fn from_keyname(val: &str) -> Result<Self, HotkeyError> {
550 let val = val.to_ascii_uppercase();
551
552 if val.as_bytes().len() == 1 {
554 let val = val.as_bytes()[0];
555 if val.is_ascii_uppercase() || val.is_ascii_digit() {
556 return Ok(Self::CustomKeyCode(val as u16));
557 }
558 }
559
560 if val.len() >= 3 && val.len() <= 6 && val.starts_with("0x") || val.starts_with("0X") {
562 if let Ok(val) = u16::from_str_radix(&val[2..], 16) {
563 return Ok(Self::CustomKeyCode(val));
564 } else {
565 return Err(HotkeyError::InvalidKey(val));
566 }
567 }
568
569 Ok(match val.trim() {
571 "BACK" | "BACKSPACE" => Self::Back,
572 "TAB" => Self::Tab,
573 "CLEAR" => Self::Clear,
574 "RETURN" => Self::Return,
575 "SHIFT" => Self::Shift,
576 "CONTROL" | "CTRL" => Self::Control,
577 "MENU" | "ALT" => Self::Menu,
578 "PAUSE" => Self::Pause,
579 "CAPITAL" => Self::Capital,
580 "ESCAPE" | "ESC" => Self::Escape,
581 "SPACE" => Self::Space,
582 "PRIOR" => Self::Prior,
583 "NEXT" => Self::Next,
584 "END" => Self::End,
585 "HOME" => Self::Home,
586 "LEFT" => Self::Left,
587 "UP" => Self::Up,
588 "RIGHT" => Self::Right,
589 "DOWN" => Self::Down,
590 "SELECT" => Self::Select,
591 "PRINT" => Self::Print,
592 "EXECUTE" => Self::Execute,
593 "SNAPSHOT" => Self::Snapshot,
594 "INSERT" => Self::Insert,
595 "DELETE" => Self::Delete,
596 "HELP" => Self::Help,
597 "LWIN" => Self::LWin,
598 "RWIN" => Self::RWin,
599 "APPS" => Self::Apps,
600 "SLEEP" => Self::Sleep,
601 "NUMPAD0" | "NUM0" => Self::Numpad0,
602 "NUMPAD1" | "NUM1" => Self::Numpad1,
603 "NUMPAD2" | "NUM2" => Self::Numpad2,
604 "NUMPAD3" | "NUM3" => Self::Numpad3,
605 "NUMPAD4" | "NUM4" => Self::Numpad4,
606 "NUMPAD5" | "NUM5" => Self::Numpad5,
607 "NUMPAD6" | "NUM6" => Self::Numpad6,
608 "NUMPAD7" | "NUM7" => Self::Numpad7,
609 "NUMPAD8" | "NUM8" => Self::Numpad8,
610 "NUMPAD9" | "NUM9" => Self::Numpad9,
611 "NUMPADMULTIPLY" | "NUMMULTIPLY" => Self::NumpadMultiply,
612 "NUMPADADD" | "NUMADD" | "NUMPADPLUS" | "NUMPLUS" => Self::NumpadAdd,
613 "NUMPADSEPARATOR" | "NUMSEPARATOR" => Self::Separator,
614 "NUMPADSUBTRACT" | "NUMSUBTRACT" | "NUMPADMINUS" | "NUMMINUS" => Self::NumpadSubtract,
615 "NUMPADDECIMAL" | "NUMDECIMAL" => Self::NumpadDecimal,
616 "NUMPADDIVIDE" | "NUMDIVIDE" => Self::NumpadDivide,
617 "F1" => Self::F1,
618 "F2" => Self::F2,
619 "F3" => Self::F3,
620 "F4" => Self::F4,
621 "F5" => Self::F5,
622 "F6" => Self::F6,
623 "F7" => Self::F7,
624 "F8" => Self::F8,
625 "F9" => Self::F9,
626 "F10" => Self::F10,
627 "F11" => Self::F11,
628 "F12" => Self::F12,
629 "F13" => Self::F13,
630 "F14" => Self::F14,
631 "F15" => Self::F15,
632 "F16" => Self::F16,
633 "F17" => Self::F17,
634 "F18" => Self::F18,
635 "F19" => Self::F19,
636 "F20" => Self::F20,
637 "F21" => Self::F21,
638 "F22" => Self::F22,
639 "F23" => Self::F23,
640 "F24" => Self::F24,
641 "NUMLOCK" => Self::Numlock,
642 "SCROLL" => Self::Scroll,
643 "LSHIFT" => Self::LShift,
644 "RSHIFT" => Self::RShift,
645 "LCONTROL" | "LCTRL" => Self::LControl,
646 "RCONTROL" | "RCTRL" => Self::RControl,
647 "LMENU" | "LALT" => Self::LMenu,
648 "RMENU" | "RALT" => Self::RMenu,
649 "BROWSER_BACK" => Self::BrowserBack,
650 "BROWSER_FORWARD" => Self::BrowserForward,
651 "BROWSER_REFRESH" => Self::BrowserRefresh,
652 "BROWSER_STOP" => Self::BrowserStop,
653 "BROWSER_SEARCH" => Self::BrowserSearch,
654 "BROWSER_FAVORITES" => Self::BrowserFavorites,
655 "BROWSER_HOME" => Self::BrowserHome,
656 "VOLUME_MUTE" => Self::VolumeMute,
657 "VOLUME_DOWN" => Self::VolumeDown,
658 "VOLUME_UP" => Self::VolumeUp,
659 "MEDIA_NEXT_TRACK" => Self::MediaNextTrack,
660 "MEDIA_PREV_TRACK" => Self::MediaPrevTrack,
661 "MEDIA_STOP" => Self::MediaStop,
662 "MEDIA_PLAY_PAUSE" => Self::MediaPlayPause,
663 "LAUNCH_MAIL" => Self::LaunchMail,
664 "LAUNCH_MEDIA_SELECT" => Self::LaunchMediaSelect,
665 "LAUNCH_APP1" => Self::LaunchApp1,
666 "LAUNCH_APP2" => Self::LaunchApp2,
667 "SEMICOLON" | "OEM_1" | ";" | ":" => Self::Semicolon,
668 "ADD" | "PLUS" | "+" => Self::Plus,
669 "COMMA" | "," => Self::Comma,
670 "SUBTRACT" | "MINUS" | "-" => Self::Minus,
671 "PERIOD" | "." => Self::Period,
672 "SLASH" | "OEM_2" | "/" => Self::Slash,
673 "BACKQUOTE" | "OEM_3" | "`" => Self::Backquote,
674 "BRACKETLEFT" | "OEM_4" | "[" | "{" => Self::BracketLeft,
675 "BACKSLASH" | "OEM_5" | "\\" => Self::Backslash,
676 "BRACKETRIGHT" | "OEM_6" | "]" | "}" => Self::BracketRight,
677 "QUOTE" | "OEM_7" | "'" | r#"""# => Self::Quote,
678 "OEM_8" => Self::Oem8,
679 "OEM_102" => Self::Oem102,
680 "ATTN" => Self::Attn,
681 "CRSEL" => Self::Crsel,
682 "EXSEL" => Self::Exsel,
683 "PLAY" => Self::Play,
684 "ZOOM" => Self::Zoom,
685 "PA1" => Self::Pa1,
686 "OEM_CLEAR" => Self::OemClear,
687
688 _ => return Err(HotkeyError::InvalidKey(val)),
689 })
690 }
691}
692
693impl Display for VirtualKey {
694 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
695 use windows_sys::Win32::UI::Input::KeyboardAndMouse::*;
696
697 let code = self.to_vk_code();
698
699 if code >= 'A' as u16 && code <= 'Z' as u16 {
700 return write!(f, "{}", code as u8 as char);
701 }
702
703 if code >= '0' as u16 && code <= '9' as u16 {
704 return write!(f, "{}", code as u8 as char);
705 }
706
707 let val = match code {
708 VK_BACK => "VK_BACK",
709 VK_TAB => "VK_TAB",
710 VK_CLEAR => "VK_CLEAR",
711 VK_RETURN => "VK_RETURN",
712 VK_SHIFT => "VK_SHIFT",
713 VK_CONTROL => "VK_CONTROL",
714 VK_MENU => "VK_MENU",
715 VK_PAUSE => "VK_PAUSE",
716 VK_CAPITAL => "VK_CAPITAL",
717 VK_ESCAPE => "VK_ESCAPE",
718 VK_SPACE => "VK_SPACE",
719 VK_PRIOR => "VK_PRIOR",
720 VK_NEXT => "VK_NEXT",
721 VK_END => "VK_END",
722 VK_HOME => "VK_HOME",
723 VK_LEFT => "VK_LEFT",
724 VK_UP => "VK_UP",
725 VK_RIGHT => "VK_RIGHT",
726 VK_DOWN => "VK_DOWN",
727 VK_SELECT => "VK_SELECT",
728 VK_PRINT => "VK_PRINT",
729 VK_EXECUTE => "VK_EXECUTE",
730 VK_SNAPSHOT => "VK_SNAPSHOT",
731 VK_INSERT => "VK_INSERT",
732 VK_DELETE => "VK_DELETE",
733 VK_HELP => "VK_HELP",
734 VK_LWIN => "VK_LWIN",
735 VK_RWIN => "VK_RWIN",
736 VK_APPS => "VK_APPS",
737 VK_SLEEP => "VK_SLEEP",
738 VK_NUMPAD0 => "VK_NUMPAD0",
739 VK_NUMPAD1 => "VK_NUMPAD1",
740 VK_NUMPAD2 => "VK_NUMPAD2",
741 VK_NUMPAD3 => "VK_NUMPAD3",
742 VK_NUMPAD4 => "VK_NUMPAD4",
743 VK_NUMPAD5 => "VK_NUMPAD5",
744 VK_NUMPAD6 => "VK_NUMPAD6",
745 VK_NUMPAD7 => "VK_NUMPAD7",
746 VK_NUMPAD8 => "VK_NUMPAD8",
747 VK_NUMPAD9 => "VK_NUMPAD9",
748 VK_MULTIPLY => "VK_MULTIPLY",
749 VK_ADD => "VK_ADD",
750 VK_SEPARATOR => "VK_SEPARATOR",
751 VK_SUBTRACT => "VK_SUBTRACT",
752 VK_DECIMAL => "VK_DECIMAL",
753 VK_DIVIDE => "VK_DIVIDE",
754 VK_F1 => "VK_F1",
755 VK_F2 => "VK_F2",
756 VK_F3 => "VK_F3",
757 VK_F4 => "VK_F4",
758 VK_F5 => "VK_F5",
759 VK_F6 => "VK_F6",
760 VK_F7 => "VK_F7",
761 VK_F8 => "VK_F8",
762 VK_F9 => "VK_F9",
763 VK_F10 => "VK_F10",
764 VK_F11 => "VK_F11",
765 VK_F12 => "VK_F12",
766 VK_F13 => "VK_F13",
767 VK_F14 => "VK_F14",
768 VK_F15 => "VK_F15",
769 VK_F16 => "VK_F16",
770 VK_F17 => "VK_F17",
771 VK_F18 => "VK_F18",
772 VK_F19 => "VK_F19",
773 VK_F20 => "VK_F20",
774 VK_F21 => "VK_F21",
775 VK_F22 => "VK_F22",
776 VK_F23 => "VK_F23",
777 VK_F24 => "VK_F24",
778 VK_NUMLOCK => "VK_NUMLOCK",
779 VK_SCROLL => "VK_SCROLL",
780 VK_LSHIFT => "VK_LSHIFT",
781 VK_RSHIFT => "VK_RSHIFT",
782 VK_LCONTROL => "VK_LCONTROL",
783 VK_RCONTROL => "VK_RCONTROL",
784 VK_LMENU => "VK_LMENU",
785 VK_RMENU => "VK_RMENU",
786 VK_BROWSER_BACK => "VK_BROWSER_BACK",
787 VK_BROWSER_FORWARD => "VK_BROWSER_FORWARD",
788 VK_BROWSER_REFRESH => "VK_BROWSER_REFRESH",
789 VK_BROWSER_STOP => "VK_BROWSER_STOP",
790 VK_BROWSER_SEARCH => "VK_BROWSER_SEARCH",
791 VK_BROWSER_FAVORITES => "VK_BROWSER_FAVORITES",
792 VK_BROWSER_HOME => "VK_BROWSER_HOME",
793 VK_VOLUME_MUTE => "VK_VOLUME_MUTE",
794 VK_VOLUME_DOWN => "VK_VOLUME_DOWN",
795 VK_VOLUME_UP => "VK_VOLUME_UP",
796 VK_MEDIA_NEXT_TRACK => "VK_MEDIA_NEXT_TRACK",
797 VK_MEDIA_PREV_TRACK => "VK_MEDIA_PREV_TRACK",
798 VK_MEDIA_STOP => "VK_MEDIA_STOP",
799 VK_MEDIA_PLAY_PAUSE => "VK_MEDIA_PLAY_PAUSE",
800 VK_LAUNCH_MAIL => "VK_LAUNCH_MAIL",
801 VK_LAUNCH_MEDIA_SELECT => "VK_LAUNCH_MEDIA_SELECT",
802 VK_LAUNCH_APP1 => "VK_LAUNCH_APP1",
803 VK_LAUNCH_APP2 => "VK_LAUNCH_APP2",
804 VK_OEM_1 => "VK_OEM_1",
805 VK_OEM_PLUS => "VK_OEM_PLUS",
806 VK_OEM_COMMA => "VK_OEM_COMMA",
807 VK_OEM_MINUS => "VK_OEM_MINUS",
808 VK_OEM_PERIOD => "VK_OEM_PERIOD",
809 VK_OEM_2 => "VK_OEM_2",
810 VK_OEM_3 => "VK_OEM_3",
811 VK_OEM_4 => "VK_OEM_4",
812 VK_OEM_5 => "VK_OEM_5",
813 VK_OEM_6 => "VK_OEM_6",
814 VK_OEM_7 => "VK_OEM_7",
815 VK_OEM_8 => "VK_OEM_8",
816 VK_OEM_102 => "VK_OEM_102",
817 VK_ATTN => "VK_ATTN",
818 VK_CRSEL => "VK_CRSEL",
819 VK_EXSEL => "VK_EXSEL",
820 VK_PLAY => "VK_PLAY",
821 VK_ZOOM => "VK_ZOOM",
822 VK_PA1 => "VK_PA1",
823 VK_OEM_CLEAR => "VK_OEM_CLEAR",
824 vk_code => return write!(f, "0x{:x}", vk_code),
825 };
826
827 write!(f, "{}", val)
828 }
829}
830
831impl PartialEq<VirtualKey> for VirtualKey {
832 fn eq(&self, other: &VirtualKey) -> bool {
833 self.to_vk_code() == other.to_vk_code()
834 }
835}
836
837impl Eq for VirtualKey {}
838
839impl Hash for VirtualKey {
840 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
841 self.to_vk_code().hash(state);
842 }
843}
844
845impl TryInto<ModifiersKey> for VirtualKey {
846 type Error = ();
847
848 fn try_into(self) -> Result<ModifiersKey, Self::Error> {
849 use windows_sys::Win32::UI::Input::KeyboardAndMouse::*;
850
851 Ok(match self.to_vk_code() {
852 VK_MENU | VK_LMENU | VK_RMENU => ModifiersKey::Alt,
853 VK_CONTROL | VK_LCONTROL | VK_RCONTROL => ModifiersKey::Ctrl,
854 VK_SHIFT | VK_LSHIFT | VK_RSHIFT => ModifiersKey::Shift,
855 VK_LWIN | VK_RWIN => ModifiersKey::Win,
856 _ => return Err(()),
857 })
858 }
859}