win_hotkey/keys/
modifiers.rs

1use super::VirtualKey;
2use crate::error::HotkeyError;
3use std::fmt::Display;
4
5/// Modifier Key for hotkeys.
6///
7/// See: `fsModifiers` from <https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey>
8///
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum ModifiersKey {
11    Alt,
12    Ctrl,
13    Shift,
14    Win,
15    /// This is a virtual modifier key that is used to prevent automatically repeating triggers
16    /// when the hotkey is being held down. When converting to a VirtualKey, this is mapped to KeyCode 0
17    NoRepeat,
18    Non,
19}
20
21impl TryFrom<&str> for ModifiersKey {
22    type Error = HotkeyError;
23
24    fn try_from(val: &str) -> Result<Self, Self::Error> {
25        Self::from_keyname(val)
26    }
27}
28
29impl ModifiersKey {
30    /// Take in a string and interpret it as one of the modifier keys.
31    /// Possible values are:
32    /// - ALT
33    /// - CTRL / CONTROL
34    /// - SHIFT
35    /// - WIN / WINDOWS / SUPER
36    /// - NOREPEAT / NO_REPEAT
37    ///
38    pub fn from_keyname(val: &str) -> Result<Self, HotkeyError> {
39        Ok(match val.to_ascii_uppercase().as_ref() {
40            "ALT" => ModifiersKey::Alt,
41            "CTRL" | "CONTROL" => ModifiersKey::Ctrl,
42            "SHIFT" => ModifiersKey::Shift,
43            "WIN" | "WINDOWS" | "SUPER" => ModifiersKey::Win,
44            "NOREPEAT" | "NO_REPEAT" => ModifiersKey::NoRepeat,
45            "NON" => ModifiersKey::Non,
46            val => return Err(HotkeyError::InvalidKey(val.to_string())),
47        })
48    }
49
50    /// Obtain the modifier code for the `ModifiersKey`.
51    ///
52    /// See: `fsModifiers` from <https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey>
53    ///
54    pub const fn to_mod_code(&self) -> u32 {
55        use windows_sys::Win32::UI::Input::KeyboardAndMouse::*;
56
57        match self {
58            ModifiersKey::Alt => MOD_ALT,
59            ModifiersKey::Ctrl => MOD_CONTROL,
60            ModifiersKey::Shift => MOD_SHIFT,
61            ModifiersKey::Win => MOD_WIN,
62            ModifiersKey::NoRepeat => MOD_NOREPEAT,
63            ModifiersKey::Non => 0,
64        }
65    }
66
67    /// Combine multiple `ModifiersKey`s using bitwise OR
68    ///
69    pub(crate) fn combine(keys: Option<&[ModifiersKey]>) -> u32 {
70        if let Some(keys) = keys {
71            keys.iter().fold(0, |a, b| a | b.to_mod_code())
72        } else {
73            ModifiersKey::Non.to_mod_code()
74        }
75    }
76}
77
78impl Display for ModifiersKey {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        let key = match self {
81            ModifiersKey::Alt => "ALT",
82            ModifiersKey::Ctrl => "CONTROL",
83            ModifiersKey::Shift => "SHIFT",
84            ModifiersKey::Win => "WIN",
85            ModifiersKey::NoRepeat => "NO_REPEAT",
86            ModifiersKey::Non => "NON",
87        };
88        write!(f, "{}", key)
89    }
90}
91
92impl From<ModifiersKey> for VirtualKey {
93    fn from(mk: ModifiersKey) -> VirtualKey {
94        match mk {
95            ModifiersKey::Alt => VirtualKey::Menu,
96            ModifiersKey::Ctrl => VirtualKey::Control,
97            ModifiersKey::Shift => VirtualKey::Shift,
98            ModifiersKey::Win => VirtualKey::LWin,
99            ModifiersKey::NoRepeat | ModifiersKey::Non => VirtualKey::CustomKeyCode(0),
100        }
101    }
102}