1use std::{fmt::Display, hash::Hash};
2
3use crate::error::HkError;
4
5use super::ModKey;
6
7#[derive(Debug, Clone, Copy)]
22pub enum VKey {
23 Back,
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 Multiply,
106 Add,
108 Separator,
110 Subtract,
112 Decimal,
114 Divide,
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 Oem1,
219 OemPlus,
221 OemComma,
223 OemMinus,
225 OemPeriod,
227 Oem2,
230 Oem3,
233 Oem4,
236 Oem5,
239 Oem6,
242 Oem7,
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(i32),
344}
345
346impl VKey {
347 pub const fn from_char(ch: char) -> Result<Self, HkError> {
351 match ch.to_ascii_uppercase() {
352 ch @ ('A'..='Z' | '0'..='9') => Ok(Self::CustomKeyCode(ch as i32)),
353 ch => Err(HkError::InvalidKeyChar(ch)),
354 }
355 }
356
357 pub const fn to_vk_code(&self) -> i32 {
360 use winapi::um::winuser::*;
361 match self {
362 VKey::Back => VK_BACK,
363 VKey::Tab => VK_TAB,
364 VKey::Clear => VK_CLEAR,
365 VKey::Return => VK_RETURN,
366 VKey::Shift => VK_SHIFT,
367 VKey::Control => VK_CONTROL,
368 VKey::Menu => VK_MENU,
369 VKey::Pause => VK_PAUSE,
370 VKey::Capital => VK_CAPITAL,
371 VKey::Escape => VK_ESCAPE,
372 VKey::Space => VK_SPACE,
373 VKey::Prior => VK_PRIOR,
374 VKey::Next => VK_NEXT,
375 VKey::End => VK_END,
376 VKey::Home => VK_HOME,
377 VKey::Left => VK_LEFT,
378 VKey::Up => VK_UP,
379 VKey::Right => VK_RIGHT,
380 VKey::Down => VK_DOWN,
381 VKey::Select => VK_SELECT,
382 VKey::Print => VK_PRINT,
383 VKey::Execute => VK_EXECUTE,
384 VKey::Snapshot => VK_SNAPSHOT,
385 VKey::Insert => VK_INSERT,
386 VKey::Delete => VK_DELETE,
387 VKey::Help => VK_HELP,
388 VKey::LWin => VK_LWIN,
389 VKey::RWin => VK_RWIN,
390 VKey::Apps => VK_APPS,
391 VKey::Sleep => VK_SLEEP,
392 VKey::Numpad0 => VK_NUMPAD0,
393 VKey::Numpad1 => VK_NUMPAD1,
394 VKey::Numpad2 => VK_NUMPAD2,
395 VKey::Numpad3 => VK_NUMPAD3,
396 VKey::Numpad4 => VK_NUMPAD4,
397 VKey::Numpad5 => VK_NUMPAD5,
398 VKey::Numpad6 => VK_NUMPAD6,
399 VKey::Numpad7 => VK_NUMPAD7,
400 VKey::Numpad8 => VK_NUMPAD8,
401 VKey::Numpad9 => VK_NUMPAD9,
402 VKey::Multiply => VK_MULTIPLY,
403 VKey::Add => VK_ADD,
404 VKey::Separator => VK_SEPARATOR,
405 VKey::Subtract => VK_SUBTRACT,
406 VKey::Decimal => VK_DECIMAL,
407 VKey::Divide => VK_DIVIDE,
408 VKey::F1 => VK_F1,
409 VKey::F2 => VK_F2,
410 VKey::F3 => VK_F3,
411 VKey::F4 => VK_F4,
412 VKey::F5 => VK_F5,
413 VKey::F6 => VK_F6,
414 VKey::F7 => VK_F7,
415 VKey::F8 => VK_F8,
416 VKey::F9 => VK_F9,
417 VKey::F10 => VK_F10,
418 VKey::F11 => VK_F11,
419 VKey::F12 => VK_F12,
420 VKey::F13 => VK_F13,
421 VKey::F14 => VK_F14,
422 VKey::F15 => VK_F15,
423 VKey::F16 => VK_F16,
424 VKey::F17 => VK_F17,
425 VKey::F18 => VK_F18,
426 VKey::F19 => VK_F19,
427 VKey::F20 => VK_F20,
428 VKey::F21 => VK_F21,
429 VKey::F22 => VK_F22,
430 VKey::F23 => VK_F23,
431 VKey::F24 => VK_F24,
432 VKey::Numlock => VK_NUMLOCK,
433 VKey::Scroll => VK_SCROLL,
434 VKey::LShift => VK_LSHIFT,
435 VKey::RShift => VK_RSHIFT,
436 VKey::LControl => VK_LCONTROL,
437 VKey::RControl => VK_RCONTROL,
438 VKey::LMenu => VK_LMENU,
439 VKey::RMenu => VK_RMENU,
440 VKey::BrowserBack => VK_BROWSER_BACK,
441 VKey::BrowserForward => VK_BROWSER_FORWARD,
442 VKey::BrowserRefresh => VK_BROWSER_REFRESH,
443 VKey::BrowserStop => VK_BROWSER_STOP,
444 VKey::BrowserSearch => VK_BROWSER_SEARCH,
445 VKey::BrowserFavorites => VK_BROWSER_FAVORITES,
446 VKey::BrowserHome => VK_BROWSER_HOME,
447 VKey::VolumeMute => VK_VOLUME_MUTE,
448 VKey::VolumeDown => VK_VOLUME_DOWN,
449 VKey::VolumeUp => VK_VOLUME_UP,
450 VKey::MediaNextTrack => VK_MEDIA_NEXT_TRACK,
451 VKey::MediaPrevTrack => VK_MEDIA_PREV_TRACK,
452 VKey::MediaStop => VK_MEDIA_STOP,
453 VKey::MediaPlayPause => VK_MEDIA_PLAY_PAUSE,
454 VKey::LaunchMail => VK_LAUNCH_MAIL,
455 VKey::LaunchMediaSelect => VK_LAUNCH_MEDIA_SELECT,
456 VKey::LaunchApp1 => VK_LAUNCH_APP1,
457 VKey::LaunchApp2 => VK_LAUNCH_APP2,
458 VKey::Oem1 => VK_OEM_1,
459 VKey::OemPlus => VK_OEM_PLUS,
460 VKey::OemComma => VK_OEM_COMMA,
461 VKey::OemMinus => VK_OEM_MINUS,
462 VKey::OemPeriod => VK_OEM_PERIOD,
463 VKey::Oem2 => VK_OEM_2,
464 VKey::Oem3 => VK_OEM_3,
465 VKey::Oem4 => VK_OEM_4,
466 VKey::Oem5 => VK_OEM_5,
467 VKey::Oem6 => VK_OEM_6,
468 VKey::Oem7 => VK_OEM_7,
469 VKey::Oem8 => VK_OEM_8,
470 VKey::Oem102 => VK_OEM_102,
471 VKey::Attn => VK_ATTN,
472 VKey::Crsel => VK_CRSEL,
473 VKey::Exsel => VK_EXSEL,
474 VKey::Play => VK_PLAY,
475 VKey::Zoom => VK_ZOOM,
476 VKey::Pa1 => VK_PA1,
477 VKey::OemClear => VK_OEM_CLEAR,
478
479 VKey::Vk0 => b'0' as i32,
480 VKey::Vk1 => b'1' as i32,
481 VKey::Vk2 => b'2' as i32,
482 VKey::Vk3 => b'3' as i32,
483 VKey::Vk4 => b'4' as i32,
484 VKey::Vk5 => b'5' as i32,
485 VKey::Vk6 => b'6' as i32,
486 VKey::Vk7 => b'7' as i32,
487 VKey::Vk8 => b'8' as i32,
488 VKey::Vk9 => b'9' as i32,
489 VKey::A => b'A' as i32,
490 VKey::B => b'B' as i32,
491 VKey::C => b'C' as i32,
492 VKey::D => b'D' as i32,
493 VKey::E => b'E' as i32,
494 VKey::F => b'F' as i32,
495 VKey::G => b'G' as i32,
496 VKey::H => b'H' as i32,
497 VKey::I => b'I' as i32,
498 VKey::J => b'J' as i32,
499 VKey::K => b'K' as i32,
500 VKey::L => b'L' as i32,
501 VKey::M => b'M' as i32,
502 VKey::N => b'N' as i32,
503 VKey::O => b'O' as i32,
504 VKey::P => b'P' as i32,
505 VKey::Q => b'Q' as i32,
506 VKey::R => b'R' as i32,
507 VKey::S => b'S' as i32,
508 VKey::T => b'T' as i32,
509 VKey::U => b'U' as i32,
510 VKey::V => b'V' as i32,
511 VKey::W => b'W' as i32,
512 VKey::X => b'X' as i32,
513 VKey::Y => b'Y' as i32,
514 VKey::Z => b'Z' as i32,
515
516 VKey::CustomKeyCode(vk) => *vk,
517 }
518 }
519
520 pub fn from_keyname(val: &str) -> Result<Self, HkError> {
533 let val = val.to_ascii_uppercase();
534
535 if val.as_bytes().len() == 1 {
537 let val = val.as_bytes()[0];
538 if val.is_ascii_uppercase() || val.is_ascii_digit() {
539 return Ok(Self::CustomKeyCode(val as i32));
540 }
541 }
542
543 if val.len() >= 3 && val.len() <= 6 && val.starts_with("0x") || val.starts_with("0X") {
545 if let Ok(val) = i32::from_str_radix(&val[2..], 16) {
546 return Ok(Self::CustomKeyCode(val));
547 } else {
548 return Err(HkError::InvalidKey(val));
549 }
550 }
551
552 Ok(match val.trim_start_matches("VK_") {
554 "BACK" => Self::Back,
555 "TAB" => Self::Tab,
556 "CLEAR" => Self::Clear,
557 "RETURN" => Self::Return,
558 "SHIFT" => Self::Shift,
559 "CONTROL" => Self::Control,
560 "MENU" => Self::Menu,
561 "PAUSE" => Self::Pause,
562 "CAPITAL" => Self::Capital,
563 "ESCAPE" => Self::Escape,
564 "SPACE" => Self::Space,
565 "PRIOR" => Self::Prior,
566 "NEXT" => Self::Next,
567 "END" => Self::End,
568 "HOME" => Self::Home,
569 "LEFT" => Self::Left,
570 "UP" => Self::Up,
571 "RIGHT" => Self::Right,
572 "DOWN" => Self::Down,
573 "SELECT" => Self::Select,
574 "PRINT" => Self::Print,
575 "EXECUTE" => Self::Execute,
576 "SNAPSHOT" => Self::Snapshot,
577 "INSERT" => Self::Insert,
578 "DELETE" => Self::Delete,
579 "HELP" => Self::Help,
580 "LWIN" => Self::LWin,
581 "RWIN" => Self::RWin,
582 "APPS" => Self::Apps,
583 "SLEEP" => Self::Sleep,
584 "NUMPAD0" => Self::Numpad0,
585 "NUMPAD1" => Self::Numpad1,
586 "NUMPAD2" => Self::Numpad2,
587 "NUMPAD3" => Self::Numpad3,
588 "NUMPAD4" => Self::Numpad4,
589 "NUMPAD5" => Self::Numpad5,
590 "NUMPAD6" => Self::Numpad6,
591 "NUMPAD7" => Self::Numpad7,
592 "NUMPAD8" => Self::Numpad8,
593 "NUMPAD9" => Self::Numpad9,
594 "MULTIPLY" => Self::Multiply,
595 "ADD" => Self::Add,
596 "SEPARATOR" => Self::Separator,
597 "SUBTRACT" => Self::Subtract,
598 "DECIMAL" => Self::Decimal,
599 "DIVIDE" => Self::Divide,
600 "F1" => Self::F1,
601 "F2" => Self::F2,
602 "F3" => Self::F3,
603 "F4" => Self::F4,
604 "F5" => Self::F5,
605 "F6" => Self::F6,
606 "F7" => Self::F7,
607 "F8" => Self::F8,
608 "F9" => Self::F9,
609 "F10" => Self::F10,
610 "F11" => Self::F11,
611 "F12" => Self::F12,
612 "F13" => Self::F13,
613 "F14" => Self::F14,
614 "F15" => Self::F15,
615 "F16" => Self::F16,
616 "F17" => Self::F17,
617 "F18" => Self::F18,
618 "F19" => Self::F19,
619 "F20" => Self::F20,
620 "F21" => Self::F21,
621 "F22" => Self::F22,
622 "F23" => Self::F23,
623 "F24" => Self::F24,
624 "NUMLOCK" => Self::Numlock,
625 "SCROLL" => Self::Scroll,
626 "LSHIFT" => Self::LShift,
627 "RSHIFT" => Self::RShift,
628 "LCONTROL" => Self::LControl,
629 "RCONTROL" => Self::RControl,
630 "LMENU" => Self::LMenu,
631 "RMENU" => Self::RMenu,
632 "BROWSER_BACK" => Self::BrowserBack,
633 "BROWSER_FORWARD" => Self::BrowserForward,
634 "BROWSER_REFRESH" => Self::BrowserRefresh,
635 "BROWSER_STOP" => Self::BrowserStop,
636 "BROWSER_SEARCH" => Self::BrowserSearch,
637 "BROWSER_FAVORITES" => Self::BrowserFavorites,
638 "BROWSER_HOME" => Self::BrowserHome,
639 "VOLUME_MUTE" => Self::VolumeMute,
640 "VOLUME_DOWN" => Self::VolumeDown,
641 "VOLUME_UP" => Self::VolumeUp,
642 "MEDIA_NEXT_TRACK" => Self::MediaNextTrack,
643 "MEDIA_PREV_TRACK" => Self::MediaPrevTrack,
644 "MEDIA_STOP" => Self::MediaStop,
645 "MEDIA_PLAY_PAUSE" => Self::MediaPlayPause,
646 "LAUNCH_MAIL" => Self::LaunchMail,
647 "LAUNCH_MEDIA_SELECT" => Self::LaunchMediaSelect,
648 "LAUNCH_APP1" => Self::LaunchApp1,
649 "LAUNCH_APP2" => Self::LaunchApp2,
650 "OEM_1" => Self::Oem1,
651 "OEM_PLUS" => Self::OemPlus,
652 "OEM_COMMA" => Self::OemComma,
653 "OEM_MINUS" => Self::OemMinus,
654 "OEM_PERIOD" => Self::OemPeriod,
655 "OEM_2" => Self::Oem2,
656 "OEM_3" => Self::Oem3,
657 "OEM_4" => Self::Oem4,
658 "OEM_5" => Self::Oem5,
659 "OEM_6" => Self::Oem6,
660 "OEM_7" => Self::Oem7,
661 "OEM_8" => Self::Oem8,
662 "OEM_102" => Self::Oem102,
663 "ATTN" => Self::Attn,
664 "CRSEL" => Self::Crsel,
665 "EXSEL" => Self::Exsel,
666 "PLAY" => Self::Play,
667 "ZOOM" => Self::Zoom,
668 "PA1" => Self::Pa1,
669 "OEM_CLEAR" => Self::OemClear,
670
671 _ => return Err(HkError::InvalidKey(val)),
672 })
673 }
674}
675
676impl Display for VKey {
677 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
678 use winapi::um::winuser::*;
679
680 let code = self.to_vk_code();
681
682 if code >= 'A' as i32 && code <= 'Z' as i32 {
683 return write!(f, "{}", code as u8 as char);
684 }
685
686 if code >= '0' as i32 && code <= '9' as i32 {
687 return write!(f, "{}", code as u8 as char);
688 }
689
690 let val = match code {
691 VK_BACK => "VK_BACK",
692 VK_TAB => "VK_TAB",
693 VK_CLEAR => "VK_CLEAR",
694 VK_RETURN => "VK_RETURN",
695 VK_SHIFT => "VK_SHIFT",
696 VK_CONTROL => "VK_CONTROL",
697 VK_MENU => "VK_MENU",
698 VK_PAUSE => "VK_PAUSE",
699 VK_CAPITAL => "VK_CAPITAL",
700 VK_ESCAPE => "VK_ESCAPE",
701 VK_SPACE => "VK_SPACE",
702 VK_PRIOR => "VK_PRIOR",
703 VK_NEXT => "VK_NEXT",
704 VK_END => "VK_END",
705 VK_HOME => "VK_HOME",
706 VK_LEFT => "VK_LEFT",
707 VK_UP => "VK_UP",
708 VK_RIGHT => "VK_RIGHT",
709 VK_DOWN => "VK_DOWN",
710 VK_SELECT => "VK_SELECT",
711 VK_PRINT => "VK_PRINT",
712 VK_EXECUTE => "VK_EXECUTE",
713 VK_SNAPSHOT => "VK_SNAPSHOT",
714 VK_INSERT => "VK_INSERT",
715 VK_DELETE => "VK_DELETE",
716 VK_HELP => "VK_HELP",
717 VK_LWIN => "VK_LWIN",
718 VK_RWIN => "VK_RWIN",
719 VK_APPS => "VK_APPS",
720 VK_SLEEP => "VK_SLEEP",
721 VK_NUMPAD0 => "VK_NUMPAD0",
722 VK_NUMPAD1 => "VK_NUMPAD1",
723 VK_NUMPAD2 => "VK_NUMPAD2",
724 VK_NUMPAD3 => "VK_NUMPAD3",
725 VK_NUMPAD4 => "VK_NUMPAD4",
726 VK_NUMPAD5 => "VK_NUMPAD5",
727 VK_NUMPAD6 => "VK_NUMPAD6",
728 VK_NUMPAD7 => "VK_NUMPAD7",
729 VK_NUMPAD8 => "VK_NUMPAD8",
730 VK_NUMPAD9 => "VK_NUMPAD9",
731 VK_MULTIPLY => "VK_MULTIPLY",
732 VK_ADD => "VK_ADD",
733 VK_SEPARATOR => "VK_SEPARATOR",
734 VK_SUBTRACT => "VK_SUBTRACT",
735 VK_DECIMAL => "VK_DECIMAL",
736 VK_DIVIDE => "VK_DIVIDE",
737 VK_F1 => "VK_F1",
738 VK_F2 => "VK_F2",
739 VK_F3 => "VK_F3",
740 VK_F4 => "VK_F4",
741 VK_F5 => "VK_F5",
742 VK_F6 => "VK_F6",
743 VK_F7 => "VK_F7",
744 VK_F8 => "VK_F8",
745 VK_F9 => "VK_F9",
746 VK_F10 => "VK_F10",
747 VK_F11 => "VK_F11",
748 VK_F12 => "VK_F12",
749 VK_F13 => "VK_F13",
750 VK_F14 => "VK_F14",
751 VK_F15 => "VK_F15",
752 VK_F16 => "VK_F16",
753 VK_F17 => "VK_F17",
754 VK_F18 => "VK_F18",
755 VK_F19 => "VK_F19",
756 VK_F20 => "VK_F20",
757 VK_F21 => "VK_F21",
758 VK_F22 => "VK_F22",
759 VK_F23 => "VK_F23",
760 VK_F24 => "VK_F24",
761 VK_NUMLOCK => "VK_NUMLOCK",
762 VK_SCROLL => "VK_SCROLL",
763 VK_LSHIFT => "VK_LSHIFT",
764 VK_RSHIFT => "VK_RSHIFT",
765 VK_LCONTROL => "VK_LCONTROL",
766 VK_RCONTROL => "VK_RCONTROL",
767 VK_LMENU => "VK_LMENU",
768 VK_RMENU => "VK_RMENU",
769 VK_BROWSER_BACK => "VK_BROWSER_BACK",
770 VK_BROWSER_FORWARD => "VK_BROWSER_FORWARD",
771 VK_BROWSER_REFRESH => "VK_BROWSER_REFRESH",
772 VK_BROWSER_STOP => "VK_BROWSER_STOP",
773 VK_BROWSER_SEARCH => "VK_BROWSER_SEARCH",
774 VK_BROWSER_FAVORITES => "VK_BROWSER_FAVORITES",
775 VK_BROWSER_HOME => "VK_BROWSER_HOME",
776 VK_VOLUME_MUTE => "VK_VOLUME_MUTE",
777 VK_VOLUME_DOWN => "VK_VOLUME_DOWN",
778 VK_VOLUME_UP => "VK_VOLUME_UP",
779 VK_MEDIA_NEXT_TRACK => "VK_MEDIA_NEXT_TRACK",
780 VK_MEDIA_PREV_TRACK => "VK_MEDIA_PREV_TRACK",
781 VK_MEDIA_STOP => "VK_MEDIA_STOP",
782 VK_MEDIA_PLAY_PAUSE => "VK_MEDIA_PLAY_PAUSE",
783 VK_LAUNCH_MAIL => "VK_LAUNCH_MAIL",
784 VK_LAUNCH_MEDIA_SELECT => "VK_LAUNCH_MEDIA_SELECT",
785 VK_LAUNCH_APP1 => "VK_LAUNCH_APP1",
786 VK_LAUNCH_APP2 => "VK_LAUNCH_APP2",
787 VK_OEM_1 => "VK_OEM_1",
788 VK_OEM_PLUS => "VK_OEM_PLUS",
789 VK_OEM_COMMA => "VK_OEM_COMMA",
790 VK_OEM_MINUS => "VK_OEM_MINUS",
791 VK_OEM_PERIOD => "VK_OEM_PERIOD",
792 VK_OEM_2 => "VK_OEM_2",
793 VK_OEM_3 => "VK_OEM_3",
794 VK_OEM_4 => "VK_OEM_4",
795 VK_OEM_5 => "VK_OEM_5",
796 VK_OEM_6 => "VK_OEM_6",
797 VK_OEM_7 => "VK_OEM_7",
798 VK_OEM_8 => "VK_OEM_8",
799 VK_OEM_102 => "VK_OEM_102",
800 VK_ATTN => "VK_ATTN",
801 VK_CRSEL => "VK_CRSEL",
802 VK_EXSEL => "VK_EXSEL",
803 VK_PLAY => "VK_PLAY",
804 VK_ZOOM => "VK_ZOOM",
805 VK_PA1 => "VK_PA1",
806 VK_OEM_CLEAR => "VK_OEM_CLEAR",
807 vk_code => return write!(f, "0x{:x}", vk_code),
808 };
809
810 write!(f, "{}", val)
811 }
812}
813
814impl PartialEq<VKey> for VKey {
815 fn eq(&self, other: &VKey) -> bool {
816 self.to_vk_code() == other.to_vk_code()
817 }
818}
819
820impl Eq for VKey {}
821
822impl Hash for VKey {
823 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
824 self.to_vk_code().hash(state);
825 }
826}
827
828impl TryInto<ModKey> for VKey {
829 type Error = ();
830
831 fn try_into(self) -> Result<ModKey, Self::Error> {
832 use winapi::um::winuser::*;
833
834 Ok(match self.to_vk_code() {
835 VK_MENU | VK_LMENU | VK_RMENU => ModKey::Alt,
836 VK_CONTROL | VK_LCONTROL | VK_RCONTROL => ModKey::Ctrl,
837 VK_SHIFT | VK_LSHIFT | VK_RSHIFT => ModKey::Shift,
838 VK_LWIN | VK_RWIN => ModKey::Win,
839 _ => return Err(()),
840 })
841 }
842}