From b6048e2a5b4fc12b4152ba36a1c51202b520cab9 Mon Sep 17 00:00:00 2001 From: Nolan Woods Date: Fri, 31 May 2024 00:59:00 -0700 Subject: [PATCH] Add modifiers config option --- README.md | 17 +++++++++++++ src/main.rs | 2 +- src/mapping.rs | 29 +++++++++++++++++++++ src/remapper.rs | 67 +++++++++++++++++++++---------------------------- 4 files changed, 76 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 005191c..50c86ea 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,23 @@ input = ["KEY_F8"] output = ["KEY_MUTE"] ``` +If you want to override the default modifiers (KEY_LEFTALT, KEY_LEFTCTRL, etc.) +you can list all the modifier keys via the `modifiers = []` config option. + +```toml +modifiers = [ + "KEY_FN", + "KEY_LEFTALT", + "KEY_RIGHTALT", + "KEY_LEFTMETA", + "KEY_RIGHTMETA", + "KEY_LEFTCTRL", + "KEY_RIGHTCTRL", + "KEY_LEFTSHIFT", + "KEY_RIGHTSHIFT", +] +``` + * How do I list available input devices? `sudo evremap list-devices` diff --git a/src/main.rs b/src/main.rs index f2e8246..1c0ba1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,7 +85,7 @@ fn main() -> Result<()> { mapping_config.phys.as_deref(), )?; - let mut mapper = InputMapper::create_mapper(device_info.path, mapping_config.mappings)?; + let mut mapper = InputMapper::create_mapper(device_info.path, mapping_config.mappings, mapping_config.modifiers)?; mapper.run_mapper() } } diff --git a/src/mapping.rs b/src/mapping.rs index 6ffc274..38a1d9c 100644 --- a/src/mapping.rs +++ b/src/mapping.rs @@ -10,6 +10,7 @@ pub struct MappingConfig { pub device_name: String, pub phys: Option, pub mappings: Vec, + pub modifiers: HashSet } impl MappingConfig { @@ -26,10 +27,35 @@ impl MappingConfig { for remap in config_file.remap { mappings.push(remap.into()); } + let modifiers; + if config_file.modifiers.is_empty() { + modifiers = HashSet::from_iter([ + KeyCode::KEY_FN, + KeyCode::KEY_LEFTALT, + KeyCode::KEY_RIGHTALT, + KeyCode::KEY_LEFTMETA, + KeyCode::KEY_RIGHTMETA, + KeyCode::KEY_LEFTCTRL, + KeyCode::KEY_RIGHTCTRL, + KeyCode::KEY_LEFTSHIFT, + KeyCode::KEY_RIGHTSHIFT, + ]); + } else { + modifiers = config_file.modifiers.into_iter().map(|name| + match EventCode::from_str(&EventType::EV_KEY, &name) { + Some(code) => match code { + EventCode::EV_KEY(code) => code, + _ => panic!("{}", ConfigError::ImpossibleParseKey), + }, + None => panic!("{}", ConfigError::InvalidKey(name.to_string())), + } + ).collect() + } Ok(Self { device_name: config_file.device_name, phys: config_file.phys, mappings, + modifiers, }) } } @@ -123,4 +149,7 @@ struct ConfigFile { #[serde(default)] remap: Vec, + + #[serde(default)] + modifiers: Vec, } diff --git a/src/remapper.rs b/src/remapper.rs index 5803ae4..8f5fc62 100644 --- a/src/remapper.rs +++ b/src/remapper.rs @@ -61,6 +61,7 @@ pub struct InputMapper { tapping: Option, output_keys: HashSet, + modifiers: HashSet, } fn enable_key_code(input: &mut Device, key: KeyCode) -> Result<()> { @@ -71,7 +72,7 @@ fn enable_key_code(input: &mut Device, key: KeyCode) -> Result<()> { } impl InputMapper { - pub fn create_mapper>(path: P, mappings: Vec) -> Result { + pub fn create_mapper>(path: P, mappings: Vec, modifiers: HashSet) -> Result { let path = path.as_ref(); let f = std::fs::File::open(path).context(format!("opening {}", path.display()))?; let mut input = Device::new_from_file(f) @@ -112,6 +113,7 @@ impl InputMapper { output_keys: HashSet::new(), tapping: None, mappings, + modifiers, }) } @@ -162,7 +164,7 @@ impl InputMapper { if input.is_subset(&keys_minus_remapped) { for i in input { keys.remove(i); - if !is_modifier(i) { + if !self.is_modifier(i) { keys_minus_remapped.remove(i); } } @@ -170,7 +172,7 @@ impl InputMapper { keys.insert(o.clone()); // Outputs that apply are not visible as // inputs for later remap rules - if !is_modifier(o) { + if !self.is_modifier(o) { keys_minus_remapped.remove(o); } } @@ -207,11 +209,11 @@ impl InputMapper { .collect(); if !to_release.is_empty() { - to_release.sort_by(modifiers_last); + to_release.sort_by(|a,b| self.modifiers_last(a,b)); self.emit_keys(&to_release, time, KeyEventType::Release)?; } if !to_press.is_empty() { - to_press.sort_by(modifiers_first); + to_press.sort_by(|a,b| self.modifiers_first(a,b)); self.emit_keys(&to_press, time, KeyEventType::Press)?; } Ok(()) @@ -392,45 +394,34 @@ impl InputMapper { ))?; Ok(()) } -} -fn make_event(key: KeyCode, time: &TimeVal, event_type: KeyEventType) -> InputEvent { - InputEvent::new(time, &EventCode::EV_KEY(key), event_type.value()) -} - -fn is_modifier(key: &KeyCode) -> bool { - match key { - KeyCode::KEY_FN - | KeyCode::KEY_LEFTALT - | KeyCode::KEY_RIGHTALT - | KeyCode::KEY_LEFTMETA - | KeyCode::KEY_RIGHTMETA - | KeyCode::KEY_LEFTCTRL - | KeyCode::KEY_RIGHTCTRL - | KeyCode::KEY_LEFTSHIFT - | KeyCode::KEY_RIGHTSHIFT => true, - _ => false, + fn is_modifier(&self, key: &KeyCode) -> bool { + self.modifiers.contains(key) } -} -/// Orders modifier keys ahead of non-modifier keys. -/// Unfortunately the underlying type doesn't allow direct -/// comparison, but that's ok for our purposes. -fn modifiers_first(a: &KeyCode, b: &KeyCode) -> Ordering { - if is_modifier(a) { - if is_modifier(b) { - Ordering::Equal + /// Orders modifier keys ahead of non-modifier keys. + /// Unfortunately the underlying type doesn't allow direct + /// comparison, but that's ok for our purposes. + fn modifiers_first(&self, a: &KeyCode, b: &KeyCode) -> Ordering { + if self.is_modifier(a) { + if self.is_modifier(b) { + Ordering::Equal + } else { + Ordering::Less + } + } else if self.is_modifier(b) { + Ordering::Greater } else { - Ordering::Less + // Neither are modifiers + Ordering::Equal } - } else if is_modifier(b) { - Ordering::Greater - } else { - // Neither are modifiers - Ordering::Equal + } + + fn modifiers_last(&self, a: &KeyCode, b: &KeyCode) -> Ordering { + self.modifiers_first(a, b).reverse() } } -fn modifiers_last(a: &KeyCode, b: &KeyCode) -> Ordering { - modifiers_first(a, b).reverse() +fn make_event(key: KeyCode, time: &TimeVal, event_type: KeyEventType) -> InputEvent { + InputEvent::new(time, &EventCode::EV_KEY(key), event_type.value()) }