use crate::config::key::parse_key;
use evdev::KeyCode as Key;
use serde::{Deserialize, Deserializer};
use std::error::{self, Error};
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct KeyPress {
pub key: Key,
pub modifiers: Vec<Modifier>,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Modifier {
Shift,
Control,
Alt,
Windows,
Key(Key),
}
impl<'de> Deserialize<'de> for KeyPress {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let key_press = String::deserialize(deserializer)?;
parse_key_press(&key_press).map_err(serde::de::Error::custom)
}
}
fn parse_key_press(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
let keys: Vec<&str> = input.split('-').collect();
if let Some((key, modifier_keys)) = keys.split_last() {
let mut modifiers = vec![];
for modifier_key in modifier_keys.iter() {
modifiers.push(parse_modifier(modifier_key)?);
}
Ok(KeyPress {
key: parse_key(key)?,
modifiers,
})
} else {
Err(format!("empty key_press: {input}").into())
}
}
fn parse_modifier(modifier: &str) -> Result<Modifier, Box<dyn Error>> {
match &modifier.to_uppercase()[..] {
"SHIFT" => Ok(Modifier::Shift),
"C" => Ok(Modifier::Control),
"CTRL" => Ok(Modifier::Control),
"CONTROL" => Ok(Modifier::Control),
"M" => Ok(Modifier::Alt),
"ALT" => Ok(Modifier::Alt),
"SUPER" => Ok(Modifier::Windows),
"WIN" => Ok(Modifier::Windows),
"WINDOWS" => Ok(Modifier::Windows),
key => parse_key(key).map(Modifier::Key),
}
}
#[test]
fn test_parse_key_press() {
assert_eq!(
parse_key_press("Shift-2").unwrap(),
KeyPress {
key: Key::KEY_2,
modifiers: vec![Modifier::Shift]
}
);
assert_eq!(
parse_key_press("Shift_L-2").unwrap(),
KeyPress {
key: Key::KEY_2,
modifiers: vec![Modifier::Key(Key::KEY_LEFTSHIFT)]
}
);
assert_eq!(
parse_key_press("Enter-2").unwrap(),
KeyPress {
key: Key::KEY_2,
modifiers: vec![Modifier::Key(Key::KEY_ENTER)]
}
);
}