use num_enum::{FromPrimitive, IntoPrimitive};
use std::{borrow::Cow, fmt};
#[allow(clippy::wildcard_imports)]
use windows::Win32::UI::Input::KeyboardAndMouse::*;
#[allow(clippy::cast_possible_truncation)]
const fn convert(key: VIRTUAL_KEY) -> u8 {
assert!(key.0 <= u8::MAX as u16);
key.0 as u8
}
#[repr(u8)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(
Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive, PartialOrd, Ord, Hash,
)]
pub enum VirtualKey {
LButton = convert(VK_LBUTTON),
RButton = convert(VK_RBUTTON),
Cancel = convert(VK_CANCEL),
MButton = convert(VK_MBUTTON),
XButton1 = convert(VK_XBUTTON1),
XButton2 = convert(VK_XBUTTON2),
Back = convert(VK_BACK),
Tab = convert(VK_TAB),
Clear = convert(VK_CLEAR),
Return = convert(VK_RETURN),
Shift = convert(VK_SHIFT),
Control = convert(VK_CONTROL),
Menu = convert(VK_MENU),
Pause = convert(VK_PAUSE),
Capital = convert(VK_CAPITAL),
LShift = convert(VK_LSHIFT),
RShift = convert(VK_RSHIFT),
LControl = convert(VK_LCONTROL),
RControl = convert(VK_RCONTROL),
LMenu = convert(VK_LMENU),
RMenu = convert(VK_RMENU),
Space = convert(VK_SPACE),
PageUp = convert(VK_PRIOR),
PageDown = convert(VK_NEXT),
End = convert(VK_END),
Home = convert(VK_HOME),
Left = convert(VK_LEFT),
Up = convert(VK_UP),
Right = convert(VK_RIGHT),
Down = convert(VK_DOWN),
Esc = convert(VK_ESCAPE),
Key0 = convert(VK_0),
Key1 = convert(VK_1),
Key2 = convert(VK_2),
Key3 = convert(VK_3),
Key4 = convert(VK_4),
Key5 = convert(VK_5),
Key6 = convert(VK_6),
Key7 = convert(VK_7),
Key8 = convert(VK_8),
Key9 = convert(VK_9),
A = convert(VK_A),
B = convert(VK_B),
C = convert(VK_C),
D = convert(VK_D),
E = convert(VK_E),
F = convert(VK_F),
G = convert(VK_G),
H = convert(VK_H),
I = convert(VK_I),
J = convert(VK_J),
K = convert(VK_K),
L = convert(VK_L),
M = convert(VK_M),
N = convert(VK_N),
O = convert(VK_O),
P = convert(VK_P),
Q = convert(VK_Q),
R = convert(VK_R),
S = convert(VK_S),
T = convert(VK_T),
U = convert(VK_U),
V = convert(VK_V),
W = convert(VK_W),
X = convert(VK_X),
Y = convert(VK_Y),
Z = convert(VK_Z),
F1 = convert(VK_F1),
F2 = convert(VK_F2),
F3 = convert(VK_F3),
F4 = convert(VK_F4),
F5 = convert(VK_F5),
F6 = convert(VK_F6),
F7 = convert(VK_F7),
F8 = convert(VK_F8),
F9 = convert(VK_F9),
F10 = convert(VK_F10),
F11 = convert(VK_F11),
F12 = convert(VK_F12),
F13 = convert(VK_F13),
F14 = convert(VK_F14),
F15 = convert(VK_F15),
F16 = convert(VK_F16),
F17 = convert(VK_F17),
F18 = convert(VK_F18),
F19 = convert(VK_F19),
F20 = convert(VK_F20),
F21 = convert(VK_F21),
F22 = convert(VK_F22),
F23 = convert(VK_F23),
F24 = convert(VK_F24),
Insert = convert(VK_INSERT),
Delete = convert(VK_DELETE),
Snapshot = convert(VK_SNAPSHOT),
Scroll = convert(VK_SCROLL),
NumLock = convert(VK_NUMLOCK),
Apps = convert(VK_APPS),
Oem1 = convert(VK_OEM_1),
Oem2 = convert(VK_OEM_2),
Oem3 = convert(VK_OEM_3),
Oem4 = convert(VK_OEM_4),
Oem5 = convert(VK_OEM_5),
Oem6 = convert(VK_OEM_6),
Oem7 = convert(VK_OEM_7),
Oem8 = convert(VK_OEM_8),
Oem102 = convert(VK_OEM_102),
#[num_enum(catch_all)]
Other(u8),
}
impl VirtualKey {
#[must_use]
pub fn to_str(&self) -> Cow<'static, str> {
match self {
Self::LButton => Cow::Borrowed("LButton"),
Self::RButton => Cow::Borrowed("RButton"),
Self::Cancel => Cow::Borrowed("Cancel"),
Self::MButton => Cow::Borrowed("MButton"),
Self::XButton1 => Cow::Borrowed("XButton1"),
Self::XButton2 => Cow::Borrowed("XButton2"),
Self::Back => Cow::Borrowed("Backspace"),
Self::Tab => Cow::Borrowed("Tab"),
Self::Clear => Cow::Borrowed("Clear"),
Self::Return => Cow::Borrowed("Enter"),
Self::Shift => Cow::Borrowed("Shift"),
Self::Control => Cow::Borrowed("Ctrl"),
Self::Menu => Cow::Borrowed("Menu"),
Self::Pause => Cow::Borrowed("Pause"),
Self::Capital => Cow::Borrowed("CapsLock"),
Self::LShift => Cow::Borrowed("LShift"),
Self::RShift => Cow::Borrowed("RShift"),
Self::LControl => Cow::Borrowed("LControl"),
Self::RControl => Cow::Borrowed("RControl"),
Self::LMenu => Cow::Borrowed("LMenu"),
Self::RMenu => Cow::Borrowed("RMenu"),
Self::Space => Cow::Borrowed("Space"),
Self::Esc => Cow::Borrowed("Esc"),
Self::A => Cow::Borrowed("A"),
Self::B => Cow::Borrowed("B"),
Self::C => Cow::Borrowed("C"),
Self::D => Cow::Borrowed("D"),
Self::E => Cow::Borrowed("E"),
Self::F => Cow::Borrowed("F"),
Self::G => Cow::Borrowed("G"),
Self::H => Cow::Borrowed("H"),
Self::I => Cow::Borrowed("I"),
Self::J => Cow::Borrowed("J"),
Self::K => Cow::Borrowed("K"),
Self::L => Cow::Borrowed("L"),
Self::M => Cow::Borrowed("M"),
Self::N => Cow::Borrowed("N"),
Self::O => Cow::Borrowed("O"),
Self::P => Cow::Borrowed("P"),
Self::Q => Cow::Borrowed("Q"),
Self::R => Cow::Borrowed("R"),
Self::S => Cow::Borrowed("S"),
Self::T => Cow::Borrowed("T"),
Self::U => Cow::Borrowed("U"),
Self::V => Cow::Borrowed("V"),
Self::W => Cow::Borrowed("W"),
Self::X => Cow::Borrowed("X"),
Self::Y => Cow::Borrowed("Y"),
Self::Z => Cow::Borrowed("Z"),
Self::Key0 => Cow::Borrowed("0"),
Self::Key1 => Cow::Borrowed("1"),
Self::Key2 => Cow::Borrowed("2"),
Self::Key3 => Cow::Borrowed("3"),
Self::Key4 => Cow::Borrowed("4"),
Self::Key5 => Cow::Borrowed("5"),
Self::Key6 => Cow::Borrowed("6"),
Self::Key7 => Cow::Borrowed("7"),
Self::Key8 => Cow::Borrowed("8"),
Self::Key9 => Cow::Borrowed("9"),
Self::F1 => Cow::Borrowed("F1"),
Self::F2 => Cow::Borrowed("F2"),
Self::F3 => Cow::Borrowed("F3"),
Self::F4 => Cow::Borrowed("F4"),
Self::F5 => Cow::Borrowed("F5"),
Self::F6 => Cow::Borrowed("F6"),
Self::F7 => Cow::Borrowed("F7"),
Self::F8 => Cow::Borrowed("F8"),
Self::F9 => Cow::Borrowed("F9"),
Self::F10 => Cow::Borrowed("F10"),
Self::F11 => Cow::Borrowed("F11"),
Self::F12 => Cow::Borrowed("F12"),
Self::F13 => Cow::Borrowed("F13"),
Self::F14 => Cow::Borrowed("F14"),
Self::F15 => Cow::Borrowed("F15"),
Self::F16 => Cow::Borrowed("F16"),
Self::F17 => Cow::Borrowed("F17"),
Self::F18 => Cow::Borrowed("F18"),
Self::F19 => Cow::Borrowed("F19"),
Self::F20 => Cow::Borrowed("F20"),
Self::F21 => Cow::Borrowed("F21"),
Self::F22 => Cow::Borrowed("F22"),
Self::F23 => Cow::Borrowed("F23"),
Self::F24 => Cow::Borrowed("F24"),
Self::Left => Cow::Borrowed("Left"),
Self::Up => Cow::Borrowed("Up"),
Self::Right => Cow::Borrowed("Right"),
Self::Down => Cow::Borrowed("Down"),
Self::Home => Cow::Borrowed("Home"),
Self::End => Cow::Borrowed("End"),
Self::PageUp => Cow::Borrowed("PageUp"),
Self::PageDown => Cow::Borrowed("PageDown"),
Self::Insert => Cow::Borrowed("Insert"),
Self::Delete => Cow::Borrowed("Delete"),
_ => Cow::Owned(format!("VK_0x{:02X}", self.to_raw())),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
self.into()
}
#[must_use]
pub fn from_raw(vk: u8) -> Self {
Self::from_primitive(vk)
}
#[must_use]
pub fn is_modifier(self) -> bool {
matches!(
self,
Self::Shift
| Self::Control
| Self::Menu
| Self::LShift
| Self::RShift
| Self::LControl
| Self::RControl
| Self::LMenu
| Self::RMenu
)
}
#[must_use]
pub fn is_mouse(self) -> bool {
matches!(
self,
Self::LButton | Self::RButton | Self::MButton | Self::XButton1 | Self::XButton2
)
}
}
impl fmt::Display for VirtualKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_str())
}
}
impl TryFrom<VIRTUAL_KEY> for VirtualKey {
type Error = ();
fn try_from(vk: VIRTUAL_KEY) -> Result<Self, Self::Error> {
u8::try_from(vk.0).map(Self::from_raw).map_err(|_| ())
}
}
impl From<VirtualKey> for VIRTUAL_KEY {
fn from(vk: VirtualKey) -> Self {
Self(u16::from(vk.to_raw()))
}
}