windows_hotkeys/keys/
vkey.rs

1use std::{fmt::Display, hash::Hash};
2
3use crate::error::HkError;
4
5use super::ModKey;
6
7/// Virtual Key Code wrapper. The codes and variants follow the virtual key codes.
8/// Not supported as enum variants are the mouse buttons, IME keys, `VK_PACKET` and `VK_NONAME`.
9/// The letter keys (`A` to `Z`) are added as additionall variants, as well as the number keys
10/// (`0` to `9`) which are available as `Vk0` to `Vk9`.
11///
12/// A `VKey` can be created for any arbitrary keycode by using the `CustomKeyCode` variant.
13///
14/// See: <https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes>
15///
16/// ## Note
17/// Matching against a `VKey` can be problematic since all of the variants can also be represented
18/// using the `CustomKeyCode` variant. If a reliable check for a `VKey` is needed, the keycode
19/// from the `VKey::to_vk_code` function should be used to get the unique keycode.
20///
21#[derive(Debug, Clone, Copy)]
22pub enum VKey {
23    /// Backspace key
24    Back,
25    /// Tab key
26    Tab,
27    /// CLEAR key
28    Clear,
29    /// ENTER key
30    Return,
31    /// Shift key
32    Shift,
33    /// CTRL key
34    Control,
35    /// ALT key
36    Menu,
37    /// PAUSE
38    Pause,
39    /// CAPS LOCK key
40    Capital,
41    /// ESC key
42    Escape,
43    /// SPACEBAR
44    Space,
45    /// PAGE UP key
46    Prior,
47    /// PAGE DOWN key
48    Next,
49    /// END key
50    End,
51    /// HOME key
52    Home,
53    /// LEFT ARROW key
54    Left,
55    /// UP ARROW key
56    Up,
57    /// RIGHT ARROW key
58    Right,
59    /// DOWN ARROW key
60    Down,
61    /// SELECT key
62    Select,
63    /// PRINT key
64    Print,
65    /// EXECUTE key
66    Execute,
67    /// PRINT SCREEN key
68    Snapshot,
69    /// INS key
70    Insert,
71    /// DEL key
72    Delete,
73    /// HELP key
74    Help,
75
76    /// Left Windows key (Natural keyboard)
77    LWin,
78    /// Right Windows key (Natural keyboard)
79    RWin,
80    /// Applications key (Natural keyboard)
81    Apps,
82    /// Computer Sleep key
83    Sleep,
84    /// Numeric keypad 0 key
85    Numpad0,
86    /// Numeric keypad 1 key
87    Numpad1,
88    /// Numeric keypad 2 key
89    Numpad2,
90    /// Numeric keypad 3 key
91    Numpad3,
92    /// Numeric keypad 4 key
93    Numpad4,
94    /// Numeric keypad 5 key
95    Numpad5,
96    /// Numeric keypad 6 key
97    Numpad6,
98    /// Numeric keypad 7 key
99    Numpad7,
100    /// Numeric keypad 8 key
101    Numpad8,
102    /// Numeric keypad 9 key
103    Numpad9,
104    /// Multiply key
105    Multiply,
106    /// Add key
107    Add,
108    /// Separator key
109    Separator,
110    /// Subtract key
111    Subtract,
112    /// Decimal key
113    Decimal,
114    /// Divide key
115    Divide,
116    /// F1 key
117    F1,
118    /// F2 key
119    F2,
120    /// F3 key
121    F3,
122    /// F4 key
123    F4,
124    /// F5 key
125    F5,
126    /// F6 key
127    F6,
128    /// F7 key
129    F7,
130    /// F8 key
131    F8,
132    /// F9 key
133    F9,
134    /// F10 key
135    F10,
136    /// F11 key
137    F11,
138    /// F12 key
139    F12,
140    /// F13 key
141    F13,
142    /// F14 key
143    F14,
144    /// F15 key
145    F15,
146    /// F16 key
147    F16,
148    /// F17 key
149    F17,
150    /// F18 key
151    F18,
152    /// F19 key
153    F19,
154    /// F20 key
155    F20,
156    /// F21 key
157    F21,
158    /// F22 key
159    F22,
160    /// F23 key
161    F23,
162    /// F24 key
163    F24,
164    /// NUM LOCK key
165    Numlock,
166    /// SCROLL LOCK key
167    Scroll,
168    /// Left SHIFT key
169    LShift,
170    /// Right SHIFT key
171    RShift,
172    /// Left CONTROL key
173    LControl,
174    /// Right CONTROL key
175    RControl,
176    /// Left ALT key
177    LMenu,
178    /// Right ALT key
179    RMenu,
180    /// Browser Back key
181    BrowserBack,
182    /// Browser Forward key
183    BrowserForward,
184    /// Browser Refresh key
185    BrowserRefresh,
186    /// Browser Stop key
187    BrowserStop,
188    /// Browser Search key
189    BrowserSearch,
190    /// Browser Favorites key
191    BrowserFavorites,
192    /// Browser Start and Home key
193    BrowserHome,
194    /// Volume Mute key
195    VolumeMute,
196    /// Volume Down key
197    VolumeDown,
198    /// Volume Up key
199    VolumeUp,
200    /// Next Track key
201    MediaNextTrack,
202    /// Previous Track key
203    MediaPrevTrack,
204    /// Stop Media key
205    MediaStop,
206    /// Play/Pause Media key
207    MediaPlayPause,
208    /// Start Mail key
209    LaunchMail,
210    /// Select Media key
211    LaunchMediaSelect,
212    /// Start Application 1 key
213    LaunchApp1,
214    /// Start Application 2 key
215    LaunchApp2,
216    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
217    /// the `;:` key
218    Oem1,
219    /// For any country/region, the `+` key
220    OemPlus,
221    /// For any country/region, the `,` key
222    OemComma,
223    /// For any country/region, the `-` key
224    OemMinus,
225    /// For any country/region, the `.` key
226    OemPeriod,
227    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
228    /// the `/?` key
229    Oem2,
230    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
231    /// the `~` key
232    Oem3,
233    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
234    /// the `[{` key
235    Oem4,
236    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
237    /// the `\|` key
238    Oem5,
239    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
240    /// the `]}` key
241    Oem6,
242    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
243    /// the `"'` key
244    Oem7,
245    /// Used for miscellaneous characters; it can vary by keyboard.
246    Oem8,
247    /// The `<>` keys on the US standard keyboard, or the `\\|` key on the non-US 102-key keyboard
248    Oem102,
249    /// Attn key
250    Attn,
251    /// CrSel key
252    Crsel,
253    /// ExSel key
254    Exsel,
255    /// Play key
256    Play,
257    /// Zoom key
258    Zoom,
259    /// PA1 key
260    Pa1,
261    /// Clear key
262    OemClear,
263
264    /// 0 key
265    Vk0,
266    /// 1 key
267    Vk1,
268    /// 2 key
269    Vk2,
270    /// 3 key
271    Vk3,
272    /// 4 key
273    Vk4,
274    /// 5 key
275    Vk5,
276    /// 6 key
277    Vk6,
278    /// 7 key
279    Vk7,
280    /// 8 key
281    Vk8,
282    /// 9 key
283    Vk9,
284
285    /// A key
286    A,
287    /// B key
288    B,
289    /// C key
290    C,
291    /// D key
292    D,
293    /// E key
294    E,
295    /// F key
296    F,
297    /// G key
298    G,
299    /// H key
300    H,
301    /// I key
302    I,
303    /// J key
304    J,
305    /// K key
306    K,
307    /// L key
308    L,
309    /// M key
310    M,
311    /// N key
312    N,
313    /// O key
314    O,
315    /// P key
316    P,
317    /// Q key
318    Q,
319    /// R key
320    R,
321    /// S key
322    S,
323    /// T key
324    T,
325    /// U key
326    U,
327    /// V key
328    V,
329    /// W key
330    W,
331    /// X key
332    X,
333    /// Y key
334    Y,
335    /// Z key
336    Z,
337
338    /// Virtual key specified by the actual keycode. This can be used to create a VKey for keys
339    /// that are not covered by the other enum variants.
340    ///
341    /// See: <https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes>
342    ///
343    CustomKeyCode(i32),
344}
345
346impl VKey {
347    /// Try to create a VKey from a char. This only works for the simple number and letter keys
348    /// ('A' to 'Z' and '0' to '9'). Letters can be upper or lower case
349    ///
350    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    /// Get the actual windows virtual keycode for the `VKey` for usage with winapi functions
358    ///
359    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    /// Take in a string and try to guess what Virtual Key (VK) it is meant to represent.
521    /// Returns the VK code as i32 on success (a key representation was recognized).
522    ///
523    /// - For single character strings the ASCII code is used as VK, this is used to represent
524    /// alphanumeric keys
525    /// - Many of the most common VKs are represented by their constant name. For example
526    /// VK_SPACE => spacebar key
527    /// - Any other key can be represented by directly specifying the VK keycode value in 2
528    /// digit hex representation. For example 0x08 == VK_TAB (Tab key)
529    ///
530    /// See <https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes>
531    ///
532    pub fn from_keyname(val: &str) -> Result<Self, HkError> {
533        let val = val.to_ascii_uppercase();
534
535        // Single letter => Simply use the ASCII Code
536        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        // 1 byte hex code => Use the raw keycode value
544        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        // Try to match against hardcoded VK_* Key specifiers
553        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}