use crate::config::key::parse_key;
use evdev::KeyCode as Key;
use serde::{Deserialize, Deserializer};
use std::error::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 Modifier {
pub fn is_in(&self, modifiers: &Vec<Key>) -> bool {
match self {
Modifier::Shift => modifiers.contains(&Key::KEY_LEFTSHIFT) || modifiers.contains(&Key::KEY_RIGHTSHIFT),
Modifier::Control => modifiers.contains(&Key::KEY_LEFTCTRL) || modifiers.contains(&Key::KEY_RIGHTCTRL),
Modifier::Alt => modifiers.contains(&Key::KEY_LEFTALT) || modifiers.contains(&Key::KEY_RIGHTALT),
Modifier::Windows => modifiers.contains(&Key::KEY_LEFTMETA) || modifiers.contains(&Key::KEY_RIGHTMETA),
Modifier::Key(key) => modifiers.contains(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>> {
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 parse_modifier_alias(modifier) {
Some(modifier) => Ok(modifier),
None => {
parse_key(modifier).map(Modifier::Key)
}
}
}
pub fn parse_modifier_alias(modifier: &str) -> Option<Modifier> {
match &modifier.to_uppercase()[..] {
"S" => Some(Modifier::Shift),
"SHIFT" => Some(Modifier::Shift),
"C" => Some(Modifier::Control),
"CTRL" => Some(Modifier::Control),
"CONTROL" => Some(Modifier::Control),
"A" => Some(Modifier::Alt),
"M" => Some(Modifier::Alt),
"ALT" => Some(Modifier::Alt),
"SUPER" => Some(Modifier::Windows),
"W" => Some(Modifier::Windows),
"WIN" => Some(Modifier::Windows),
"WINDOWS" => Some(Modifier::Windows),
_ => None,
}
}
#[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)]
}
);
}