win_hotkeys/
keys.rs

1use crate::error::WHKError;
2use std::hash::Hash;
3
4/// Represents a virtual key (VK) code.
5///
6/// # See Also
7/// - [Microsoft Virtual-Key Codes](https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)
8///
9#[derive(Debug, Clone, Copy)]
10pub enum VKey {
11    Back,
12    Tab,
13    Clear,
14    Return,
15    Shift,
16    Control,
17    Menu,
18    Pause,
19    Capital,
20    Escape,
21    Space,
22    Prior,
23    Next,
24    End,
25    Home,
26    Left,
27    Up,
28    Right,
29    Down,
30    Select,
31    Print,
32    Execute,
33    Snapshot,
34    Insert,
35    Delete,
36    Help,
37    LWin,
38    RWin,
39    Apps,
40    Sleep,
41    Numpad0,
42    Numpad1,
43    Numpad2,
44    Numpad3,
45    Numpad4,
46    Numpad5,
47    Numpad6,
48    Numpad7,
49    Numpad8,
50    Numpad9,
51    Multiply,
52    Add,
53    Separator,
54    Subtract,
55    Decimal,
56    Divide,
57    F1,
58    F2,
59    F3,
60    F4,
61    F5,
62    F6,
63    F7,
64    F8,
65    F9,
66    F10,
67    F11,
68    F12,
69    F13,
70    F14,
71    F15,
72    F16,
73    F17,
74    F18,
75    F19,
76    F20,
77    F21,
78    F22,
79    F23,
80    F24,
81    Numlock,
82    Scroll,
83    LShift,
84    RShift,
85    LControl,
86    RControl,
87    LMenu,
88    RMenu,
89    BrowserBack,
90    BrowserForward,
91    BrowserRefresh,
92    BrowserStop,
93    BrowserSearch,
94    BrowserFavorites,
95    BrowserHome,
96    VolumeMute,
97    VolumeDown,
98    VolumeUp,
99    MediaNextTrack,
100    MediaPrevTrack,
101    MediaStop,
102    MediaPlayPause,
103    LaunchMail,
104    LaunchMediaSelect,
105    LaunchApp1,
106    LaunchApp2,
107    Oem1,
108    OemPlus,
109    OemComma,
110    OemMinus,
111    OemPeriod,
112    Oem2,
113    Oem3,
114    Oem4,
115    Oem5,
116    Oem6,
117    Oem7,
118    Oem8,
119    Oem102,
120    Attn,
121    Crsel,
122    Exsel,
123    Play,
124    Zoom,
125    Pa1,
126    OemClear,
127    Vk0,
128    Vk1,
129    Vk2,
130    Vk3,
131    Vk4,
132    Vk5,
133    Vk6,
134    Vk7,
135    Vk8,
136    Vk9,
137    A,
138    B,
139    C,
140    D,
141    E,
142    F,
143    G,
144    H,
145    I,
146    J,
147    K,
148    L,
149    M,
150    N,
151    O,
152    P,
153    Q,
154    R,
155    S,
156    T,
157    U,
158    V,
159    W,
160    X,
161    Y,
162    Z,
163    CustomKeyCode(u16),
164}
165
166impl VKey {
167    /// Converts a `VKey` to its corresponding Windows Virtual-Key (VK) code.
168    ///
169    /// # See Also
170    /// - [Microsoft Virtual-Key Codes](https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)
171    ///
172    pub const fn to_vk_code(&self) -> u16 {
173        use windows::Win32::UI::Input::KeyboardAndMouse::*;
174        match self {
175            VKey::Back => VK_BACK.0,
176            VKey::Tab => VK_TAB.0,
177            VKey::Clear => VK_CLEAR.0,
178            VKey::Return => VK_RETURN.0,
179            VKey::Shift => VK_SHIFT.0,
180            VKey::Control => VK_CONTROL.0,
181            VKey::Menu => VK_MENU.0,
182            VKey::Pause => VK_PAUSE.0,
183            VKey::Capital => VK_CAPITAL.0,
184            VKey::Escape => VK_ESCAPE.0,
185            VKey::Space => VK_SPACE.0,
186            VKey::Prior => VK_PRIOR.0,
187            VKey::Next => VK_NEXT.0,
188            VKey::End => VK_END.0,
189            VKey::Home => VK_HOME.0,
190            VKey::Left => VK_LEFT.0,
191            VKey::Up => VK_UP.0,
192            VKey::Right => VK_RIGHT.0,
193            VKey::Down => VK_DOWN.0,
194            VKey::Select => VK_SELECT.0,
195            VKey::Print => VK_PRINT.0,
196            VKey::Execute => VK_EXECUTE.0,
197            VKey::Snapshot => VK_SNAPSHOT.0,
198            VKey::Insert => VK_INSERT.0,
199            VKey::Delete => VK_DELETE.0,
200            VKey::Help => VK_HELP.0,
201            VKey::LWin => VK_LWIN.0,
202            VKey::RWin => VK_RWIN.0,
203            VKey::Apps => VK_APPS.0,
204            VKey::Sleep => VK_SLEEP.0,
205            VKey::Numpad0 => VK_NUMPAD0.0,
206            VKey::Numpad1 => VK_NUMPAD1.0,
207            VKey::Numpad2 => VK_NUMPAD2.0,
208            VKey::Numpad3 => VK_NUMPAD3.0,
209            VKey::Numpad4 => VK_NUMPAD4.0,
210            VKey::Numpad5 => VK_NUMPAD5.0,
211            VKey::Numpad6 => VK_NUMPAD6.0,
212            VKey::Numpad7 => VK_NUMPAD7.0,
213            VKey::Numpad8 => VK_NUMPAD8.0,
214            VKey::Numpad9 => VK_NUMPAD9.0,
215            VKey::Multiply => VK_MULTIPLY.0,
216            VKey::Add => VK_ADD.0,
217            VKey::Separator => VK_SEPARATOR.0,
218            VKey::Subtract => VK_SUBTRACT.0,
219            VKey::Decimal => VK_DECIMAL.0,
220            VKey::Divide => VK_DIVIDE.0,
221            VKey::F1 => VK_F1.0,
222            VKey::F2 => VK_F2.0,
223            VKey::F3 => VK_F3.0,
224            VKey::F4 => VK_F4.0,
225            VKey::F5 => VK_F5.0,
226            VKey::F6 => VK_F6.0,
227            VKey::F7 => VK_F7.0,
228            VKey::F8 => VK_F8.0,
229            VKey::F9 => VK_F9.0,
230            VKey::F10 => VK_F10.0,
231            VKey::F11 => VK_F11.0,
232            VKey::F12 => VK_F12.0,
233            VKey::F13 => VK_F13.0,
234            VKey::F14 => VK_F14.0,
235            VKey::F15 => VK_F15.0,
236            VKey::F16 => VK_F16.0,
237            VKey::F17 => VK_F17.0,
238            VKey::F18 => VK_F18.0,
239            VKey::F19 => VK_F19.0,
240            VKey::F20 => VK_F20.0,
241            VKey::F21 => VK_F21.0,
242            VKey::F22 => VK_F22.0,
243            VKey::F23 => VK_F23.0,
244            VKey::F24 => VK_F24.0,
245            VKey::Numlock => VK_NUMLOCK.0,
246            VKey::Scroll => VK_SCROLL.0,
247            VKey::LShift => VK_LSHIFT.0,
248            VKey::RShift => VK_RSHIFT.0,
249            VKey::LControl => VK_LCONTROL.0,
250            VKey::RControl => VK_RCONTROL.0,
251            VKey::LMenu => VK_LMENU.0,
252            VKey::RMenu => VK_RMENU.0,
253            VKey::BrowserBack => VK_BROWSER_BACK.0,
254            VKey::BrowserForward => VK_BROWSER_FORWARD.0,
255            VKey::BrowserRefresh => VK_BROWSER_REFRESH.0,
256            VKey::BrowserStop => VK_BROWSER_STOP.0,
257            VKey::BrowserSearch => VK_BROWSER_SEARCH.0,
258            VKey::BrowserFavorites => VK_BROWSER_FAVORITES.0,
259            VKey::BrowserHome => VK_BROWSER_HOME.0,
260            VKey::VolumeMute => VK_VOLUME_MUTE.0,
261            VKey::VolumeDown => VK_VOLUME_DOWN.0,
262            VKey::VolumeUp => VK_VOLUME_UP.0,
263            VKey::MediaNextTrack => VK_MEDIA_NEXT_TRACK.0,
264            VKey::MediaPrevTrack => VK_MEDIA_PREV_TRACK.0,
265            VKey::MediaStop => VK_MEDIA_STOP.0,
266            VKey::MediaPlayPause => VK_MEDIA_PLAY_PAUSE.0,
267            VKey::LaunchMail => VK_LAUNCH_MAIL.0,
268            VKey::LaunchMediaSelect => VK_LAUNCH_MEDIA_SELECT.0,
269            VKey::LaunchApp1 => VK_LAUNCH_APP1.0,
270            VKey::LaunchApp2 => VK_LAUNCH_APP2.0,
271            VKey::Oem1 => VK_OEM_1.0,
272            VKey::OemPlus => VK_OEM_PLUS.0,
273            VKey::OemComma => VK_OEM_COMMA.0,
274            VKey::OemMinus => VK_OEM_MINUS.0,
275            VKey::OemPeriod => VK_OEM_PERIOD.0,
276            VKey::Oem2 => VK_OEM_2.0,
277            VKey::Oem3 => VK_OEM_3.0,
278            VKey::Oem4 => VK_OEM_4.0,
279            VKey::Oem5 => VK_OEM_5.0,
280            VKey::Oem6 => VK_OEM_6.0,
281            VKey::Oem7 => VK_OEM_7.0,
282            VKey::Oem8 => VK_OEM_8.0,
283            VKey::Oem102 => VK_OEM_102.0,
284            VKey::Attn => VK_ATTN.0,
285            VKey::Crsel => VK_CRSEL.0,
286            VKey::Exsel => VK_EXSEL.0,
287            VKey::Play => VK_PLAY.0,
288            VKey::Zoom => VK_ZOOM.0,
289            VKey::Pa1 => VK_PA1.0,
290            VKey::OemClear => VK_OEM_CLEAR.0,
291            VKey::Vk0 => VK_0.0,
292            VKey::Vk1 => VK_1.0,
293            VKey::Vk2 => VK_2.0,
294            VKey::Vk3 => VK_3.0,
295            VKey::Vk4 => VK_4.0,
296            VKey::Vk5 => VK_5.0,
297            VKey::Vk6 => VK_6.0,
298            VKey::Vk7 => VK_7.0,
299            VKey::Vk8 => VK_8.0,
300            VKey::Vk9 => VK_9.0,
301            VKey::A => VK_A.0,
302            VKey::B => VK_B.0,
303            VKey::C => VK_C.0,
304            VKey::D => VK_D.0,
305            VKey::E => VK_E.0,
306            VKey::F => VK_F.0,
307            VKey::G => VK_G.0,
308            VKey::H => VK_H.0,
309            VKey::I => VK_I.0,
310            VKey::J => VK_J.0,
311            VKey::K => VK_K.0,
312            VKey::L => VK_L.0,
313            VKey::M => VK_M.0,
314            VKey::N => VK_N.0,
315            VKey::O => VK_O.0,
316            VKey::P => VK_P.0,
317            VKey::Q => VK_Q.0,
318            VKey::R => VK_R.0,
319            VKey::S => VK_S.0,
320            VKey::T => VK_T.0,
321            VKey::U => VK_U.0,
322            VKey::V => VK_V.0,
323            VKey::W => VK_W.0,
324            VKey::X => VK_X.0,
325            VKey::Y => VK_Y.0,
326            VKey::Z => VK_Z.0,
327            VKey::CustomKeyCode(vk) => *vk,
328        }
329    }
330
331    /// Returns a `VKey` based a Windows Virtual-Key (VK) code.
332    ///
333    /// # See Also
334    /// - [Microsoft Virtual-Key Codes](https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)
335    ///
336    pub const fn from_vk_code(vk_code: u16) -> VKey {
337        use windows::Win32::UI::Input::KeyboardAndMouse::*;
338        match vk_code {
339            _ if vk_code == VK_BACK.0 => VKey::Back,
340            _ if vk_code == VK_TAB.0 => VKey::Tab,
341            _ if vk_code == VK_CLEAR.0 => VKey::Clear,
342            _ if vk_code == VK_RETURN.0 => VKey::Return,
343            _ if vk_code == VK_SHIFT.0 => VKey::Shift,
344            _ if vk_code == VK_CONTROL.0 => VKey::Control,
345            _ if vk_code == VK_MENU.0 => VKey::Menu,
346            _ if vk_code == VK_PAUSE.0 => VKey::Pause,
347            _ if vk_code == VK_CAPITAL.0 => VKey::Capital,
348            _ if vk_code == VK_ESCAPE.0 => VKey::Escape,
349            _ if vk_code == VK_SPACE.0 => VKey::Space,
350            _ if vk_code == VK_PRIOR.0 => VKey::Prior,
351            _ if vk_code == VK_NEXT.0 => VKey::Next,
352            _ if vk_code == VK_END.0 => VKey::End,
353            _ if vk_code == VK_HOME.0 => VKey::Home,
354            _ if vk_code == VK_LEFT.0 => VKey::Left,
355            _ if vk_code == VK_UP.0 => VKey::Up,
356            _ if vk_code == VK_RIGHT.0 => VKey::Right,
357            _ if vk_code == VK_DOWN.0 => VKey::Down,
358            _ if vk_code == VK_SELECT.0 => VKey::Select,
359            _ if vk_code == VK_PRINT.0 => VKey::Print,
360            _ if vk_code == VK_EXECUTE.0 => VKey::Execute,
361            _ if vk_code == VK_SNAPSHOT.0 => VKey::Snapshot,
362            _ if vk_code == VK_INSERT.0 => VKey::Insert,
363            _ if vk_code == VK_DELETE.0 => VKey::Delete,
364            _ if vk_code == VK_HELP.0 => VKey::Help,
365            _ if vk_code == VK_LWIN.0 => VKey::LWin,
366            _ if vk_code == VK_RWIN.0 => VKey::RWin,
367            _ if vk_code == VK_APPS.0 => VKey::Apps,
368            _ if vk_code == VK_SLEEP.0 => VKey::Sleep,
369            _ if vk_code == VK_NUMPAD0.0 => VKey::Numpad0,
370            _ if vk_code == VK_NUMPAD1.0 => VKey::Numpad1,
371            _ if vk_code == VK_NUMPAD2.0 => VKey::Numpad2,
372            _ if vk_code == VK_NUMPAD3.0 => VKey::Numpad3,
373            _ if vk_code == VK_NUMPAD4.0 => VKey::Numpad4,
374            _ if vk_code == VK_NUMPAD5.0 => VKey::Numpad5,
375            _ if vk_code == VK_NUMPAD6.0 => VKey::Numpad6,
376            _ if vk_code == VK_NUMPAD7.0 => VKey::Numpad7,
377            _ if vk_code == VK_NUMPAD8.0 => VKey::Numpad8,
378            _ if vk_code == VK_NUMPAD9.0 => VKey::Numpad9,
379            _ if vk_code == VK_MULTIPLY.0 => VKey::Multiply,
380            _ if vk_code == VK_ADD.0 => VKey::Add,
381            _ if vk_code == VK_SEPARATOR.0 => VKey::Separator,
382            _ if vk_code == VK_SUBTRACT.0 => VKey::Subtract,
383            _ if vk_code == VK_DECIMAL.0 => VKey::Decimal,
384            _ if vk_code == VK_DIVIDE.0 => VKey::Divide,
385            _ if vk_code == VK_F1.0 => VKey::F1,
386            _ if vk_code == VK_F2.0 => VKey::F2,
387            _ if vk_code == VK_F3.0 => VKey::F3,
388            _ if vk_code == VK_F4.0 => VKey::F4,
389            _ if vk_code == VK_F5.0 => VKey::F5,
390            _ if vk_code == VK_F6.0 => VKey::F6,
391            _ if vk_code == VK_F7.0 => VKey::F7,
392            _ if vk_code == VK_F8.0 => VKey::F8,
393            _ if vk_code == VK_F9.0 => VKey::F9,
394            _ if vk_code == VK_F10.0 => VKey::F10,
395            _ if vk_code == VK_F11.0 => VKey::F11,
396            _ if vk_code == VK_F12.0 => VKey::F12,
397            _ if vk_code == VK_F13.0 => VKey::F13,
398            _ if vk_code == VK_F14.0 => VKey::F14,
399            _ if vk_code == VK_F15.0 => VKey::F15,
400            _ if vk_code == VK_F16.0 => VKey::F16,
401            _ if vk_code == VK_F17.0 => VKey::F17,
402            _ if vk_code == VK_F18.0 => VKey::F18,
403            _ if vk_code == VK_F19.0 => VKey::F19,
404            _ if vk_code == VK_F20.0 => VKey::F20,
405            _ if vk_code == VK_F21.0 => VKey::F21,
406            _ if vk_code == VK_F22.0 => VKey::F22,
407            _ if vk_code == VK_F23.0 => VKey::F23,
408            _ if vk_code == VK_F24.0 => VKey::F24,
409            _ if vk_code == VK_NUMLOCK.0 => VKey::Numlock,
410            _ if vk_code == VK_SCROLL.0 => VKey::Scroll,
411            _ if vk_code == VK_LSHIFT.0 => VKey::LShift,
412            _ if vk_code == VK_RSHIFT.0 => VKey::RShift,
413            _ if vk_code == VK_LCONTROL.0 => VKey::LControl,
414            _ if vk_code == VK_RCONTROL.0 => VKey::RControl,
415            _ if vk_code == VK_LMENU.0 => VKey::LMenu,
416            _ if vk_code == VK_RMENU.0 => VKey::RMenu,
417            _ if vk_code == VK_BROWSER_BACK.0 => VKey::BrowserBack,
418            _ if vk_code == VK_BROWSER_FORWARD.0 => VKey::BrowserForward,
419            _ if vk_code == VK_BROWSER_REFRESH.0 => VKey::BrowserRefresh,
420            _ if vk_code == VK_BROWSER_STOP.0 => VKey::BrowserStop,
421            _ if vk_code == VK_BROWSER_SEARCH.0 => VKey::BrowserSearch,
422            _ if vk_code == VK_BROWSER_FAVORITES.0 => VKey::BrowserFavorites,
423            _ if vk_code == VK_BROWSER_HOME.0 => VKey::BrowserHome,
424            _ if vk_code == VK_VOLUME_MUTE.0 => VKey::VolumeMute,
425            _ if vk_code == VK_VOLUME_DOWN.0 => VKey::VolumeDown,
426            _ if vk_code == VK_VOLUME_UP.0 => VKey::VolumeUp,
427            _ if vk_code == VK_MEDIA_NEXT_TRACK.0 => VKey::MediaNextTrack,
428            _ if vk_code == VK_MEDIA_PREV_TRACK.0 => VKey::MediaPrevTrack,
429            _ if vk_code == VK_MEDIA_STOP.0 => VKey::MediaStop,
430            _ if vk_code == VK_MEDIA_PLAY_PAUSE.0 => VKey::MediaPlayPause,
431            _ if vk_code == VK_LAUNCH_MAIL.0 => VKey::LaunchMail,
432            _ if vk_code == VK_LAUNCH_MEDIA_SELECT.0 => VKey::LaunchMediaSelect,
433            _ if vk_code == VK_LAUNCH_APP1.0 => VKey::LaunchApp1,
434            _ if vk_code == VK_LAUNCH_APP2.0 => VKey::LaunchApp2,
435            _ if vk_code == VK_OEM_1.0 => VKey::Oem1,
436            _ if vk_code == VK_OEM_PLUS.0 => VKey::OemPlus,
437            _ if vk_code == VK_OEM_COMMA.0 => VKey::OemComma,
438            _ if vk_code == VK_OEM_MINUS.0 => VKey::OemMinus,
439            _ if vk_code == VK_OEM_PERIOD.0 => VKey::OemPeriod,
440            _ if vk_code == VK_OEM_2.0 => VKey::Oem2,
441            _ if vk_code == VK_OEM_3.0 => VKey::Oem3,
442            _ if vk_code == VK_OEM_4.0 => VKey::Oem4,
443            _ if vk_code == VK_OEM_5.0 => VKey::Oem5,
444            _ if vk_code == VK_OEM_6.0 => VKey::Oem6,
445            _ if vk_code == VK_OEM_7.0 => VKey::Oem7,
446            _ if vk_code == VK_OEM_8.0 => VKey::Oem8,
447            _ if vk_code == VK_OEM_102.0 => VKey::Oem102,
448            _ if vk_code == VK_ATTN.0 => VKey::Attn,
449            _ if vk_code == VK_CRSEL.0 => VKey::Crsel,
450            _ if vk_code == VK_EXSEL.0 => VKey::Exsel,
451            _ if vk_code == VK_PLAY.0 => VKey::Play,
452            _ if vk_code == VK_ZOOM.0 => VKey::Zoom,
453            _ if vk_code == VK_PA1.0 => VKey::Pa1,
454            _ if vk_code == VK_OEM_CLEAR.0 => VKey::OemClear,
455            _ if vk_code == VK_0.0 => VKey::Vk0,
456            _ if vk_code == VK_1.0 => VKey::Vk1,
457            _ if vk_code == VK_2.0 => VKey::Vk2,
458            _ if vk_code == VK_3.0 => VKey::Vk3,
459            _ if vk_code == VK_4.0 => VKey::Vk4,
460            _ if vk_code == VK_5.0 => VKey::Vk5,
461            _ if vk_code == VK_6.0 => VKey::Vk6,
462            _ if vk_code == VK_7.0 => VKey::Vk7,
463            _ if vk_code == VK_8.0 => VKey::Vk8,
464            _ if vk_code == VK_9.0 => VKey::Vk9,
465            _ if vk_code == VK_A.0 => VKey::A,
466            _ if vk_code == VK_B.0 => VKey::B,
467            _ if vk_code == VK_C.0 => VKey::C,
468            _ if vk_code == VK_D.0 => VKey::D,
469            _ if vk_code == VK_E.0 => VKey::E,
470            _ if vk_code == VK_F.0 => VKey::F,
471            _ if vk_code == VK_G.0 => VKey::G,
472            _ if vk_code == VK_H.0 => VKey::H,
473            _ if vk_code == VK_I.0 => VKey::I,
474            _ if vk_code == VK_J.0 => VKey::J,
475            _ if vk_code == VK_K.0 => VKey::K,
476            _ if vk_code == VK_L.0 => VKey::L,
477            _ if vk_code == VK_M.0 => VKey::M,
478            _ if vk_code == VK_N.0 => VKey::N,
479            _ if vk_code == VK_O.0 => VKey::O,
480            _ if vk_code == VK_P.0 => VKey::P,
481            _ if vk_code == VK_Q.0 => VKey::Q,
482            _ if vk_code == VK_R.0 => VKey::R,
483            _ if vk_code == VK_S.0 => VKey::S,
484            _ if vk_code == VK_T.0 => VKey::T,
485            _ if vk_code == VK_U.0 => VKey::U,
486            _ if vk_code == VK_V.0 => VKey::V,
487            _ if vk_code == VK_W.0 => VKey::W,
488            _ if vk_code == VK_X.0 => VKey::X,
489            _ if vk_code == VK_Y.0 => VKey::Y,
490            _ if vk_code == VK_Z.0 => VKey::Z,
491            _ => VKey::CustomKeyCode(vk_code),
492        }
493    }
494
495    /// Creates a `VKey` from a string representation of the key.
496    ///
497    /// NOTE: Certain common aliases for keys are accepted in addition to the Microsoft Virtual-Key Codes names
498    ///
499    /// WIN maps to `VKey::LWin`
500    /// CTRL maps to `VKey::Control`
501    /// ALT maps to `VKey::Menu`
502    ///
503    /// # See Also
504    /// - [Microsoft Virtual-Key Codes](https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)
505    ///
506    pub fn from_keyname(name: &str) -> Result<VKey, WHKError> {
507        let name = name.to_ascii_uppercase();
508
509        // 1 byte hex code => Use the raw keycode value
510        if name.len() >= 3 && name.len() <= 6 && name.starts_with("0x") || name.starts_with("0X") {
511            return if let Ok(val) = u16::from_str_radix(&name[2..], 16) {
512                Ok(Self::from_vk_code(val))
513            } else {
514                Err(WHKError::InvalidKey(name))
515            };
516        }
517
518        Ok(match name.trim_start_matches("VK_") {
519            "BACK" => VKey::Back,
520            "TAB" => VKey::Tab,
521            "CLEAR" => VKey::Clear,
522            "RETURN" => VKey::Return,
523            "SHIFT" => VKey::Shift,
524            "CTRL" => VKey::Control,
525            "CONTROL" => VKey::Control,
526            "ALT" => VKey::Menu,
527            "MENU" => VKey::Menu,
528            "PAUSE" => VKey::Pause,
529            "CAPITAL" => VKey::Capital,
530            "ESCAPE" => VKey::Escape,
531            "SPACE" => VKey::Space,
532            "PRIOR" => VKey::Prior,
533            "NEXT" => VKey::Next,
534            "END" => VKey::End,
535            "HOME" => VKey::Home,
536            "LEFT" => VKey::Left,
537            "UP" => VKey::Up,
538            "RIGHT" => VKey::Right,
539            "DOWN" => VKey::Down,
540            "SELECT" => VKey::Select,
541            "PRINT" => VKey::Print,
542            "EXECUTE" => VKey::Execute,
543            "SNAPSHOT" => VKey::Snapshot,
544            "INSERT" => VKey::Insert,
545            "DELETE" => VKey::Delete,
546            "HELP" => VKey::Help,
547            "WIN" => VKey::LWin,
548            "LWIN" => VKey::LWin,
549            "RWIN" => VKey::RWin,
550            "APPS" => VKey::Apps,
551            "SLEEP" => VKey::Sleep,
552            "NUMPAD0" => VKey::Numpad0,
553            "NUMPAD1" => VKey::Numpad1,
554            "NUMPAD2" => VKey::Numpad2,
555            "NUMPAD3" => VKey::Numpad3,
556            "NUMPAD4" => VKey::Numpad4,
557            "NUMPAD5" => VKey::Numpad5,
558            "NUMPAD6" => VKey::Numpad6,
559            "NUMPAD7" => VKey::Numpad7,
560            "NUMPAD8" => VKey::Numpad8,
561            "NUMPAD9" => VKey::Numpad9,
562            "MULTIPLY" => VKey::Multiply,
563            "ADD" => VKey::Add,
564            "SEPARATOR" => VKey::Separator,
565            "SUBTRACT" => VKey::Subtract,
566            "DECIMAL" => VKey::Decimal,
567            "DIVIDE" => VKey::Divide,
568            "F1" => VKey::F1,
569            "F2" => VKey::F2,
570            "F3" => VKey::F3,
571            "F4" => VKey::F4,
572            "F5" => VKey::F5,
573            "F6" => VKey::F6,
574            "F7" => VKey::F7,
575            "F8" => VKey::F8,
576            "F9" => VKey::F9,
577            "F10" => VKey::F10,
578            "F11" => VKey::F11,
579            "F12" => VKey::F12,
580            "F13" => VKey::F13,
581            "F14" => VKey::F14,
582            "F15" => VKey::F15,
583            "F16" => VKey::F16,
584            "F17" => VKey::F17,
585            "F18" => VKey::F18,
586            "F19" => VKey::F19,
587            "F20" => VKey::F20,
588            "F21" => VKey::F21,
589            "F22" => VKey::F22,
590            "F23" => VKey::F23,
591            "F24" => VKey::F24,
592            "NUMLOCK" => VKey::Numlock,
593            "SCROLL" => VKey::Scroll,
594            "LSHIFT" => VKey::LShift,
595            "RSHIFT" => VKey::RShift,
596            "LCTRL" => VKey::LControl,
597            "LCONTROL" => VKey::LControl,
598            "RCTRL" => VKey::RControl,
599            "RCONTROL" => VKey::RControl,
600            "LALT" => VKey::LMenu,
601            "LMENU" => VKey::LMenu,
602            "RALT" => VKey::RMenu,
603            "RMENU" => VKey::RMenu,
604            "BROWSER_BACK" => VKey::BrowserBack,
605            "BROWSER_FORWARD" => VKey::BrowserForward,
606            "BROWSER_REFRESH" => VKey::BrowserRefresh,
607            "BROWSER_STOP" => VKey::BrowserStop,
608            "BROWSER_SEARCH" => VKey::BrowserSearch,
609            "BROWSER_FAVORITES" => VKey::BrowserFavorites,
610            "BROWSER_HOME" => VKey::BrowserHome,
611            "VOLUME_MUTE" => VKey::VolumeMute,
612            "VOLUME_DOWN" => VKey::VolumeDown,
613            "VOLUME_UP" => VKey::VolumeUp,
614            "MEDIA_NEXT_TRACK" => VKey::MediaNextTrack,
615            "MEDIA_PREV_TRACK" => VKey::MediaPrevTrack,
616            "MEDIA_STOP" => VKey::MediaStop,
617            "MEDIA_PLAY_PAUSE" => VKey::MediaPlayPause,
618            "LAUNCH_MAIL" => VKey::LaunchMail,
619            "LAUNCH_MEDIA_SELECT" => VKey::LaunchMediaSelect,
620            "LAUNCH_APP1" => VKey::LaunchApp1,
621            "LAUNCH_APP2" => VKey::LaunchApp2,
622            "OEM_1" => VKey::Oem1,
623            "OEM_PLUS" => VKey::OemPlus,
624            "OEM_COMMA" => VKey::OemComma,
625            "OEM_MINUS" => VKey::OemMinus,
626            "OEM_PERIOD" => VKey::OemPeriod,
627            "OEM_2" => VKey::Oem2,
628            "OEM_3" => VKey::Oem3,
629            "OEM_4" => VKey::Oem4,
630            "OEM_5" => VKey::Oem5,
631            "OEM_6" => VKey::Oem6,
632            "OEM_7" => VKey::Oem7,
633            "OEM_8" => VKey::Oem8,
634            "OEM_102" => VKey::Oem102,
635            "ATTN" => VKey::Attn,
636            "CRSEL" => VKey::Crsel,
637            "EXSEL" => VKey::Exsel,
638            "PLAY" => VKey::Play,
639            "ZOOM" => VKey::Zoom,
640            "PA1" => VKey::Pa1,
641            "OEM_CLEAR" => VKey::OemClear,
642            "0" => VKey::Vk0,
643            "1" => VKey::Vk1,
644            "2" => VKey::Vk2,
645            "3" => VKey::Vk3,
646            "4" => VKey::Vk4,
647            "5" => VKey::Vk5,
648            "6" => VKey::Vk6,
649            "7" => VKey::Vk7,
650            "8" => VKey::Vk8,
651            "9" => VKey::Vk9,
652            "A" => VKey::A,
653            "B" => VKey::B,
654            "C" => VKey::C,
655            "D" => VKey::D,
656            "E" => VKey::E,
657            "F" => VKey::F,
658            "G" => VKey::G,
659            "H" => VKey::H,
660            "I" => VKey::I,
661            "J" => VKey::J,
662            "K" => VKey::K,
663            "L" => VKey::L,
664            "M" => VKey::M,
665            "N" => VKey::N,
666            "O" => VKey::O,
667            "P" => VKey::P,
668            "Q" => VKey::Q,
669            "R" => VKey::R,
670            "S" => VKey::S,
671            "T" => VKey::T,
672            "U" => VKey::U,
673            "V" => VKey::V,
674            "W" => VKey::W,
675            "X" => VKey::X,
676            "Y" => VKey::Y,
677            "Z" => VKey::Z,
678            _ => return Err(WHKError::InvalidKey(name)),
679        })
680    }
681}
682
683impl std::fmt::Display for VKey {
684    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
685        let name = match self {
686            VKey::Back => "VK_BACK",
687            VKey::Tab => "VK_TAB",
688            VKey::Clear => "VK_CLEAR",
689            VKey::Return => "VK_RETURN",
690            VKey::Shift => "VK_SHIFT",
691            VKey::Control => "VK_CONTROL",
692            VKey::Menu => "VK_MENU",
693            VKey::Pause => "VK_PAUSE",
694            VKey::Capital => "VK_CAPITAL",
695            VKey::Escape => "VK_ESCAPE",
696            VKey::Space => "VK_SPACE",
697            VKey::Prior => "VK_PRIOR",
698            VKey::Next => "VK_NEXT",
699            VKey::End => "VK_END",
700            VKey::Home => "VK_HOME",
701            VKey::Left => "VK_LEFT",
702            VKey::Up => "VK_UP",
703            VKey::Right => "VK_RIGHT",
704            VKey::Down => "VK_DOWN",
705            VKey::Select => "VK_SELECT",
706            VKey::Print => "VK_PRINT",
707            VKey::Execute => "VK_EXECUTE",
708            VKey::Snapshot => "VK_SNAPSHOT",
709            VKey::Insert => "VK_INSERT",
710            VKey::Delete => "VK_DELETE",
711            VKey::Help => "VK_HELP",
712            VKey::LWin => "VK_LWIN",
713            VKey::RWin => "VK_RWIN",
714            VKey::Apps => "VK_APPS",
715            VKey::Sleep => "VK_SLEEP",
716            VKey::Numpad0 => "VK_NUMPAD0",
717            VKey::Numpad1 => "VK_NUMPAD1",
718            VKey::Numpad2 => "VK_NUMPAD2",
719            VKey::Numpad3 => "VK_NUMPAD3",
720            VKey::Numpad4 => "VK_NUMPAD4",
721            VKey::Numpad5 => "VK_NUMPAD5",
722            VKey::Numpad6 => "VK_NUMPAD6",
723            VKey::Numpad7 => "VK_NUMPAD7",
724            VKey::Numpad8 => "VK_NUMPAD8",
725            VKey::Numpad9 => "VK_NUMPAD9",
726            VKey::Multiply => "VK_MULTIPLY",
727            VKey::Add => "VK_ADD",
728            VKey::Separator => "VK_SEPARATOR",
729            VKey::Subtract => "VK_SUBTRACT",
730            VKey::Decimal => "VK_DECIMAL",
731            VKey::Divide => "VK_DIVIDE",
732            VKey::F1 => "VK_F1",
733            VKey::F2 => "VK_F2",
734            VKey::F3 => "VK_F3",
735            VKey::F4 => "VK_F4",
736            VKey::F5 => "VK_F5",
737            VKey::F6 => "VK_F6",
738            VKey::F7 => "VK_F7",
739            VKey::F8 => "VK_F8",
740            VKey::F9 => "VK_F9",
741            VKey::F10 => "VK_F10",
742            VKey::F11 => "VK_F11",
743            VKey::F12 => "VK_F12",
744            VKey::F13 => "VK_F13",
745            VKey::F14 => "VK_F14",
746            VKey::F15 => "VK_F15",
747            VKey::F16 => "VK_F16",
748            VKey::F17 => "VK_F17",
749            VKey::F18 => "VK_F18",
750            VKey::F19 => "VK_F19",
751            VKey::F20 => "VK_F20",
752            VKey::F21 => "VK_F21",
753            VKey::F22 => "VK_F22",
754            VKey::F23 => "VK_F23",
755            VKey::F24 => "VK_F24",
756            VKey::Numlock => "VK_NUMLOCK",
757            VKey::Scroll => "VK_SCROLL",
758            VKey::LShift => "VK_LSHIFT",
759            VKey::RShift => "VK_RSHIFT",
760            VKey::LControl => "VK_LCONTROL",
761            VKey::RControl => "VK_RCONTROL",
762            VKey::LMenu => "VK_LMENU",
763            VKey::RMenu => "VK_RMENU",
764            VKey::BrowserBack => "VK_BROWSER_BACK",
765            VKey::BrowserForward => "VK_BROWSER_FORWARD",
766            VKey::BrowserRefresh => "VK_BROWSER_REFRESH",
767            VKey::BrowserStop => "VK_BROWSER_STOP",
768            VKey::BrowserSearch => "VK_BROWSER_SEARCH",
769            VKey::BrowserFavorites => "VK_BROWSER_FAVORITES",
770            VKey::BrowserHome => "VK_BROWSER_HOME",
771            VKey::VolumeMute => "VK_VOLUME_MUTE",
772            VKey::VolumeDown => "VK_VOLUME_DOWN",
773            VKey::VolumeUp => "VK_VOLUME_UP",
774            VKey::MediaNextTrack => "VK_MEDIA_NEXT_TRACK",
775            VKey::MediaPrevTrack => "VK_MEDIA_PREV_TRACK",
776            VKey::MediaStop => "VK_MEDIA_STOP",
777            VKey::MediaPlayPause => "VK_MEDIA_PLAY_PAUSE",
778            VKey::LaunchMail => "VK_LAUNCH_MAIL",
779            VKey::LaunchMediaSelect => "VK_LAUNCH_MEDIA_SELECT",
780            VKey::LaunchApp1 => "VK_LAUNCH_APP1",
781            VKey::LaunchApp2 => "VK_LAUNCH_APP2",
782            VKey::Oem1 => "VK_OEM_1",
783            VKey::OemPlus => "VK_OEM_PLUS",
784            VKey::OemComma => "VK_OEM_COMMA",
785            VKey::OemMinus => "VK_OEM_MINUS",
786            VKey::OemPeriod => "VK_OEM_PERIOD",
787            VKey::Oem2 => "VK_OEM_2",
788            VKey::Oem3 => "VK_OEM_3",
789            VKey::Oem4 => "VK_OEM_4",
790            VKey::Oem5 => "VK_OEM_5",
791            VKey::Oem6 => "VK_OEM_6",
792            VKey::Oem7 => "VK_OEM_7",
793            VKey::Oem8 => "VK_OEM_8",
794            VKey::Oem102 => "VK_OEM_102",
795            VKey::Attn => "VK_ATTN",
796            VKey::Crsel => "VK_CRSEL",
797            VKey::Exsel => "VK_EXSEL",
798            VKey::Play => "VK_PLAY",
799            VKey::Zoom => "VK_ZOOM",
800            VKey::Pa1 => "VK_PA1",
801            VKey::OemClear => "VK_OEM_CLEAR",
802            VKey::Vk0 => "VK_0",
803            VKey::Vk1 => "VK_1",
804            VKey::Vk2 => "VK_2",
805            VKey::Vk3 => "VK_3",
806            VKey::Vk4 => "VK_4",
807            VKey::Vk5 => "VK_5",
808            VKey::Vk6 => "VK_6",
809            VKey::Vk7 => "VK_7",
810            VKey::Vk8 => "VK_8",
811            VKey::Vk9 => "VK_9",
812            VKey::A => "VK_A",
813            VKey::B => "VK_B",
814            VKey::C => "VK_C",
815            VKey::D => "VK_D",
816            VKey::E => "VK_E",
817            VKey::F => "VK_F",
818            VKey::G => "VK_G",
819            VKey::H => "VK_H",
820            VKey::I => "VK_I",
821            VKey::J => "VK_J",
822            VKey::K => "VK_K",
823            VKey::L => "VK_L",
824            VKey::M => "VK_M",
825            VKey::N => "VK_N",
826            VKey::O => "VK_O",
827            VKey::P => "VK_P",
828            VKey::Q => "VK_Q",
829            VKey::R => "VK_R",
830            VKey::S => "VK_S",
831            VKey::T => "VK_T",
832            VKey::U => "VK_U",
833            VKey::V => "VK_V",
834            VKey::W => "VK_W",
835            VKey::X => "VK_X",
836            VKey::Y => "VK_Y",
837            VKey::Z => "VK_Z",
838            VKey::CustomKeyCode(vk) => return write!(f, "Custom({})", vk),
839        };
840        write!(f, "{}", name)
841    }
842}
843
844impl std::str::FromStr for VKey {
845    type Err = WHKError;
846    fn from_str(s: &str) -> Result<Self, Self::Err> {
847        VKey::from_keyname(s)
848    }
849}
850
851impl PartialEq<VKey> for VKey {
852    fn eq(&self, other: &VKey) -> bool {
853        self.to_vk_code() == other.to_vk_code()
854    }
855}
856
857impl Eq for VKey {}
858
859impl Hash for VKey {
860    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
861        self.to_vk_code().hash(state);
862    }
863}
864
865#[cfg(test)]
866mod tests {
867    use super::*;
868
869    #[test]
870    fn test_to_vk_code() {
871        assert_eq!(VKey::Back.to_vk_code(), 0x08); // VK_BACK
872        assert_eq!(VKey::Return.to_vk_code(), 0x0D); // VK_RETURN
873        assert_eq!(VKey::Space.to_vk_code(), 0x20); // VK_SPACE
874        assert_eq!(VKey::F12.to_vk_code(), 0x7B); // VK_F12
875        assert_eq!(VKey::CustomKeyCode(1234).to_vk_code(), 1234); // Custom key
876    }
877
878    #[test]
879    fn test_from_keyname() {
880        assert_eq!(VKey::from_keyname("BACK").unwrap(), VKey::Back);
881        assert_eq!(VKey::from_keyname("VK_BACK").unwrap(), VKey::Back);
882        assert_eq!(VKey::from_keyname("RETURN").unwrap(), VKey::Return);
883        assert_eq!(
884            VKey::from_keyname("0x29").unwrap(),
885            VKey::CustomKeyCode(0x29)
886        );
887        assert!(VKey::from_keyname("INVALID_KEY").is_err());
888    }
889
890    #[test]
891    fn test_display() {
892        assert_eq!(format!("{}", VKey::Back), "VK_BACK");
893        assert_eq!(format!("{}", VKey::Return), "VK_RETURN");
894        assert_eq!(format!("{}", VKey::CustomKeyCode(1234)), "Custom(1234)");
895    }
896
897    #[test]
898    fn test_from_str() {
899        use std::str::FromStr;
900        assert_eq!(VKey::from_str("BACK").unwrap(), VKey::Back);
901        assert_eq!(VKey::from_str("VK_BACK").unwrap(), VKey::Back);
902        assert_eq!(VKey::from_str("INVALID_KEY").is_err(), true);
903    }
904
905    #[test]
906    fn test_partial_eq() {
907        assert_eq!(VKey::Back, VKey::Back); // Identical keys
908        assert_eq!(VKey::CustomKeyCode(1234), VKey::CustomKeyCode(1234)); // Same custom key
909        assert_ne!(VKey::CustomKeyCode(1234), VKey::CustomKeyCode(5678)); // Different custom keys
910    }
911
912    #[test]
913    fn test_custom_keycode_range() {
914        assert_eq!(VKey::CustomKeyCode(0).to_vk_code(), 0);
915        assert_eq!(VKey::CustomKeyCode(65535).to_vk_code(), 65535); // Maximum value for u16
916    }
917}