use crate::*; pub struct KeyMatcher { valid: bool, key: Option, mods: KeyModifiers, } impl KeyMatcher { pub fn new (token: impl AsRef) -> Self { let token = token.as_ref(); if token.len() < 2 { Self { valid: false, key: None, mods: KeyModifiers::NONE } } else if token.chars().next() != Some('@') { Self { valid: false, key: None, mods: KeyModifiers::NONE } } else { Self { valid: true, key: None, mods: KeyModifiers::NONE }.next(&token[1..]) } } pub fn build (self) -> Option { if self.valid && self.key.is_some() { Some(Event::Key(KeyEvent::new(self.key.unwrap(), self.mods))) } else { None } } fn next (mut self, token: &str) -> Self { let mut tokens = token.split('-').peekable(); while let Some(token) = tokens.next() { if tokens.peek().is_some() { match token { "ctrl" | "Ctrl" | "c" | "C" => self.mods |= KeyModifiers::CONTROL, "alt" | "Alt" | "m" | "M" => self.mods |= KeyModifiers::ALT, "shift" | "Shift" | "s" | "S" => { self.mods |= KeyModifiers::SHIFT; // + TODO normalize character case, BackTab, etc. }, _ => panic!("unknown modifier {token}"), } } else { self.key = if token.len() == 1 { Some(KeyCode::Char(token.chars().next().unwrap())) } else { Some(Self::named_key(token).unwrap_or_else(||panic!("unknown character {token}"))) } } } self } fn named_key (token: &str) -> Option { use KeyCode::*; Some(match token { "up" => Up, "down" => Down, "left" => Left, "right" => Right, "esc" | "escape" => Esc, "enter" | "return" => Enter, "delete" | "del" => Delete, "tab" => Tab, "space" => Char(' '), "comma" => Char(','), "period" => Char('.'), "plus" => Char('+'), "minus" | "dash" => Char('-'), "equal" | "equals" => Char('='), "underscore" => Char('_'), "backtick" => Char('`'), "lt" => Char('<'), "gt" => Char('>'), "openbracket" => Char('['), "closebracket" => Char(']'), "pgup" | "pageup" => PageUp, "pgdn" | "pagedown" => PageDown, "f1" => F(1), "f2" => F(2), "f3" => F(3), "f4" => F(4), "f5" => F(5), "f6" => F(6), "f7" => F(7), "f8" => F(8), "f9" => F(9), "f10" => F(10), "f11" => F(11), "f12" => F(12), _ => return None, }) } }