win_hotkey/keys/
vk.rs

1use super::ModifiersKey;
2use crate::error::HotkeyError;
3use std::{fmt::Display, hash::Hash};
4
5/// Virtual Key Code wrapper. The codes and variants follow the virtual key codes.
6/// Not supported as enum variants are the mouse buttons, IME keys, `VK_PACKET` and `VK_NONAME`.
7/// The letter keys (`A` to `Z`) are added as additionall variants, as well as the number keys
8/// (`0` to `9`) which are available as `Vk0` to `Vk9`.
9///
10/// A `VirtualKey` can be created for any arbitrary keycode by using the `CustomKeyCode` variant.
11///
12/// See: <https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes>
13///
14/// ## Note
15/// Matching against a `VirtualKey` can be problematic since all of the variants can also be represented
16/// using the `CustomKeyCode` variant. If a reliable check for a `VirtualKey` is needed, the keycode
17/// from the `VirtualKey::to_vk_code` function should be used to get the unique keycode.
18///
19#[derive(Debug, Clone, Copy)]
20pub enum VirtualKey {
21    /// Backspace key
22    Back,
23    /// Backspace key
24    Backspace,
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    NumpadMultiply,
106    /// Add key
107    NumpadAdd,
108    /// Separator key
109    Separator,
110    /// Subtract key
111    NumpadSubtract,
112    /// Decimal key
113    NumpadDecimal,
114    /// Divide key
115    NumpadDivide,
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    Semicolon,
219    /// For any country/region, the `+` key
220    Plus,
221    /// For any country/region, the `,` key
222    Comma,
223    /// For any country/region, the `-` key
224    Minus,
225    /// For any country/region, the `.` key
226    Period,
227    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
228    /// the `/?` key
229    Slash,
230    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
231    /// the `~` key
232    Backquote,
233    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
234    /// the `[{` key
235    BracketLeft,
236    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
237    /// the `\|` key
238    Backslash,
239    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
240    /// the `]}` key
241    BracketRight,
242    /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard,
243    /// the `"'` key
244    Quote,
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 VirtualKey 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(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    /// Try to create a VirtualKey from a char. This only works for the simple number and letter keys
365    /// ('A' to 'Z' and '0' to '9'). Letters can be upper or lower case
366    ///
367    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    /// Get the actual windows virtual keycode for the `VirtualKey` for usage with winapi functions
375    ///
376    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    /// Take in a string and try to guess what Virtual Key (VK) it is meant to represent.
538    /// Returns the VK code as u16 on success (a key representation was recognized).
539    ///
540    /// - For single character strings the ASCII code is used as VK, this is used to represent
541    /// alphanumeric keys
542    /// - Many of the most common VKs are represented by their constant name. For example
543    /// VK_SPACE => spacebar key
544    /// - Any other key can be represented by directly specifying the VK keycode value in 2
545    /// digit hex representation. For example 0x08 == VK_TAB (Tab key)
546    ///
547    /// See <https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes>
548    ///
549    pub fn from_keyname(val: &str) -> Result<Self, HotkeyError> {
550        let val = val.to_ascii_uppercase();
551
552        // Single letter => Simply use the ASCII Code
553        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        // 1 byte hex code => Use the raw keycode value
561        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        // Try to match against hardcoded VK_* Key specifiers
570        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}