use crate::config::key_press::parse_modifier_alias;
use crate::event_handler::{DISGUISED_EVENT_OFFSETTER, KEY_MATCH_ANY};
use evdev::KeyCode as Key;
use serde::{Deserialize, Deserializer};
use std::error::Error;
use std::str::FromStr;
pub fn deserialize_key<'de, D>(deserializer: D) -> Result<Key, D::Error>
where
D: Deserializer<'de>,
{
let key = String::deserialize(deserializer)?;
parse_key(&key).map_err(serde::de::Error::custom)
}
pub fn parse_key(input: &str) -> Result<Key, Box<dyn Error>> {
let name = input.to_uppercase();
if let Ok(key) = Key::from_str(&name) {
return Ok(key);
}
if let Ok(key) = Key::from_str(&format!("KEY_{name}")) {
return Ok(key);
}
let key = match &name[..] {
"SHIFT_R" => Key::KEY_RIGHTSHIFT,
"SHIFT_L" => Key::KEY_LEFTSHIFT,
"S_R" => Key::KEY_RIGHTSHIFT,
"S_L" => Key::KEY_LEFTSHIFT,
"CONTROL_R" => Key::KEY_RIGHTCTRL,
"CONTROL_L" => Key::KEY_LEFTCTRL,
"CTRL_R" => Key::KEY_RIGHTCTRL,
"CTRL_L" => Key::KEY_LEFTCTRL,
"C_R" => Key::KEY_RIGHTCTRL,
"C_L" => Key::KEY_LEFTCTRL,
"ALT_R" => Key::KEY_RIGHTALT,
"ALT_L" => Key::KEY_LEFTALT,
"A_R" => Key::KEY_RIGHTALT,
"A_L" => Key::KEY_LEFTALT,
"M_R" => Key::KEY_RIGHTALT,
"M_L" => Key::KEY_LEFTALT,
"SUPER_R" => Key::KEY_RIGHTMETA,
"SUPER_L" => Key::KEY_LEFTMETA,
"WIN_R" => Key::KEY_RIGHTMETA,
"WIN_L" => Key::KEY_LEFTMETA,
"W_R" => Key::KEY_RIGHTMETA,
"W_L" => Key::KEY_LEFTMETA,
"XRIGHTCURSOR" => Key(DISGUISED_EVENT_OFFSETTER),
"XLEFTCURSOR" => Key(DISGUISED_EVENT_OFFSETTER + 1),
"XDOWNCURSOR" => Key(DISGUISED_EVENT_OFFSETTER + 2),
"XUPCURSOR" => Key(DISGUISED_EVENT_OFFSETTER + 3),
"XREL_Z_AXIS_1" => Key(DISGUISED_EVENT_OFFSETTER + 4),
"XREL_Z_AXIS_2" => Key(DISGUISED_EVENT_OFFSETTER + 5),
"XREL_RX_AXIS_1" => Key(DISGUISED_EVENT_OFFSETTER + 6),
"XREL_RX_AXIS_2" => Key(DISGUISED_EVENT_OFFSETTER + 7),
"XREL_RY_AXIS_1" => Key(DISGUISED_EVENT_OFFSETTER + 8),
"XREL_RY_AXIS_2" => Key(DISGUISED_EVENT_OFFSETTER + 9),
"XREL_RZ_AXIS_1" => Key(DISGUISED_EVENT_OFFSETTER + 10),
"XREL_RZ_AXIS_2" => Key(DISGUISED_EVENT_OFFSETTER + 11),
"XRIGHTSCROLL" => Key(DISGUISED_EVENT_OFFSETTER + 12),
"XLEFTSCROLL" => Key(DISGUISED_EVENT_OFFSETTER + 13),
"XREL_DIAL_1" => Key(DISGUISED_EVENT_OFFSETTER + 14),
"XREL_DIAL_2" => Key(DISGUISED_EVENT_OFFSETTER + 15),
"XUPSCROLL" => Key(DISGUISED_EVENT_OFFSETTER + 16),
"XDOWNSCROLL" => Key(DISGUISED_EVENT_OFFSETTER + 17),
"XREL_MISC_1" => Key(DISGUISED_EVENT_OFFSETTER + 18),
"XREL_MISC_2" => Key(DISGUISED_EVENT_OFFSETTER + 19),
"XREL_RESERVED_1" => Key(DISGUISED_EVENT_OFFSETTER + 20),
"XREL_RESERVED_2" => Key(DISGUISED_EVENT_OFFSETTER + 21),
"XHIRES_UPSCROLL" => Key(DISGUISED_EVENT_OFFSETTER + 22),
"XHIRES_DOWNSCROLL" => Key(DISGUISED_EVENT_OFFSETTER + 23),
"XHIRES_RIGHTSCROLL" => Key(DISGUISED_EVENT_OFFSETTER + 24),
"XHIRES_LEFTSCROLL" => Key(DISGUISED_EVENT_OFFSETTER + 25),
"ANY" => KEY_MATCH_ANY,
_ => Key::KEY_RESERVED,
};
if key != Key::KEY_RESERVED {
return Ok(key);
}
if parse_modifier_alias(input).is_some() {
return Err(format!("Modifiers must have left/right specified when used as key: '{input}'").into());
}
Err(format!("unknown key '{input}'").into())
}
#[test]
fn test_parse_key() {
assert_eq!(parse_key("Enter").unwrap(), Key::KEY_ENTER);
assert_eq!(parse_key("key_enter").unwrap(), Key::KEY_ENTER);
assert_eq!(parse_key("KEY_ENTER").unwrap(), Key::KEY_ENTER);
assert_eq!(parse_key("S").unwrap(), Key::KEY_S);
assert_eq!(
parse_key("Shift").unwrap_err().to_string(),
"Modifiers must have left/right specified when used as key: 'Shift'"
);
}