use crate::{Key, RawCode};
macro_rules! decl {
($($const_name:ident = $code:expr => $variant:ident);* $(;)?) => {
$(const $const_name: u32 = $code;)*
pub(crate) fn key_from_vk(vk: u32) -> Key {
match vk {
$($const_name => Key::$variant,)*
other => Key::Unknown(RawCode(other)),
}
}
};
}
decl! {
VK_LSHIFT = 0xA0 => ShiftLeft;
VK_RSHIFT = 0xA1 => ShiftRight;
VK_LCONTROL = 0xA2 => ControlLeft;
VK_RCONTROL = 0xA3 => ControlRight;
VK_LMENU = 0xA4 => AltLeft;
VK_RMENU = 0xA5 => AltRight;
VK_LWIN = 0x5B => MetaLeft;
VK_RWIN = 0x5C => MetaRight;
VK_CAPITAL = 0x14 => CapsLock;
VK_BACK = 0x08 => Backspace;
VK_TAB = 0x09 => Tab;
VK_RETURN = 0x0D => Enter;
VK_ESCAPE = 0x1B => Escape;
VK_SPACE = 0x20 => Space;
VK_LEFT = 0x25 => ArrowLeft;
VK_UP = 0x26 => ArrowUp;
VK_RIGHT = 0x27 => ArrowRight;
VK_DOWN = 0x28 => ArrowDown;
VK_HOME = 0x24 => Home;
VK_END = 0x23 => End;
VK_PRIOR = 0x21 => PageUp;
VK_NEXT = 0x22 => PageDown;
VK_INSERT = 0x2D => Insert;
VK_DELETE = 0x2E => Delete;
VK_SNAPSHOT = 0x2C => PrintScreen;
VK_SCROLL = 0x91 => ScrollLock;
VK_PAUSE = 0x13 => Pause;
VK_NUMLOCK = 0x90 => NumLock;
VK_APPS = 0x5D => Menu;
VK_0 = 0x30 => Digit0;
VK_1 = 0x31 => Digit1;
VK_2 = 0x32 => Digit2;
VK_3 = 0x33 => Digit3;
VK_4 = 0x34 => Digit4;
VK_5 = 0x35 => Digit5;
VK_6 = 0x36 => Digit6;
VK_7 = 0x37 => Digit7;
VK_8 = 0x38 => Digit8;
VK_9 = 0x39 => Digit9;
VK_A = 0x41 => A;
VK_B = 0x42 => B;
VK_C = 0x43 => C;
VK_D = 0x44 => D;
VK_E = 0x45 => E;
VK_F = 0x46 => F;
VK_G = 0x47 => G;
VK_H = 0x48 => H;
VK_I = 0x49 => I;
VK_J = 0x4A => J;
VK_K = 0x4B => K;
VK_L = 0x4C => L;
VK_M = 0x4D => M;
VK_N = 0x4E => N;
VK_O = 0x4F => O;
VK_P = 0x50 => P;
VK_Q = 0x51 => Q;
VK_R = 0x52 => R;
VK_S = 0x53 => S;
VK_T = 0x54 => T;
VK_U = 0x55 => U;
VK_V = 0x56 => V;
VK_W = 0x57 => W;
VK_X = 0x58 => X;
VK_Y = 0x59 => Y;
VK_Z = 0x5A => Z;
VK_F1 = 0x70 => F1;
VK_F2 = 0x71 => F2;
VK_F3 = 0x72 => F3;
VK_F4 = 0x73 => F4;
VK_F5 = 0x74 => F5;
VK_F6 = 0x75 => F6;
VK_F7 = 0x76 => F7;
VK_F8 = 0x77 => F8;
VK_F9 = 0x78 => F9;
VK_F10 = 0x79 => F10;
VK_F11 = 0x7A => F11;
VK_F12 = 0x7B => F12;
VK_F13 = 0x7C => F13;
VK_F14 = 0x7D => F14;
VK_F15 = 0x7E => F15;
VK_F16 = 0x7F => F16;
VK_F17 = 0x80 => F17;
VK_F18 = 0x81 => F18;
VK_F19 = 0x82 => F19;
VK_F20 = 0x83 => F20;
VK_F21 = 0x84 => F21;
VK_F22 = 0x85 => F22;
VK_F23 = 0x86 => F23;
VK_F24 = 0x87 => F24;
VK_NUMPAD0 = 0x60 => Numpad0;
VK_NUMPAD1 = 0x61 => Numpad1;
VK_NUMPAD2 = 0x62 => Numpad2;
VK_NUMPAD3 = 0x63 => Numpad3;
VK_NUMPAD4 = 0x64 => Numpad4;
VK_NUMPAD5 = 0x65 => Numpad5;
VK_NUMPAD6 = 0x66 => Numpad6;
VK_NUMPAD7 = 0x67 => Numpad7;
VK_NUMPAD8 = 0x68 => Numpad8;
VK_NUMPAD9 = 0x69 => Numpad9;
VK_MULTIPLY = 0x6A => NumpadMultiply;
VK_ADD = 0x6B => NumpadAdd;
VK_SUBTRACT = 0x6D => NumpadSubtract;
VK_DECIMAL = 0x6E => NumpadDecimal;
VK_DIVIDE = 0x6F => NumpadDivide;
VK_OEM_1 = 0xBA => Semicolon;
VK_OEM_PLUS = 0xBB => Equal;
VK_OEM_COMMA = 0xBC => Comma;
VK_OEM_MINUS = 0xBD => Minus;
VK_OEM_PERIOD = 0xBE => Period;
VK_OEM_2 = 0xBF => Slash;
VK_OEM_3 = 0xC0 => Backtick;
VK_OEM_4 = 0xDB => BracketLeft;
VK_OEM_5 = 0xDC => Backslash;
VK_OEM_6 = 0xDD => BracketRight;
VK_OEM_7 = 0xDE => Quote;
VK_OEM_102 = 0xE2 => IntlBackslash;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip_known_vks() {
let codes = [
VK_A,
VK_Z,
VK_LSHIFT,
VK_RSHIFT,
VK_LWIN,
VK_RWIN,
VK_LMENU,
VK_RMENU,
VK_LCONTROL,
VK_RCONTROL,
VK_ESCAPE,
VK_SPACE,
VK_RETURN,
VK_F1,
VK_F24,
VK_UP,
VK_NUMPAD5,
];
for c in codes {
assert!(
!matches!(key_from_vk(c), Key::Unknown(_)),
"VK 0x{c:X} should map to a named Key"
);
}
}
#[test]
fn left_right_modifiers_are_distinct() {
assert_ne!(key_from_vk(VK_LSHIFT), key_from_vk(VK_RSHIFT));
assert_ne!(key_from_vk(VK_LCONTROL), key_from_vk(VK_RCONTROL));
assert_ne!(key_from_vk(VK_LMENU), key_from_vk(VK_RMENU));
assert_ne!(key_from_vk(VK_LWIN), key_from_vk(VK_RWIN));
}
#[test]
fn unknown_vk_round_trips() {
assert_eq!(key_from_vk(0xFFFE), Key::Unknown(RawCode(0xFFFE)));
}
}