use super::ModifiersKey;
use crate::error::HotkeyError;
use std::{fmt::Display, hash::Hash};
#[derive(Debug, Clone, Copy)]
pub enum VirtualKey {
Back,
Backspace,
Tab,
Clear,
Return,
Shift,
Control,
Menu,
Pause,
Capital,
Escape,
Space,
Prior,
Next,
End,
Home,
Left,
Up,
Right,
Down,
Select,
Print,
Execute,
Snapshot,
Insert,
Delete,
Help,
LWin,
RWin,
Apps,
Sleep,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
NumpadMultiply,
NumpadAdd,
Separator,
NumpadSubtract,
NumpadDecimal,
NumpadDivide,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
Numlock,
Scroll,
LShift,
RShift,
LControl,
RControl,
LMenu,
RMenu,
BrowserBack,
BrowserForward,
BrowserRefresh,
BrowserStop,
BrowserSearch,
BrowserFavorites,
BrowserHome,
VolumeMute,
VolumeDown,
VolumeUp,
MediaNextTrack,
MediaPrevTrack,
MediaStop,
MediaPlayPause,
LaunchMail,
LaunchMediaSelect,
LaunchApp1,
LaunchApp2,
Semicolon,
Plus,
Comma,
Minus,
Period,
Slash,
Backquote,
BracketLeft,
Backslash,
BracketRight,
Quote,
Oem8,
Oem102,
Attn,
Crsel,
Exsel,
Play,
Zoom,
Pa1,
OemClear,
Vk0,
Vk1,
Vk2,
Vk3,
Vk4,
Vk5,
Vk6,
Vk7,
Vk8,
Vk9,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
CustomKeyCode(u16),
}
impl TryFrom<&str> for VirtualKey {
type Error = HotkeyError;
fn try_from(val: &str) -> Result<Self, Self::Error> {
Self::from_keyname(val)
}
}
impl TryFrom<char> for VirtualKey {
type Error = HotkeyError;
fn try_from(ch: char) -> Result<Self, Self::Error> {
match ch.to_ascii_uppercase() {
ch @ ('A'..='Z' | '0'..='9') => Ok(Self::CustomKeyCode(ch as u16)),
ch => Err(HotkeyError::InvalidKeyChar(ch)),
}
}
}
impl VirtualKey {
pub const fn from_char(ch: char) -> Result<Self, HotkeyError> {
match ch.to_ascii_uppercase() {
ch @ ('A'..='Z' | '0'..='9') => Ok(Self::CustomKeyCode(ch as u16)),
ch => Err(HotkeyError::InvalidKeyChar(ch)),
}
}
pub const fn to_vk_code(&self) -> u16 {
use windows_sys::Win32::UI::Input::KeyboardAndMouse::*;
match self {
VirtualKey::Back | VirtualKey::Backspace => VK_BACK,
VirtualKey::Tab => VK_TAB,
VirtualKey::Clear => VK_CLEAR,
VirtualKey::Return => VK_RETURN,
VirtualKey::Shift => VK_SHIFT,
VirtualKey::Control => VK_CONTROL,
VirtualKey::Menu => VK_MENU,
VirtualKey::Pause => VK_PAUSE,
VirtualKey::Capital => VK_CAPITAL,
VirtualKey::Escape => VK_ESCAPE,
VirtualKey::Space => VK_SPACE,
VirtualKey::Prior => VK_PRIOR,
VirtualKey::Next => VK_NEXT,
VirtualKey::End => VK_END,
VirtualKey::Home => VK_HOME,
VirtualKey::Left => VK_LEFT,
VirtualKey::Up => VK_UP,
VirtualKey::Right => VK_RIGHT,
VirtualKey::Down => VK_DOWN,
VirtualKey::Select => VK_SELECT,
VirtualKey::Print => VK_PRINT,
VirtualKey::Execute => VK_EXECUTE,
VirtualKey::Snapshot => VK_SNAPSHOT,
VirtualKey::Insert => VK_INSERT,
VirtualKey::Delete => VK_DELETE,
VirtualKey::Help => VK_HELP,
VirtualKey::LWin => VK_LWIN,
VirtualKey::RWin => VK_RWIN,
VirtualKey::Apps => VK_APPS,
VirtualKey::Sleep => VK_SLEEP,
VirtualKey::Numpad0 => VK_NUMPAD0,
VirtualKey::Numpad1 => VK_NUMPAD1,
VirtualKey::Numpad2 => VK_NUMPAD2,
VirtualKey::Numpad3 => VK_NUMPAD3,
VirtualKey::Numpad4 => VK_NUMPAD4,
VirtualKey::Numpad5 => VK_NUMPAD5,
VirtualKey::Numpad6 => VK_NUMPAD6,
VirtualKey::Numpad7 => VK_NUMPAD7,
VirtualKey::Numpad8 => VK_NUMPAD8,
VirtualKey::Numpad9 => VK_NUMPAD9,
VirtualKey::NumpadMultiply => VK_MULTIPLY,
VirtualKey::NumpadAdd => VK_ADD,
VirtualKey::Separator => VK_SEPARATOR,
VirtualKey::NumpadSubtract => VK_SUBTRACT,
VirtualKey::NumpadDecimal => VK_DECIMAL,
VirtualKey::NumpadDivide => VK_DIVIDE,
VirtualKey::F1 => VK_F1,
VirtualKey::F2 => VK_F2,
VirtualKey::F3 => VK_F3,
VirtualKey::F4 => VK_F4,
VirtualKey::F5 => VK_F5,
VirtualKey::F6 => VK_F6,
VirtualKey::F7 => VK_F7,
VirtualKey::F8 => VK_F8,
VirtualKey::F9 => VK_F9,
VirtualKey::F10 => VK_F10,
VirtualKey::F11 => VK_F11,
VirtualKey::F12 => VK_F12,
VirtualKey::F13 => VK_F13,
VirtualKey::F14 => VK_F14,
VirtualKey::F15 => VK_F15,
VirtualKey::F16 => VK_F16,
VirtualKey::F17 => VK_F17,
VirtualKey::F18 => VK_F18,
VirtualKey::F19 => VK_F19,
VirtualKey::F20 => VK_F20,
VirtualKey::F21 => VK_F21,
VirtualKey::F22 => VK_F22,
VirtualKey::F23 => VK_F23,
VirtualKey::F24 => VK_F24,
VirtualKey::Numlock => VK_NUMLOCK,
VirtualKey::Scroll => VK_SCROLL,
VirtualKey::LShift => VK_LSHIFT,
VirtualKey::RShift => VK_RSHIFT,
VirtualKey::LControl => VK_LCONTROL,
VirtualKey::RControl => VK_RCONTROL,
VirtualKey::LMenu => VK_LMENU,
VirtualKey::RMenu => VK_RMENU,
VirtualKey::BrowserBack => VK_BROWSER_BACK,
VirtualKey::BrowserForward => VK_BROWSER_FORWARD,
VirtualKey::BrowserRefresh => VK_BROWSER_REFRESH,
VirtualKey::BrowserStop => VK_BROWSER_STOP,
VirtualKey::BrowserSearch => VK_BROWSER_SEARCH,
VirtualKey::BrowserFavorites => VK_BROWSER_FAVORITES,
VirtualKey::BrowserHome => VK_BROWSER_HOME,
VirtualKey::VolumeMute => VK_VOLUME_MUTE,
VirtualKey::VolumeDown => VK_VOLUME_DOWN,
VirtualKey::VolumeUp => VK_VOLUME_UP,
VirtualKey::MediaNextTrack => VK_MEDIA_NEXT_TRACK,
VirtualKey::MediaPrevTrack => VK_MEDIA_PREV_TRACK,
VirtualKey::MediaStop => VK_MEDIA_STOP,
VirtualKey::MediaPlayPause => VK_MEDIA_PLAY_PAUSE,
VirtualKey::LaunchMail => VK_LAUNCH_MAIL,
VirtualKey::LaunchMediaSelect => VK_LAUNCH_MEDIA_SELECT,
VirtualKey::LaunchApp1 => VK_LAUNCH_APP1,
VirtualKey::LaunchApp2 => VK_LAUNCH_APP2,
VirtualKey::Semicolon => VK_OEM_1,
VirtualKey::Plus => VK_OEM_PLUS,
VirtualKey::Comma => VK_OEM_COMMA,
VirtualKey::Minus => VK_OEM_MINUS,
VirtualKey::Period => VK_OEM_PERIOD,
VirtualKey::Slash => VK_OEM_2,
VirtualKey::Backquote => VK_OEM_3,
VirtualKey::BracketLeft => VK_OEM_4,
VirtualKey::Backslash => VK_OEM_5,
VirtualKey::BracketRight => VK_OEM_6,
VirtualKey::Quote => VK_OEM_7,
VirtualKey::Oem8 => VK_OEM_8,
VirtualKey::Oem102 => VK_OEM_102,
VirtualKey::Attn => VK_ATTN,
VirtualKey::Crsel => VK_CRSEL,
VirtualKey::Exsel => VK_EXSEL,
VirtualKey::Play => VK_PLAY,
VirtualKey::Zoom => VK_ZOOM,
VirtualKey::Pa1 => VK_PA1,
VirtualKey::OemClear => VK_OEM_CLEAR,
VirtualKey::Vk0 => b'0' as u16,
VirtualKey::Vk1 => b'1' as u16,
VirtualKey::Vk2 => b'2' as u16,
VirtualKey::Vk3 => b'3' as u16,
VirtualKey::Vk4 => b'4' as u16,
VirtualKey::Vk5 => b'5' as u16,
VirtualKey::Vk6 => b'6' as u16,
VirtualKey::Vk7 => b'7' as u16,
VirtualKey::Vk8 => b'8' as u16,
VirtualKey::Vk9 => b'9' as u16,
VirtualKey::A => b'A' as u16,
VirtualKey::B => b'B' as u16,
VirtualKey::C => b'C' as u16,
VirtualKey::D => b'D' as u16,
VirtualKey::E => b'E' as u16,
VirtualKey::F => b'F' as u16,
VirtualKey::G => b'G' as u16,
VirtualKey::H => b'H' as u16,
VirtualKey::I => b'I' as u16,
VirtualKey::J => b'J' as u16,
VirtualKey::K => b'K' as u16,
VirtualKey::L => b'L' as u16,
VirtualKey::M => b'M' as u16,
VirtualKey::N => b'N' as u16,
VirtualKey::O => b'O' as u16,
VirtualKey::P => b'P' as u16,
VirtualKey::Q => b'Q' as u16,
VirtualKey::R => b'R' as u16,
VirtualKey::S => b'S' as u16,
VirtualKey::T => b'T' as u16,
VirtualKey::U => b'U' as u16,
VirtualKey::V => b'V' as u16,
VirtualKey::W => b'W' as u16,
VirtualKey::X => b'X' as u16,
VirtualKey::Y => b'Y' as u16,
VirtualKey::Z => b'Z' as u16,
VirtualKey::CustomKeyCode(vk) => *vk,
}
}
pub fn from_keyname(val: &str) -> Result<Self, HotkeyError> {
let val = val.to_ascii_uppercase();
if val.as_bytes().len() == 1 {
let val = val.as_bytes()[0];
if val.is_ascii_uppercase() || val.is_ascii_digit() {
return Ok(Self::CustomKeyCode(val as u16));
}
}
if val.len() >= 3 && val.len() <= 6 && val.starts_with("0x") || val.starts_with("0X") {
if let Ok(val) = u16::from_str_radix(&val[2..], 16) {
return Ok(Self::CustomKeyCode(val));
} else {
return Err(HotkeyError::InvalidKey(val));
}
}
Ok(match val.trim() {
"BACK" | "BACKSPACE" => Self::Back,
"TAB" => Self::Tab,
"CLEAR" => Self::Clear,
"RETURN" => Self::Return,
"SHIFT" => Self::Shift,
"CONTROL" | "CTRL" => Self::Control,
"MENU" | "ALT" => Self::Menu,
"PAUSE" => Self::Pause,
"CAPITAL" => Self::Capital,
"ESCAPE" | "ESC" => Self::Escape,
"SPACE" => Self::Space,
"PRIOR" => Self::Prior,
"NEXT" => Self::Next,
"END" => Self::End,
"HOME" => Self::Home,
"LEFT" => Self::Left,
"UP" => Self::Up,
"RIGHT" => Self::Right,
"DOWN" => Self::Down,
"SELECT" => Self::Select,
"PRINT" => Self::Print,
"EXECUTE" => Self::Execute,
"SNAPSHOT" => Self::Snapshot,
"INSERT" => Self::Insert,
"DELETE" => Self::Delete,
"HELP" => Self::Help,
"LWIN" => Self::LWin,
"RWIN" => Self::RWin,
"APPS" => Self::Apps,
"SLEEP" => Self::Sleep,
"NUMPAD0" | "NUM0" => Self::Numpad0,
"NUMPAD1" | "NUM1" => Self::Numpad1,
"NUMPAD2" | "NUM2" => Self::Numpad2,
"NUMPAD3" | "NUM3" => Self::Numpad3,
"NUMPAD4" | "NUM4" => Self::Numpad4,
"NUMPAD5" | "NUM5" => Self::Numpad5,
"NUMPAD6" | "NUM6" => Self::Numpad6,
"NUMPAD7" | "NUM7" => Self::Numpad7,
"NUMPAD8" | "NUM8" => Self::Numpad8,
"NUMPAD9" | "NUM9" => Self::Numpad9,
"NUMPADMULTIPLY" | "NUMMULTIPLY" => Self::NumpadMultiply,
"NUMPADADD" | "NUMADD" | "NUMPADPLUS" | "NUMPLUS" => Self::NumpadAdd,
"NUMPADSEPARATOR" | "NUMSEPARATOR" => Self::Separator,
"NUMPADSUBTRACT" | "NUMSUBTRACT" | "NUMPADMINUS" | "NUMMINUS" => Self::NumpadSubtract,
"NUMPADDECIMAL" | "NUMDECIMAL" => Self::NumpadDecimal,
"NUMPADDIVIDE" | "NUMDIVIDE" => Self::NumpadDivide,
"F1" => Self::F1,
"F2" => Self::F2,
"F3" => Self::F3,
"F4" => Self::F4,
"F5" => Self::F5,
"F6" => Self::F6,
"F7" => Self::F7,
"F8" => Self::F8,
"F9" => Self::F9,
"F10" => Self::F10,
"F11" => Self::F11,
"F12" => Self::F12,
"F13" => Self::F13,
"F14" => Self::F14,
"F15" => Self::F15,
"F16" => Self::F16,
"F17" => Self::F17,
"F18" => Self::F18,
"F19" => Self::F19,
"F20" => Self::F20,
"F21" => Self::F21,
"F22" => Self::F22,
"F23" => Self::F23,
"F24" => Self::F24,
"NUMLOCK" => Self::Numlock,
"SCROLL" => Self::Scroll,
"LSHIFT" => Self::LShift,
"RSHIFT" => Self::RShift,
"LCONTROL" | "LCTRL" => Self::LControl,
"RCONTROL" | "RCTRL" => Self::RControl,
"LMENU" | "LALT" => Self::LMenu,
"RMENU" | "RALT" => Self::RMenu,
"BROWSER_BACK" => Self::BrowserBack,
"BROWSER_FORWARD" => Self::BrowserForward,
"BROWSER_REFRESH" => Self::BrowserRefresh,
"BROWSER_STOP" => Self::BrowserStop,
"BROWSER_SEARCH" => Self::BrowserSearch,
"BROWSER_FAVORITES" => Self::BrowserFavorites,
"BROWSER_HOME" => Self::BrowserHome,
"VOLUME_MUTE" => Self::VolumeMute,
"VOLUME_DOWN" => Self::VolumeDown,
"VOLUME_UP" => Self::VolumeUp,
"MEDIA_NEXT_TRACK" => Self::MediaNextTrack,
"MEDIA_PREV_TRACK" => Self::MediaPrevTrack,
"MEDIA_STOP" => Self::MediaStop,
"MEDIA_PLAY_PAUSE" => Self::MediaPlayPause,
"LAUNCH_MAIL" => Self::LaunchMail,
"LAUNCH_MEDIA_SELECT" => Self::LaunchMediaSelect,
"LAUNCH_APP1" => Self::LaunchApp1,
"LAUNCH_APP2" => Self::LaunchApp2,
"SEMICOLON" | "OEM_1" | ";" | ":" => Self::Semicolon,
"ADD" | "PLUS" | "+" => Self::Plus,
"COMMA" | "," => Self::Comma,
"SUBTRACT" | "MINUS" | "-" => Self::Minus,
"PERIOD" | "." => Self::Period,
"SLASH" | "OEM_2" | "/" => Self::Slash,
"BACKQUOTE" | "OEM_3" | "`" => Self::Backquote,
"BRACKETLEFT" | "OEM_4" | "[" | "{" => Self::BracketLeft,
"BACKSLASH" | "OEM_5" | "\\" => Self::Backslash,
"BRACKETRIGHT" | "OEM_6" | "]" | "}" => Self::BracketRight,
"QUOTE" | "OEM_7" | "'" | r#"""# => Self::Quote,
"OEM_8" => Self::Oem8,
"OEM_102" => Self::Oem102,
"ATTN" => Self::Attn,
"CRSEL" => Self::Crsel,
"EXSEL" => Self::Exsel,
"PLAY" => Self::Play,
"ZOOM" => Self::Zoom,
"PA1" => Self::Pa1,
"OEM_CLEAR" => Self::OemClear,
_ => return Err(HotkeyError::InvalidKey(val)),
})
}
}
impl Display for VirtualKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use windows_sys::Win32::UI::Input::KeyboardAndMouse::*;
let code = self.to_vk_code();
if code >= 'A' as u16 && code <= 'Z' as u16 {
return write!(f, "{}", code as u8 as char);
}
if code >= '0' as u16 && code <= '9' as u16 {
return write!(f, "{}", code as u8 as char);
}
let val = match code {
VK_BACK => "VK_BACK",
VK_TAB => "VK_TAB",
VK_CLEAR => "VK_CLEAR",
VK_RETURN => "VK_RETURN",
VK_SHIFT => "VK_SHIFT",
VK_CONTROL => "VK_CONTROL",
VK_MENU => "VK_MENU",
VK_PAUSE => "VK_PAUSE",
VK_CAPITAL => "VK_CAPITAL",
VK_ESCAPE => "VK_ESCAPE",
VK_SPACE => "VK_SPACE",
VK_PRIOR => "VK_PRIOR",
VK_NEXT => "VK_NEXT",
VK_END => "VK_END",
VK_HOME => "VK_HOME",
VK_LEFT => "VK_LEFT",
VK_UP => "VK_UP",
VK_RIGHT => "VK_RIGHT",
VK_DOWN => "VK_DOWN",
VK_SELECT => "VK_SELECT",
VK_PRINT => "VK_PRINT",
VK_EXECUTE => "VK_EXECUTE",
VK_SNAPSHOT => "VK_SNAPSHOT",
VK_INSERT => "VK_INSERT",
VK_DELETE => "VK_DELETE",
VK_HELP => "VK_HELP",
VK_LWIN => "VK_LWIN",
VK_RWIN => "VK_RWIN",
VK_APPS => "VK_APPS",
VK_SLEEP => "VK_SLEEP",
VK_NUMPAD0 => "VK_NUMPAD0",
VK_NUMPAD1 => "VK_NUMPAD1",
VK_NUMPAD2 => "VK_NUMPAD2",
VK_NUMPAD3 => "VK_NUMPAD3",
VK_NUMPAD4 => "VK_NUMPAD4",
VK_NUMPAD5 => "VK_NUMPAD5",
VK_NUMPAD6 => "VK_NUMPAD6",
VK_NUMPAD7 => "VK_NUMPAD7",
VK_NUMPAD8 => "VK_NUMPAD8",
VK_NUMPAD9 => "VK_NUMPAD9",
VK_MULTIPLY => "VK_MULTIPLY",
VK_ADD => "VK_ADD",
VK_SEPARATOR => "VK_SEPARATOR",
VK_SUBTRACT => "VK_SUBTRACT",
VK_DECIMAL => "VK_DECIMAL",
VK_DIVIDE => "VK_DIVIDE",
VK_F1 => "VK_F1",
VK_F2 => "VK_F2",
VK_F3 => "VK_F3",
VK_F4 => "VK_F4",
VK_F5 => "VK_F5",
VK_F6 => "VK_F6",
VK_F7 => "VK_F7",
VK_F8 => "VK_F8",
VK_F9 => "VK_F9",
VK_F10 => "VK_F10",
VK_F11 => "VK_F11",
VK_F12 => "VK_F12",
VK_F13 => "VK_F13",
VK_F14 => "VK_F14",
VK_F15 => "VK_F15",
VK_F16 => "VK_F16",
VK_F17 => "VK_F17",
VK_F18 => "VK_F18",
VK_F19 => "VK_F19",
VK_F20 => "VK_F20",
VK_F21 => "VK_F21",
VK_F22 => "VK_F22",
VK_F23 => "VK_F23",
VK_F24 => "VK_F24",
VK_NUMLOCK => "VK_NUMLOCK",
VK_SCROLL => "VK_SCROLL",
VK_LSHIFT => "VK_LSHIFT",
VK_RSHIFT => "VK_RSHIFT",
VK_LCONTROL => "VK_LCONTROL",
VK_RCONTROL => "VK_RCONTROL",
VK_LMENU => "VK_LMENU",
VK_RMENU => "VK_RMENU",
VK_BROWSER_BACK => "VK_BROWSER_BACK",
VK_BROWSER_FORWARD => "VK_BROWSER_FORWARD",
VK_BROWSER_REFRESH => "VK_BROWSER_REFRESH",
VK_BROWSER_STOP => "VK_BROWSER_STOP",
VK_BROWSER_SEARCH => "VK_BROWSER_SEARCH",
VK_BROWSER_FAVORITES => "VK_BROWSER_FAVORITES",
VK_BROWSER_HOME => "VK_BROWSER_HOME",
VK_VOLUME_MUTE => "VK_VOLUME_MUTE",
VK_VOLUME_DOWN => "VK_VOLUME_DOWN",
VK_VOLUME_UP => "VK_VOLUME_UP",
VK_MEDIA_NEXT_TRACK => "VK_MEDIA_NEXT_TRACK",
VK_MEDIA_PREV_TRACK => "VK_MEDIA_PREV_TRACK",
VK_MEDIA_STOP => "VK_MEDIA_STOP",
VK_MEDIA_PLAY_PAUSE => "VK_MEDIA_PLAY_PAUSE",
VK_LAUNCH_MAIL => "VK_LAUNCH_MAIL",
VK_LAUNCH_MEDIA_SELECT => "VK_LAUNCH_MEDIA_SELECT",
VK_LAUNCH_APP1 => "VK_LAUNCH_APP1",
VK_LAUNCH_APP2 => "VK_LAUNCH_APP2",
VK_OEM_1 => "VK_OEM_1",
VK_OEM_PLUS => "VK_OEM_PLUS",
VK_OEM_COMMA => "VK_OEM_COMMA",
VK_OEM_MINUS => "VK_OEM_MINUS",
VK_OEM_PERIOD => "VK_OEM_PERIOD",
VK_OEM_2 => "VK_OEM_2",
VK_OEM_3 => "VK_OEM_3",
VK_OEM_4 => "VK_OEM_4",
VK_OEM_5 => "VK_OEM_5",
VK_OEM_6 => "VK_OEM_6",
VK_OEM_7 => "VK_OEM_7",
VK_OEM_8 => "VK_OEM_8",
VK_OEM_102 => "VK_OEM_102",
VK_ATTN => "VK_ATTN",
VK_CRSEL => "VK_CRSEL",
VK_EXSEL => "VK_EXSEL",
VK_PLAY => "VK_PLAY",
VK_ZOOM => "VK_ZOOM",
VK_PA1 => "VK_PA1",
VK_OEM_CLEAR => "VK_OEM_CLEAR",
vk_code => return write!(f, "0x{:x}", vk_code),
};
write!(f, "{}", val)
}
}
impl PartialEq<VirtualKey> for VirtualKey {
fn eq(&self, other: &VirtualKey) -> bool {
self.to_vk_code() == other.to_vk_code()
}
}
impl Eq for VirtualKey {}
impl Hash for VirtualKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.to_vk_code().hash(state);
}
}
impl TryInto<ModifiersKey> for VirtualKey {
type Error = ();
fn try_into(self) -> Result<ModifiersKey, Self::Error> {
use windows_sys::Win32::UI::Input::KeyboardAndMouse::*;
Ok(match self.to_vk_code() {
VK_MENU | VK_LMENU | VK_RMENU => ModifiersKey::Alt,
VK_CONTROL | VK_LCONTROL | VK_RCONTROL => ModifiersKey::Ctrl,
VK_SHIFT | VK_LSHIFT | VK_RSHIFT => ModifiersKey::Shift,
VK_LWIN | VK_RWIN => ModifiersKey::Win,
_ => return Err(()),
})
}
}