diff --git a/src/config/action.rs b/src/config/action.rs index cf8044c..a07c207 100644 --- a/src/config/action.rs +++ b/src/config/action.rs @@ -2,6 +2,7 @@ use crate::config::key_press::KeyPress; use std::collections::HashMap; use crate::config::remap::Remap; +use evdev::Key; use serde::de; use serde::{Deserialize, Deserializer}; use std::fmt::Debug; @@ -14,6 +15,7 @@ use super::remap::RemapActions; #[derive(Clone, Debug, Deserialize)] #[serde(untagged)] pub enum Action { + // Config interface KeyPress(KeyPress), #[serde(deserialize_with = "deserialize_remap")] Remap(Remap), @@ -27,6 +29,12 @@ pub enum Action { WithMark(KeyPress), #[serde(deserialize_with = "deserialize_escape_next_key")] EscapeNextKey(bool), + + // Internals + #[serde(skip)] + PressModifier(Vec), + #[serde(skip)] + ReleaseModifier(Vec), } fn deserialize_remap<'de, D>(deserializer: D) -> Result diff --git a/src/event_handler.rs b/src/event_handler.rs index 867ba7a..ff2ed82 100644 --- a/src/event_handler.rs +++ b/src/event_handler.rs @@ -248,10 +248,11 @@ impl EventHandler { if let Some(entries) = override_remap.get(key) { for exact_match in [true, false] { for entry in entries { - if !self.match_modifiers(&entry.modifiers, exact_match) { + let (extra_modifiers, missing_modifiers) = self.diff_modifiers(&entry.modifiers); + if (exact_match && extra_modifiers.len() > 0) || missing_modifiers.len() > 0 { continue; } - return Ok(Some(entry.actions.to_vec())); + return Ok(Some(with_extra_modifiers(&entry.actions, &extra_modifiers))); } } } @@ -259,7 +260,8 @@ impl EventHandler { if let Some(entries) = config.keymap_table.get(key) { for exact_match in [true, false] { for entry in entries { - if !self.match_modifiers(&entry.modifiers, exact_match) { + let (extra_modifiers, missing_modifiers) = self.diff_modifiers(&entry.modifiers); + if (exact_match && extra_modifiers.len() > 0) || missing_modifiers.len() > 0 { continue; } if let Some(application_matcher) = &entry.application { @@ -272,7 +274,7 @@ impl EventHandler { continue; } } - return Ok(Some(entry.actions.clone())); + return Ok(Some(with_extra_modifiers(&entry.actions, &extra_modifiers))); } } } @@ -310,6 +312,16 @@ impl EventHandler { Action::SetMark(set) => self.mark_set = *set, Action::WithMark(key_press) => self.send_key_press(&self.with_mark(key_press))?, Action::EscapeNextKey(escape_next_key) => self.escape_next_key = *escape_next_key, + Action::PressModifier(keys) => { + for key in keys { + self.modifiers.insert(*key); + } + } + Action::ReleaseModifier(keys) => { + for key in keys { + self.modifiers.remove(key); + } + } } Ok(()) } @@ -317,32 +329,9 @@ impl EventHandler { fn send_key_press(&mut self, key_press: &KeyPress) -> Result<(), Box> { // Build extra or missing modifiers. Note that only MODIFIER_KEYS are handled // because logical modifiers shouldn't make an impact outside xremap. - let extra_modifiers: Vec = self - .modifiers - .iter() - .filter(|modifier| { - !self.contains_modifier(&key_press.modifiers, modifier) && MODIFIER_KEYS.contains(&modifier.code()) - }) - .map(|modifier| modifier.clone()) - .collect(); - let missing_modifiers: Vec = key_press - .modifiers - .iter() - .filter_map(|modifier| { - if self.match_modifier(modifier) { - None - } else { - match modifier { - Modifier::Shift => Some(Key::KEY_LEFTSHIFT), - Modifier::Control => Some(Key::KEY_LEFTCTRL), - Modifier::Alt => Some(Key::KEY_LEFTALT), - Modifier::Windows => Some(Key::KEY_LEFTMETA), - Modifier::Key(key) if MODIFIER_KEYS.contains(&key.code()) => Some(key.clone()), - _ => None, - } - } - }) - .collect(); + let (mut extra_modifiers, mut missing_modifiers) = self.diff_modifiers(&key_press.modifiers); + extra_modifiers.retain(|key| MODIFIER_KEYS.contains(&key.code())); + missing_modifiers.retain(|key| MODIFIER_KEYS.contains(&key.code())); // Emulate the modifiers of KeyPress self.send_keys(&extra_modifiers, RELEASE)?; @@ -395,31 +384,31 @@ impl EventHandler { } } - fn contains_modifier(&self, modifiers: &Vec, key: &Key) -> bool { - for modifier in modifiers { - if match modifier { - Modifier::Shift => key == &Key::KEY_LEFTSHIFT || key == &Key::KEY_RIGHTSHIFT, - Modifier::Control => key == &Key::KEY_LEFTCTRL || key == &Key::KEY_RIGHTCTRL, - Modifier::Alt => key == &Key::KEY_LEFTALT || key == &Key::KEY_RIGHTALT, - Modifier::Windows => key == &Key::KEY_LEFTMETA || key == &Key::KEY_RIGHTMETA, - Modifier::Key(modifier_key) => key == modifier_key, - } { - return true; - } - } - false - } - - fn match_modifiers(&self, modifiers: &Vec, exact_match: bool) -> bool { - if exact_match && self.modifiers.len() > modifiers.len() { - return false; - } - for modifier in modifiers { - if !self.match_modifier(modifier) { - return false; - } - } - return true; + // Return (extra_modifiers, missing_modifiers) + fn diff_modifiers(&self, modifiers: &Vec) -> (Vec, Vec) { + let extra_modifiers: Vec = self + .modifiers + .iter() + .filter(|modifier| !contains_modifier(modifiers, modifier)) + .map(|modifier| modifier.clone()) + .collect(); + let missing_modifiers: Vec = modifiers + .iter() + .filter_map(|modifier| { + if self.match_modifier(modifier) { + None + } else { + match modifier { + Modifier::Shift => Some(Key::KEY_LEFTSHIFT), + Modifier::Control => Some(Key::KEY_LEFTCTRL), + Modifier::Alt => Some(Key::KEY_LEFTALT), + Modifier::Windows => Some(Key::KEY_LEFTMETA), + Modifier::Key(key) => Some(*key), + } + } + }) + .collect(); + return (extra_modifiers, missing_modifiers); } fn match_modifier(&self, modifier: &Modifier) -> bool { @@ -467,6 +456,35 @@ impl EventHandler { } } +fn with_extra_modifiers(actions: &Vec, extra_modifiers: &Vec) -> Vec { + let mut result: Vec = vec![]; + if extra_modifiers.len() > 0 { + // Virtually release extra modifiers so that they won't be physically released on KeyPress + result.push(Action::ReleaseModifier(extra_modifiers.clone())); + } + result.extend(actions.clone()); + if extra_modifiers.len() > 0 { + // Resurrect the modifier status + result.push(Action::PressModifier(extra_modifiers.clone())); + } + return result; +} + +fn contains_modifier(modifiers: &Vec, key: &Key) -> bool { + for modifier in modifiers { + if match modifier { + Modifier::Shift => key == &Key::KEY_LEFTSHIFT || key == &Key::KEY_RIGHTSHIFT, + Modifier::Control => key == &Key::KEY_LEFTCTRL || key == &Key::KEY_RIGHTCTRL, + Modifier::Alt => key == &Key::KEY_LEFTALT || key == &Key::KEY_RIGHTALT, + Modifier::Windows => key == &Key::KEY_LEFTMETA || key == &Key::KEY_RIGHTMETA, + Modifier::Key(modifier_key) => key == modifier_key, + } { + return true; + } + } + false +} + lazy_static! { static ref MODIFIER_KEYS: [u16; 8] = [ // Shift