use std::fmt;
use std::str::FromStr;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(i32)]
pub enum Key {
#[default]
None = 0,
Cancel = 1,
Back = 2,
Tab = 3,
LineFeed = 4,
Clear = 5,
Return = 6,
Pause = 7,
CapsLock = 8,
HangulMode = 9,
JunjaMode = 10,
FinalMode = 11,
KanjiMode = 12,
Escape = 13,
ImeConvert = 14,
ImeNonConvert = 15,
ImeAccept = 16,
ImeModeChange = 17,
Space = 18,
PageUp = 19,
PageDown = 20,
End = 21,
Home = 22,
Left = 23,
Up = 24,
Right = 25,
Down = 26,
Select = 27,
Print = 28,
Execute = 29,
Snapshot = 30,
Insert = 31,
Delete = 32,
Help = 33,
D0 = 34,
D1 = 35,
D2 = 36,
D3 = 37,
D4 = 38,
D5 = 39,
D6 = 40,
D7 = 41,
D8 = 42,
D9 = 43,
A = 44,
B = 45,
C = 46,
D = 47,
E = 48,
F = 49,
G = 50,
H = 51,
I = 52,
J = 53,
K = 54,
L = 55,
M = 56,
N = 57,
O = 58,
P = 59,
Q = 60,
R = 61,
S = 62,
T = 63,
U = 64,
V = 65,
W = 66,
X = 67,
Y = 68,
Z = 69,
LWin = 70,
RWin = 71,
Apps = 72,
Sleep = 73,
NumPad0 = 74,
NumPad1 = 75,
NumPad2 = 76,
NumPad3 = 77,
NumPad4 = 78,
NumPad5 = 79,
NumPad6 = 80,
NumPad7 = 81,
NumPad8 = 82,
NumPad9 = 83,
Multiply = 84,
Add = 85,
Separator = 86,
Subtract = 87,
Decimal = 88,
Divide = 89,
F1 = 90,
F2 = 91,
F3 = 92,
F4 = 93,
F5 = 94,
F6 = 95,
F7 = 96,
F8 = 97,
F9 = 98,
F10 = 99,
F11 = 100,
F12 = 101,
F13 = 102,
F14 = 103,
F15 = 104,
F16 = 105,
F17 = 106,
F18 = 107,
F19 = 108,
F20 = 109,
F21 = 110,
F22 = 111,
F23 = 112,
F24 = 113,
NumLock = 114,
Scroll = 115,
LeftShift = 116,
RightShift = 117,
LeftCtrl = 118,
RightCtrl = 119,
LeftAlt = 120,
RightAlt = 121,
BrowserBack = 122,
BrowserForward = 123,
BrowserRefresh = 124,
BrowserStop = 125,
BrowserSearch = 126,
BrowserFavorites = 127,
BrowserHome = 128,
VolumeMute = 129,
VolumeDown = 130,
VolumeUp = 131,
MediaNextTrack = 132,
MediaPreviousTrack = 133,
MediaStop = 134,
MediaPlayPause = 135,
LaunchMail = 136,
SelectMedia = 137,
LaunchApplication1 = 138,
LaunchApplication2 = 139,
OemSemicolon = 140,
OemPlus = 141,
OemComma = 142,
OemMinus = 143,
OemPeriod = 144,
OemQuestion = 145,
OemTilde = 146,
AbntC1 = 147,
AbntC2 = 148,
OemOpenBrackets = 149,
OemPipe = 150,
OemCloseBrackets = 151,
OemQuotes = 152,
Oem8 = 153,
OemBackslash = 154,
ImeProcessed = 155,
System = 156,
OemAttn = 157,
OemFinish = 158,
DbeHiragana = 159,
DbeSbcsChar = 160,
DbeDbcsChar = 161,
OemBackTab = 162,
DbeNoRoman = 163,
CrSel = 164,
ExSel = 165,
EraseEof = 166,
Play = 167,
DbeNoCodeInput = 168,
NoName = 169,
DbeEnterDialogConversionMode = 170,
OemClear = 171,
DeadCharProcessed = 172,
FnLeftArrow = 10001,
FnRightArrow = 10002,
FnUpArrow = 10003,
FnDownArrow = 10004,
MediaHome = 100000,
MediaChannelList = 100001,
MediaChannelRaise = 100002,
MediaChannelLower = 100003,
MediaRecord = 100005,
MediaRed = 100010,
MediaGreen = 100011,
MediaYellow = 100012,
MediaBlue = 100013,
MediaMenu = 100020,
MediaMore = 100021,
MediaOption = 100022,
MediaInfo = 100023,
MediaSearch = 100024,
MediaSubtitle = 100025,
MediaTvGuide = 100026,
MediaPreviousChannel = 100027,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseKeyError(pub String);
impl fmt::Display for ParseKeyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Requested value '{}' was not found.", self.0)
}
}
impl std::error::Error for ParseKeyError {}
static NAMES: &[(&str, Key)] = &[
("None", Key::None),
("Cancel", Key::Cancel),
("Back", Key::Back),
("Tab", Key::Tab),
("LineFeed", Key::LineFeed),
("Clear", Key::Clear),
("Return", Key::Return),
("Enter", Key::Return),
("Pause", Key::Pause),
("CapsLock", Key::CapsLock),
("Capital", Key::CapsLock),
("HangulMode", Key::HangulMode),
("KanaMode", Key::HangulMode),
("JunjaMode", Key::JunjaMode),
("FinalMode", Key::FinalMode),
("KanjiMode", Key::KanjiMode),
("HanjaMode", Key::KanjiMode),
("Escape", Key::Escape),
("ImeConvert", Key::ImeConvert),
("ImeNonConvert", Key::ImeNonConvert),
("ImeAccept", Key::ImeAccept),
("ImeModeChange", Key::ImeModeChange),
("Space", Key::Space),
("PageUp", Key::PageUp),
("Prior", Key::PageUp),
("PageDown", Key::PageDown),
("Next", Key::PageDown),
("End", Key::End),
("Home", Key::Home),
("Left", Key::Left),
("Up", Key::Up),
("Right", Key::Right),
("Down", Key::Down),
("Select", Key::Select),
("Print", Key::Print),
("Execute", Key::Execute),
("Snapshot", Key::Snapshot),
("PrintScreen", Key::Snapshot),
("Insert", Key::Insert),
("Delete", Key::Delete),
("Help", Key::Help),
("D0", Key::D0),
("D1", Key::D1),
("D2", Key::D2),
("D3", Key::D3),
("D4", Key::D4),
("D5", Key::D5),
("D6", Key::D6),
("D7", Key::D7),
("D8", Key::D8),
("D9", Key::D9),
("A", Key::A),
("B", Key::B),
("C", Key::C),
("D", Key::D),
("E", Key::E),
("F", Key::F),
("G", Key::G),
("H", Key::H),
("I", Key::I),
("J", Key::J),
("K", Key::K),
("L", Key::L),
("M", Key::M),
("N", Key::N),
("O", Key::O),
("P", Key::P),
("Q", Key::Q),
("R", Key::R),
("S", Key::S),
("T", Key::T),
("U", Key::U),
("V", Key::V),
("W", Key::W),
("X", Key::X),
("Y", Key::Y),
("Z", Key::Z),
("LWin", Key::LWin),
("RWin", Key::RWin),
("Apps", Key::Apps),
("Sleep", Key::Sleep),
("NumPad0", Key::NumPad0),
("NumPad1", Key::NumPad1),
("NumPad2", Key::NumPad2),
("NumPad3", Key::NumPad3),
("NumPad4", Key::NumPad4),
("NumPad5", Key::NumPad5),
("NumPad6", Key::NumPad6),
("NumPad7", Key::NumPad7),
("NumPad8", Key::NumPad8),
("NumPad9", Key::NumPad9),
("Multiply", Key::Multiply),
("Add", Key::Add),
("Separator", Key::Separator),
("Subtract", Key::Subtract),
("Decimal", Key::Decimal),
("Divide", Key::Divide),
("F1", Key::F1),
("F2", Key::F2),
("F3", Key::F3),
("F4", Key::F4),
("F5", Key::F5),
("F6", Key::F6),
("F7", Key::F7),
("F8", Key::F8),
("F9", Key::F9),
("F10", Key::F10),
("F11", Key::F11),
("F12", Key::F12),
("F13", Key::F13),
("F14", Key::F14),
("F15", Key::F15),
("F16", Key::F16),
("F17", Key::F17),
("F18", Key::F18),
("F19", Key::F19),
("F20", Key::F20),
("F21", Key::F21),
("F22", Key::F22),
("F23", Key::F23),
("F24", Key::F24),
("NumLock", Key::NumLock),
("Scroll", Key::Scroll),
("LeftShift", Key::LeftShift),
("RightShift", Key::RightShift),
("LeftCtrl", Key::LeftCtrl),
("RightCtrl", Key::RightCtrl),
("LeftAlt", Key::LeftAlt),
("RightAlt", Key::RightAlt),
("BrowserBack", Key::BrowserBack),
("BrowserForward", Key::BrowserForward),
("BrowserRefresh", Key::BrowserRefresh),
("BrowserStop", Key::BrowserStop),
("BrowserSearch", Key::BrowserSearch),
("BrowserFavorites", Key::BrowserFavorites),
("BrowserHome", Key::BrowserHome),
("VolumeMute", Key::VolumeMute),
("VolumeDown", Key::VolumeDown),
("VolumeUp", Key::VolumeUp),
("MediaNextTrack", Key::MediaNextTrack),
("MediaPreviousTrack", Key::MediaPreviousTrack),
("MediaStop", Key::MediaStop),
("MediaPlayPause", Key::MediaPlayPause),
("LaunchMail", Key::LaunchMail),
("SelectMedia", Key::SelectMedia),
("LaunchApplication1", Key::LaunchApplication1),
("LaunchApplication2", Key::LaunchApplication2),
("OemSemicolon", Key::OemSemicolon),
("Oem1", Key::OemSemicolon),
("OemPlus", Key::OemPlus),
("OemComma", Key::OemComma),
("OemMinus", Key::OemMinus),
("OemPeriod", Key::OemPeriod),
("OemQuestion", Key::OemQuestion),
("Oem2", Key::OemQuestion),
("OemTilde", Key::OemTilde),
("Oem3", Key::OemTilde),
("AbntC1", Key::AbntC1),
("AbntC2", Key::AbntC2),
("OemOpenBrackets", Key::OemOpenBrackets),
("Oem4", Key::OemOpenBrackets),
("OemPipe", Key::OemPipe),
("Oem5", Key::OemPipe),
("OemCloseBrackets", Key::OemCloseBrackets),
("Oem6", Key::OemCloseBrackets),
("OemQuotes", Key::OemQuotes),
("Oem7", Key::OemQuotes),
("Oem8", Key::Oem8),
("OemBackslash", Key::OemBackslash),
("Oem102", Key::OemBackslash),
("ImeProcessed", Key::ImeProcessed),
("System", Key::System),
("OemAttn", Key::OemAttn),
("DbeAlphanumeric", Key::OemAttn),
("OemFinish", Key::OemFinish),
("DbeKatakana", Key::OemFinish),
("DbeHiragana", Key::DbeHiragana),
("OemCopy", Key::DbeHiragana),
("DbeSbcsChar", Key::DbeSbcsChar),
("OemAuto", Key::DbeSbcsChar),
("DbeDbcsChar", Key::DbeDbcsChar),
("OemEnlw", Key::DbeDbcsChar),
("OemBackTab", Key::OemBackTab),
("DbeRoman", Key::OemBackTab),
("DbeNoRoman", Key::DbeNoRoman),
("Attn", Key::DbeNoRoman),
("CrSel", Key::CrSel),
("DbeEnterWordRegisterMode", Key::CrSel),
("ExSel", Key::ExSel),
("DbeEnterImeConfigureMode", Key::ExSel),
("EraseEof", Key::EraseEof),
("DbeFlushString", Key::EraseEof),
("Play", Key::Play),
("DbeCodeInput", Key::Play),
("DbeNoCodeInput", Key::DbeNoCodeInput),
("Zoom", Key::DbeNoCodeInput),
("NoName", Key::NoName),
("DbeDetermineString", Key::NoName),
("DbeEnterDialogConversionMode", Key::DbeEnterDialogConversionMode),
("Pa1", Key::DbeEnterDialogConversionMode),
("OemClear", Key::OemClear),
("DeadCharProcessed", Key::DeadCharProcessed),
("FnLeftArrow", Key::FnLeftArrow),
("FnRightArrow", Key::FnRightArrow),
("FnUpArrow", Key::FnUpArrow),
("FnDownArrow", Key::FnDownArrow),
("MediaHome", Key::MediaHome),
("MediaChannelList", Key::MediaChannelList),
("MediaChannelRaise", Key::MediaChannelRaise),
("MediaChannelLower", Key::MediaChannelLower),
("MediaRecord", Key::MediaRecord),
("MediaRed", Key::MediaRed),
("MediaGreen", Key::MediaGreen),
("MediaYellow", Key::MediaYellow),
("MediaBlue", Key::MediaBlue),
("MediaMenu", Key::MediaMenu),
("MediaMore", Key::MediaMore),
("MediaOption", Key::MediaOption),
("MediaInfo", Key::MediaInfo),
("MediaSearch", Key::MediaSearch),
("MediaSubtitle", Key::MediaSubtitle),
("MediaTvGuide", Key::MediaTvGuide),
("MediaPreviousChannel", Key::MediaPreviousChannel),
];
#[allow(non_upper_case_globals)]
impl Key {
pub const Enter: Key = Key::Return;
pub const Capital: Key = Key::CapsLock;
pub const KanaMode: Key = Key::HangulMode;
pub const HanjaMode: Key = Key::KanjiMode;
pub const Prior: Key = Key::PageUp;
pub const Next: Key = Key::PageDown;
pub const PrintScreen: Key = Key::Snapshot;
pub const Oem1: Key = Key::OemSemicolon;
pub const Oem2: Key = Key::OemQuestion;
pub const Oem3: Key = Key::OemTilde;
pub const Oem4: Key = Key::OemOpenBrackets;
pub const Oem5: Key = Key::OemPipe;
pub const Oem6: Key = Key::OemCloseBrackets;
pub const Oem7: Key = Key::OemQuotes;
pub const Oem102: Key = Key::OemBackslash;
pub const DbeAlphanumeric: Key = Key::OemAttn;
pub const DbeKatakana: Key = Key::OemFinish;
pub const OemCopy: Key = Key::DbeHiragana;
pub const OemAuto: Key = Key::DbeSbcsChar;
pub const OemEnlw: Key = Key::DbeDbcsChar;
pub const DbeRoman: Key = Key::OemBackTab;
pub const Attn: Key = Key::DbeNoRoman;
pub const DbeEnterWordRegisterMode: Key = Key::CrSel;
pub const DbeEnterImeConfigureMode: Key = Key::ExSel;
pub const DbeFlushString: Key = Key::EraseEof;
pub const DbeCodeInput: Key = Key::Play;
pub const Zoom: Key = Key::DbeNoCodeInput;
pub const DbeDetermineString: Key = Key::NoName;
pub const Pa1: Key = Key::DbeEnterDialogConversionMode;
#[inline]
pub const fn value(self) -> i32 {
self as i32
}
pub fn from_value(value: i32) -> Option<Key> {
NAMES.iter().map(|(_, k)| *k).find(|k| *k as i32 == value)
}
pub fn name(self) -> &'static str {
match self {
Key::None => "None",
Key::Cancel => "Cancel",
Key::Back => "Back",
Key::Tab => "Tab",
Key::LineFeed => "LineFeed",
Key::Clear => "Clear",
Key::Return => "Return",
Key::Pause => "Pause",
Key::CapsLock => "CapsLock",
Key::HangulMode => "HangulMode",
Key::JunjaMode => "JunjaMode",
Key::FinalMode => "FinalMode",
Key::KanjiMode => "KanjiMode",
Key::Escape => "Escape",
Key::ImeConvert => "ImeConvert",
Key::ImeNonConvert => "ImeNonConvert",
Key::ImeAccept => "ImeAccept",
Key::ImeModeChange => "ImeModeChange",
Key::Space => "Space",
Key::PageUp => "PageUp",
Key::PageDown => "PageDown",
Key::End => "End",
Key::Home => "Home",
Key::Left => "Left",
Key::Up => "Up",
Key::Right => "Right",
Key::Down => "Down",
Key::Select => "Select",
Key::Print => "Print",
Key::Execute => "Execute",
Key::Snapshot => "Snapshot",
Key::Insert => "Insert",
Key::Delete => "Delete",
Key::Help => "Help",
Key::D0 => "D0",
Key::D1 => "D1",
Key::D2 => "D2",
Key::D3 => "D3",
Key::D4 => "D4",
Key::D5 => "D5",
Key::D6 => "D6",
Key::D7 => "D7",
Key::D8 => "D8",
Key::D9 => "D9",
Key::A => "A",
Key::B => "B",
Key::C => "C",
Key::D => "D",
Key::E => "E",
Key::F => "F",
Key::G => "G",
Key::H => "H",
Key::I => "I",
Key::J => "J",
Key::K => "K",
Key::L => "L",
Key::M => "M",
Key::N => "N",
Key::O => "O",
Key::P => "P",
Key::Q => "Q",
Key::R => "R",
Key::S => "S",
Key::T => "T",
Key::U => "U",
Key::V => "V",
Key::W => "W",
Key::X => "X",
Key::Y => "Y",
Key::Z => "Z",
Key::LWin => "LWin",
Key::RWin => "RWin",
Key::Apps => "Apps",
Key::Sleep => "Sleep",
Key::NumPad0 => "NumPad0",
Key::NumPad1 => "NumPad1",
Key::NumPad2 => "NumPad2",
Key::NumPad3 => "NumPad3",
Key::NumPad4 => "NumPad4",
Key::NumPad5 => "NumPad5",
Key::NumPad6 => "NumPad6",
Key::NumPad7 => "NumPad7",
Key::NumPad8 => "NumPad8",
Key::NumPad9 => "NumPad9",
Key::Multiply => "Multiply",
Key::Add => "Add",
Key::Separator => "Separator",
Key::Subtract => "Subtract",
Key::Decimal => "Decimal",
Key::Divide => "Divide",
Key::F1 => "F1",
Key::F2 => "F2",
Key::F3 => "F3",
Key::F4 => "F4",
Key::F5 => "F5",
Key::F6 => "F6",
Key::F7 => "F7",
Key::F8 => "F8",
Key::F9 => "F9",
Key::F10 => "F10",
Key::F11 => "F11",
Key::F12 => "F12",
Key::F13 => "F13",
Key::F14 => "F14",
Key::F15 => "F15",
Key::F16 => "F16",
Key::F17 => "F17",
Key::F18 => "F18",
Key::F19 => "F19",
Key::F20 => "F20",
Key::F21 => "F21",
Key::F22 => "F22",
Key::F23 => "F23",
Key::F24 => "F24",
Key::NumLock => "NumLock",
Key::Scroll => "Scroll",
Key::LeftShift => "LeftShift",
Key::RightShift => "RightShift",
Key::LeftCtrl => "LeftCtrl",
Key::RightCtrl => "RightCtrl",
Key::LeftAlt => "LeftAlt",
Key::RightAlt => "RightAlt",
Key::BrowserBack => "BrowserBack",
Key::BrowserForward => "BrowserForward",
Key::BrowserRefresh => "BrowserRefresh",
Key::BrowserStop => "BrowserStop",
Key::BrowserSearch => "BrowserSearch",
Key::BrowserFavorites => "BrowserFavorites",
Key::BrowserHome => "BrowserHome",
Key::VolumeMute => "VolumeMute",
Key::VolumeDown => "VolumeDown",
Key::VolumeUp => "VolumeUp",
Key::MediaNextTrack => "MediaNextTrack",
Key::MediaPreviousTrack => "MediaPreviousTrack",
Key::MediaStop => "MediaStop",
Key::MediaPlayPause => "MediaPlayPause",
Key::LaunchMail => "LaunchMail",
Key::SelectMedia => "SelectMedia",
Key::LaunchApplication1 => "LaunchApplication1",
Key::LaunchApplication2 => "LaunchApplication2",
Key::OemSemicolon => "OemSemicolon",
Key::OemPlus => "OemPlus",
Key::OemComma => "OemComma",
Key::OemMinus => "OemMinus",
Key::OemPeriod => "OemPeriod",
Key::OemQuestion => "OemQuestion",
Key::OemTilde => "OemTilde",
Key::AbntC1 => "AbntC1",
Key::AbntC2 => "AbntC2",
Key::OemOpenBrackets => "OemOpenBrackets",
Key::OemPipe => "OemPipe",
Key::OemCloseBrackets => "OemCloseBrackets",
Key::OemQuotes => "OemQuotes",
Key::Oem8 => "Oem8",
Key::OemBackslash => "OemBackslash",
Key::ImeProcessed => "ImeProcessed",
Key::System => "System",
Key::OemAttn => "OemAttn",
Key::OemFinish => "OemFinish",
Key::DbeHiragana => "DbeHiragana",
Key::DbeSbcsChar => "DbeSbcsChar",
Key::DbeDbcsChar => "DbeDbcsChar",
Key::OemBackTab => "OemBackTab",
Key::DbeNoRoman => "DbeNoRoman",
Key::CrSel => "CrSel",
Key::ExSel => "ExSel",
Key::EraseEof => "EraseEof",
Key::Play => "Play",
Key::DbeNoCodeInput => "DbeNoCodeInput",
Key::NoName => "NoName",
Key::DbeEnterDialogConversionMode => "DbeEnterDialogConversionMode",
Key::OemClear => "OemClear",
Key::DeadCharProcessed => "DeadCharProcessed",
Key::FnLeftArrow => "FnLeftArrow",
Key::FnRightArrow => "FnRightArrow",
Key::FnUpArrow => "FnUpArrow",
Key::FnDownArrow => "FnDownArrow",
Key::MediaHome => "MediaHome",
Key::MediaChannelList => "MediaChannelList",
Key::MediaChannelRaise => "MediaChannelRaise",
Key::MediaChannelLower => "MediaChannelLower",
Key::MediaRecord => "MediaRecord",
Key::MediaRed => "MediaRed",
Key::MediaGreen => "MediaGreen",
Key::MediaYellow => "MediaYellow",
Key::MediaBlue => "MediaBlue",
Key::MediaMenu => "MediaMenu",
Key::MediaMore => "MediaMore",
Key::MediaOption => "MediaOption",
Key::MediaInfo => "MediaInfo",
Key::MediaSearch => "MediaSearch",
Key::MediaSubtitle => "MediaSubtitle",
Key::MediaTvGuide => "MediaTvGuide",
Key::MediaPreviousChannel => "MediaPreviousChannel",
}
}
pub fn parse(s: &str) -> Result<Key, ParseKeyError> {
let s = s.trim();
if let Some((_, value)) = NAMES.iter().find(|(name, _)| name.eq_ignore_ascii_case(s)) {
return Ok(*value);
}
if let Ok(number) = s.parse::<i32>() {
if let Some(value) = Self::from_value(number) {
return Ok(value);
}
}
Err(ParseKeyError(s.to_string()))
}
}
impl FromStr for Key {
type Err = ParseKeyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn aliases_share_values() {
assert_eq!(Key::Enter, Key::Return);
assert_eq!(Key::Enter.value(), 6);
assert_eq!(Key::parse("enter"), Ok(Key::Return));
assert_eq!(Key::parse("ENTER"), Ok(Key::Enter));
}
#[test]
fn parse_and_display_round_trip() {
for (name, key) in NAMES {
assert_eq!(Key::parse(name), Ok(*key));
assert_eq!(Key::parse(key.name()), Ok(*key));
}
assert_eq!(Key::A.to_string(), "A");
assert_eq!(Key::None.to_string(), "None");
assert_eq!(Key::parse("44"), Ok(Key::A));
assert!(Key::parse("NotAKey").is_err());
}
}