Keep extra modifiers on KeyPress

This commit is contained in:
Takashi Kokubun 2022-08-14 16:08:24 -07:00
parent 53f37c1353
commit be7d11e244
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD
2 changed files with 81 additions and 55 deletions

View File

@ -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<Key>),
#[serde(skip)]
ReleaseModifier(Vec<Key>),
}
fn deserialize_remap<'de, D>(deserializer: D) -> Result<Remap, D::Error>

View File

@ -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<dyn Error>> {
// 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<Key> = 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> = 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<Modifier>, 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<Modifier>, 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<Modifier>) -> (Vec<Key>, Vec<Key>) {
let extra_modifiers: Vec<Key> = self
.modifiers
.iter()
.filter(|modifier| !contains_modifier(modifiers, modifier))
.map(|modifier| modifier.clone())
.collect();
let missing_modifiers: Vec<Key> = 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<Action>, extra_modifiers: &Vec<Key>) -> Vec<Action> {
let mut result: Vec<Action> = 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<Modifier>, 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