From 04e94ea9f4ad6084832d0c2f1b3ea1eee95d8f3c Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Sat, 13 Aug 2022 21:04:18 -0700 Subject: [PATCH] Make modifier lookup more efficient and flexible Close #102 --- src/config/application.rs | 4 +- src/config/key.rs | 4 + src/config/key_press.rs | 83 +++------- src/config/keymap.rs | 104 ++++++------ src/config/mod.rs | 16 +- src/event_handler.rs | 326 ++++++++++++++++---------------------- 6 files changed, 236 insertions(+), 301 deletions(-) diff --git a/src/config/application.rs b/src/config/application.rs index caaada4..aa3bf9b 100644 --- a/src/config/application.rs +++ b/src/config/application.rs @@ -5,7 +5,7 @@ use regex::Regex; use serde::{Deserialize, Deserializer}; // TODO: Use trait to allow only either `only` or `not` -#[derive(Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize)] #[serde(deny_unknown_fields)] pub struct Application { #[serde(default, deserialize_with = "deserialize_matchers")] @@ -14,7 +14,7 @@ pub struct Application { pub not: Option>, } -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum ApplicationMatcher { // class.name Literal(String), diff --git a/src/config/key.rs b/src/config/key.rs index 1cc35e2..e07b5ce 100644 --- a/src/config/key.rs +++ b/src/config/key.rs @@ -35,9 +35,13 @@ pub fn parse_key(input: &str) -> Result> { "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 "ALT_R" => Key::KEY_RIGHTALT, "ALT_L" => Key::KEY_LEFTALT, + "M_R" => Key::KEY_RIGHTALT, + "M_L" => Key::KEY_LEFTALT, // Windows "SUPER_R" => Key::KEY_RIGHTMETA, "SUPER_L" => Key::KEY_LEFTMETA, diff --git a/src/config/key_press.rs b/src/config/key_press.rs index 9ff08a3..478ee5d 100644 --- a/src/config/key_press.rs +++ b/src/config/key_press.rs @@ -1,30 +1,23 @@ use crate::config::key::parse_key; use evdev::Key; use serde::{Deserialize, Deserializer}; -use std::error; +use std::error::{self, Error}; #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct KeyPress { pub key: Key, - pub shift: ModifierState, - pub control: ModifierState, - pub alt: ModifierState, - pub windows: ModifierState, + pub modifiers: Vec, } #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum ModifierState { - Left, - Right, - Either, - None, -} - pub enum Modifier { + // Matches left, right, or both Shift, Control, Alt, Windows, + // Matches exactly this key + Key(Key), } impl<'de> Deserialize<'de> for KeyPress { @@ -39,69 +32,41 @@ impl<'de> Deserialize<'de> for KeyPress { fn parse_key_press(input: &str) -> Result> { let keys: Vec<&str> = input.split('-').collect(); - if let Some((key, modifiers)) = keys.split_last() { - let mut shift = ModifierState::None; - let mut control = ModifierState::None; - let mut alt = ModifierState::None; - let mut windows = ModifierState::None; - - for modifier in modifiers.iter() { - match parse_modifier(modifier) { - Some((Modifier::Shift, state)) => shift = state, - Some((Modifier::Control, state)) => control = state, - Some((Modifier::Alt, state)) => alt = state, - Some((Modifier::Windows, state)) => windows = state, - None => return Err(format!("unknown modifier: {}", modifier).into()), + if let Some((key, modifier_keys)) = keys.split_last() { + let mut modifiers = vec![]; + for modifier_key in modifier_keys.iter() { + match parse_modifier(modifier_key) { + Ok(modifier) => modifiers.push(modifier), + Err(e) => return Err(e), } } - // TODO: invalidate modifier keys in `key`? Ok(KeyPress { key: parse_key(key)?, - shift, - control, - alt, - windows, + modifiers, }) } else { Err(format!("empty key_press: {}", input).into()) } } -fn parse_modifier(modifier: &str) -> Option<(Modifier, ModifierState)> { +fn parse_modifier(modifier: &str) -> Result> { // Everything is case-insensitive - let mut modifier = &modifier.to_uppercase()[..]; - let mut modifier_state = ModifierState::Either; - if modifier.ends_with("_L") { - modifier = remove_suffix(modifier); - modifier_state = ModifierState::Left; - } else if modifier.ends_with("_R") { - modifier = remove_suffix(modifier); - modifier_state = ModifierState::Right; - } - - match modifier { + match &modifier.to_uppercase()[..] { // Shift - "SHIFT" => Some((Modifier::Shift, modifier_state)), + "SHIFT" => Ok(Modifier::Shift), // Control - "C" => Some((Modifier::Control, modifier_state)), - "CTRL" => Some((Modifier::Control, modifier_state)), - "CONTROL" => Some((Modifier::Control, modifier_state)), + "C" => Ok(Modifier::Control), + "CTRL" => Ok(Modifier::Control), + "CONTROL" => Ok(Modifier::Control), // Alt - "M" => Some((Modifier::Alt, modifier_state)), - "ALT" => Some((Modifier::Alt, modifier_state)), + "M" => Ok(Modifier::Alt), + "ALT" => Ok(Modifier::Alt), // Windows - "SUPER" => Some((Modifier::Windows, modifier_state)), - "WIN" => Some((Modifier::Windows, modifier_state)), - "WINDOWS" => Some((Modifier::Windows, modifier_state)), + "SUPER" => Ok(Modifier::Windows), + "WIN" => Ok(Modifier::Windows), + "WINDOWS" => Ok(Modifier::Windows), // else - _ => None, + key => parse_key(key).map(|key| Modifier::Key(key)), } } - -fn remove_suffix(string: &str) -> &str { - let mut chars = string.chars(); - chars.next_back(); - chars.next_back(); - chars.as_str() -} diff --git a/src/config/keymap.rs b/src/config/keymap.rs index 0c3cc74..c786730 100644 --- a/src/config/keymap.rs +++ b/src/config/keymap.rs @@ -1,10 +1,14 @@ use crate::config::action::{Action, Actions}; use crate::config::application::deserialize_string_or_vec; use crate::config::application::Application; -use crate::config::key_press::{KeyPress, Modifier, ModifierState}; +use crate::config::key_press::KeyPress; +use evdev::Key; use serde::{Deserialize, Deserializer}; use std::collections::HashMap; +use super::key_press::Modifier; + +// Config interface #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub struct Keymap { @@ -24,59 +28,65 @@ where let remap = HashMap::::deserialize(deserializer)?; Ok(remap .into_iter() - .flat_map(|(key_press, actions)| { - expand_modifiers(key_press) - .into_iter() - .map(|k| (k, actions.clone().into_vec())) - .collect::)>>() - }) + .map(|(key_press, actions)| (key_press, actions.into_vec())) .collect()) } -// Expand ModifierState::Either to Left and Right. Not leaving Either to save some space and computation. -// Note that we currently don't have `Both`. Does anybody need it? -pub fn expand_modifiers(key_press: KeyPress) -> Vec { - if key_press.shift == ModifierState::Either { - expand_modifier(key_press, &Modifier::Shift) - } else if key_press.control == ModifierState::Either { - expand_modifier(key_press, &Modifier::Control) - } else if key_press.alt == ModifierState::Either { - expand_modifier(key_press, &Modifier::Alt) - } else if key_press.windows == ModifierState::Either { - expand_modifier(key_press, &Modifier::Windows) - } else { - vec![key_press] - } +// Internals for efficient keymap lookup +#[derive(Clone, Debug)] +pub struct KeymapEntry { + pub actions: Vec, + pub modifiers: Vec, + pub application: Option, + pub mode: Option>, } -fn expand_modifier(key_press: KeyPress, modifier: &Modifier) -> Vec { - vec![ - change_modifier(key_press.clone(), modifier, ModifierState::Left), - change_modifier(key_press, modifier, ModifierState::Right), - ] - .into_iter() - .flat_map(expand_modifiers) - .collect() +// Convert an array of keymaps to a single hashmap whose key is a triggering key. +// +// For each key, Vec is scanned once, matching the exact modifiers, +// and then it's scanned again, allowing extra modifiers. +// +// First matching KeymapEntry wins at each iteration. +pub fn build_keymap_table(keymaps: &Vec) -> HashMap> { + let mut table: HashMap> = HashMap::new(); + for keymap in keymaps { + for (key_press, actions) in keymap.remap.iter() { + let mut entries: Vec = match table.get(&key_press.key) { + Some(entries) => entries.to_vec(), + None => vec![], + }; + entries.push(KeymapEntry { + actions: actions.to_vec(), + modifiers: key_press.modifiers.clone(), + application: keymap.application.clone(), + mode: keymap.mode.clone(), + }); + table.insert(key_press.key, entries); + } + } + return table; } -fn change_modifier(key_press: KeyPress, modifier: &Modifier, state: ModifierState) -> KeyPress { - let mut shift = key_press.shift.clone(); - let mut control = key_press.control.clone(); - let mut alt = key_press.alt.clone(); - let mut windows = key_press.windows.clone(); - - match modifier { - Modifier::Shift => shift = state, - Modifier::Control => control = state, - Modifier::Alt => alt = state, - Modifier::Windows => windows = state, - } +// Subset of KeymapEntry for override_remap +#[derive(Clone)] +pub struct OverrideEntry { + pub actions: Vec, + pub modifiers: Vec, +} - KeyPress { - key: key_press.key, - shift, - control, - alt, - windows, +// This is executed on runtime unlike build_keymap_table, but hopefully not called so often. +pub fn build_override_table(remap: &HashMap>) -> HashMap> { + let mut table: HashMap> = HashMap::new(); + for (key_press, actions) in remap.iter() { + let mut entries: Vec = match table.get(&key_press.key) { + Some(entries) => entries.to_vec(), + None => vec![], + }; + entries.push(OverrideEntry { + actions: actions.to_vec(), + modifiers: key_press.modifiers.clone(), + }); + table.insert(key_press.key, entries); } + return table; } diff --git a/src/config/mod.rs b/src/config/mod.rs index fa917ba..6d65878 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -12,29 +12,43 @@ mod tests; extern crate serde_yaml; +use evdev::Key; use keymap::Keymap; use modmap::Modmap; use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify}; use serde::Deserialize; -use std::{error, fs, path::Path, time::SystemTime}; +use std::{collections::HashMap, error, fs, path::Path, time::SystemTime}; + +use self::keymap::{build_keymap_table, KeymapEntry}; #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub struct Config { + // Config interface #[serde(default = "Vec::new")] pub modmap: Vec, #[serde(default = "Vec::new")] pub keymap: Vec, #[serde(default = "default_mode")] pub default_mode: String, + + // Internals #[serde(skip)] pub modify_time: Option, + #[serde(skip)] + pub keymap_table: HashMap>, } pub fn load_config(filename: &Path) -> Result> { let yaml = fs::read_to_string(&filename)?; let mut config: Config = serde_yaml::from_str(&yaml)?; + + // Timestamp for --watch=config config.modify_time = filename.metadata()?.modified().ok(); + + // Convert keymap for efficient keymap lookup + config.keymap_table = build_keymap_table(&config.keymap); + Ok(config) } diff --git a/src/event_handler.rs b/src/event_handler.rs index 8b06dec..8ac10f8 100644 --- a/src/event_handler.rs +++ b/src/event_handler.rs @@ -2,8 +2,8 @@ use crate::client::{build_client, WMClient}; use crate::config::action::Action; use crate::config::application::Application; use crate::config::key_action::{KeyAction, MultiPurposeKey, PressReleaseKey}; -use crate::config::key_press::{KeyPress, Modifier, ModifierState}; -use crate::config::keymap::expand_modifiers; +use crate::config::key_press::{KeyPress, Modifier}; +use crate::config::keymap::{build_override_table, OverrideEntry}; use crate::config::remap::Remap; use crate::Config; use evdev::uinput::VirtualDevice; @@ -14,18 +14,16 @@ use nix::sys::signal; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet}; use nix::sys::time::TimeSpec; use nix::sys::timerfd::{Expiration, TimerFd, TimerSetTimeFlags}; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::error::Error; use std::process::{Command, Stdio}; use std::time::Instant; pub struct EventHandler { + // Device to emit events device: VirtualDevice, - // Recognize modifier key combinations - shift: PressState, - control: PressState, - alt: PressState, - windows: PressState, + // Currently pressed modifier keys + modifiers: HashSet, // Make sure the original event is released even if remapping changes while holding the key pressed_keys: HashMap, // Check the currently active application @@ -34,7 +32,7 @@ pub struct EventHandler { // State machine for multi-purpose keys multi_purpose_keys: HashMap, // Current nested remaps - override_remap: Option>>, + override_remap: Option>>, // Key triggered on a timeout of nested remaps override_timeout_key: Option, // Trigger a timeout of nested remaps through select(2) @@ -53,10 +51,7 @@ impl EventHandler { pub fn new(device: VirtualDevice, timer: TimerFd, mode: &str) -> EventHandler { EventHandler { device, - shift: PressState::new(), - control: PressState::new(), - alt: PressState::new(), - windows: PressState::new(), + modifiers: HashSet::new(), pressed_keys: HashMap::new(), application_client: build_client(), application_cache: None, @@ -91,7 +86,7 @@ impl EventHandler { // Apply keymap for (key, value) in key_values.into_iter() { if MODIFIER_KEYS.contains(&key.code()) { - self.update_modifier(key.code(), value); + self.update_modifier(key, value); } else if is_pressed(value) { if self.escape_next_key { self.escape_next_key = false @@ -127,6 +122,13 @@ impl EventHandler { Ok(()) } + fn send_keys(&mut self, keys: &Vec, value: i32) -> std::io::Result<()> { + for key in keys { + self.send_key(key, value)?; + } + Ok(()) + } + fn send_key(&mut self, key: &Key, value: i32) -> std::io::Result<()> { let event = InputEvent::new(EventType::KEY, key.code(), value); self.send_event(event) @@ -239,34 +241,36 @@ impl EventHandler { } fn find_keymap(&mut self, config: &Config, key: &Key) -> Result>, Box> { - let key_press = KeyPress { - key: *key, - shift: self.shift.to_modifier_state(), - control: self.control.to_modifier_state(), - alt: self.alt.to_modifier_state(), - windows: self.windows.to_modifier_state(), - }; if let Some(override_remap) = &self.override_remap { - if let Some(actions) = override_remap.clone().get(&key_press) { - self.remove_override()?; - return Ok(Some(actions.to_vec())); - } else { - self.timeout_override()?; + 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) { + continue; + } + return Ok(Some(entry.actions.to_vec())); + } + } } } - for keymap in &config.keymap { - if let Some(actions) = keymap.remap.get(&key_press) { - if let Some(application_matcher) = &keymap.application { - if !self.match_application(application_matcher) { + 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) { continue; } - } - if let Some(modes) = &keymap.mode { - if !modes.contains(&self.mode) { - continue; + if let Some(application_matcher) = &entry.application { + if !self.match_application(application_matcher) { + continue; + } + } + if let Some(modes) = &entry.mode { + if !modes.contains(&self.mode) { + continue; + } } + return Ok(Some(entry.actions.clone())); } - return Ok(Some(actions.to_vec())); } } Ok(None) @@ -287,13 +291,7 @@ impl EventHandler { timeout, timeout_key, }) => { - let mut override_remap: HashMap> = HashMap::new(); - for (key_press, actions) in remap.iter() { - for key_press in expand_modifiers(key_press.clone()) { - override_remap.insert(key_press, actions.to_vec()); - } - } - self.override_remap = Some(override_remap); + self.override_remap = Some(build_override_table(remap)); if let Some(timeout) = timeout { let expiration = Expiration::OneShot(TimeSpec::from_duration(*timeout)); self.override_timer.unset()?; @@ -314,121 +312,61 @@ impl EventHandler { } fn send_key_press(&mut self, key_press: &KeyPress) -> Result<(), Box> { - let next_shift = self.build_state(Modifier::Shift, key_press.shift.clone()); - let next_control = self.build_state(Modifier::Control, key_press.control.clone()); - let next_alt = self.build_state(Modifier::Alt, key_press.alt.clone()); - let next_windows = self.build_state(Modifier::Windows, key_press.windows.clone()); + // Build missing or extra modifiers + let extra_modifiers: Vec = self + .modifiers + .iter() + .filter_map(|modifier| { + if self.contains_modifier(&key_press.modifiers, modifier) { + None + } else { + Some(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) => Some(key.clone()), + } + } + }) + .collect(); - let prev_shift = self.send_modifier(Modifier::Shift, &next_shift)?; - let prev_control = self.send_modifier(Modifier::Control, &next_control)?; - let prev_alt = self.send_modifier(Modifier::Alt, &next_alt)?; - let prev_windows = self.send_modifier(Modifier::Windows, &next_windows)?; + // Emulate the modifiers of KeyPress + self.send_keys(&extra_modifiers, RELEASE)?; + self.send_keys(&missing_modifiers, PRESS)?; + // Press the main key self.send_key(&key_press.key, PRESS)?; self.send_key(&key_press.key, RELEASE)?; - self.send_modifier(Modifier::Windows, &prev_windows)?; - self.send_modifier(Modifier::Alt, &prev_alt)?; - self.send_modifier(Modifier::Control, &prev_control)?; - self.send_modifier(Modifier::Shift, &prev_shift)?; - Ok(()) - } - - fn send_modifier(&mut self, modifier: Modifier, desired: &PressState) -> Result> { - let mut current = match modifier { - Modifier::Shift => &self.shift, - Modifier::Control => &self.control, - Modifier::Alt => &self.alt, - Modifier::Windows => &self.windows, - } - .clone(); - let original = current.clone(); - let left_key = match modifier { - Modifier::Shift => &SHIFT_KEYS[0], - Modifier::Control => &CONTROL_KEYS[0], - Modifier::Alt => &ALT_KEYS[0], - Modifier::Windows => &WINDOWS_KEYS[0], - }; - let right_key = match modifier { - Modifier::Shift => &SHIFT_KEYS[1], - Modifier::Control => &CONTROL_KEYS[1], - Modifier::Alt => &ALT_KEYS[1], - Modifier::Windows => &WINDOWS_KEYS[1], - }; - - if !current.left && desired.left { - self.send_key(left_key, PRESS)?; - current.left = true; - } else if current.left && !desired.left { - self.send_key(left_key, RELEASE)?; - current.left = false; - } - - if !current.right && desired.right { - self.send_key(right_key, PRESS)?; - current.right = true; - } else if current.right && !desired.right { - self.send_key(right_key, RELEASE)?; - current.right = false; - } - - match modifier { - Modifier::Shift => self.shift = current, - Modifier::Control => self.control = current, - Modifier::Alt => self.alt = current, - Modifier::Windows => self.windows = current, - }; - Ok(original) - } + // Resurrect the original modifiers + self.send_keys(&missing_modifiers, RELEASE)?; + self.send_keys(&extra_modifiers, PRESS)?; - fn build_state(&self, modifier: Modifier, modifier_state: ModifierState) -> PressState { - let press_state = match modifier { - Modifier::Shift => &self.shift, - Modifier::Control => &self.control, - Modifier::Alt => &self.alt, - Modifier::Windows => &self.windows, - }; - - match modifier_state { - ModifierState::Either => { - // Choose a PressState closest to the current PressState - if press_state.left || press_state.right { - press_state.clone() // no change is necessary - } else { - // Just press left - PressState { - left: true, - right: false, - } - } - } - ModifierState::Left => PressState { - left: true, - right: false, - }, - ModifierState::Right => PressState { - left: false, - right: true, - }, - ModifierState::None => PressState { - left: false, - right: false, - }, - } + Ok(()) } fn with_mark(&self, key_press: &KeyPress) -> KeyPress { - let mut shift = key_press.shift.clone(); - if self.mark_set && shift == ModifierState::None { - // We don't leave Either in expand_modifiers(), so just using Left here. - shift = ModifierState::Left; - } - KeyPress { - key: key_press.key, - shift, - control: key_press.control.clone(), - alt: key_press.alt.clone(), - windows: key_press.windows.clone(), + if self.mark_set && !self.match_modifier(&Modifier::Shift) { + let mut modifiers = key_press.modifiers.clone(); + modifiers.push(Modifier::Shift); + KeyPress { + key: key_press.key, + modifiers, + } + } else { + key_press.clone() } } @@ -455,6 +393,49 @@ 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; + } + + fn match_modifier(&self, modifier: &Modifier) -> bool { + match modifier { + Modifier::Shift => { + self.modifiers.contains(&Key::KEY_LEFTSHIFT) || self.modifiers.contains(&Key::KEY_RIGHTSHIFT) + } + Modifier::Control => { + self.modifiers.contains(&Key::KEY_LEFTCTRL) || self.modifiers.contains(&Key::KEY_RIGHTCTRL) + } + Modifier::Alt => self.modifiers.contains(&Key::KEY_LEFTALT) || self.modifiers.contains(&Key::KEY_RIGHTALT), + Modifier::Windows => { + self.modifiers.contains(&Key::KEY_LEFTMETA) || self.modifiers.contains(&Key::KEY_RIGHTMETA) + } + Modifier::Key(key) => self.modifiers.contains(key), + } + } + fn match_application(&mut self, application_matcher: &Application) -> bool { // Lazily fill the wm_class cache if self.application_cache.is_none() { @@ -475,25 +456,11 @@ impl EventHandler { false } - fn update_modifier(&mut self, code: u16, value: i32) { - if code == Key::KEY_LEFTSHIFT.code() { - self.shift.left = is_pressed(value) - } else if code == Key::KEY_RIGHTSHIFT.code() { - self.shift.right = is_pressed(value) - } else if code == Key::KEY_LEFTCTRL.code() { - self.control.left = is_pressed(value) - } else if code == Key::KEY_RIGHTCTRL.code() { - self.control.right = is_pressed(value) - } else if code == Key::KEY_LEFTALT.code() { - self.alt.left = is_pressed(value) - } else if code == Key::KEY_RIGHTALT.code() { - self.alt.right = is_pressed(value) - } else if code == Key::KEY_LEFTMETA.code() { - self.windows.left = is_pressed(value) - } else if code == Key::KEY_RIGHTMETA.code() { - self.windows.right = is_pressed(value) - } else { - panic!("unexpected key {:?} at update_modifier", Key::new(code)); + fn update_modifier(&mut self, key: Key, value: i32) { + if value == PRESS { + self.modifiers.insert(key); + } else if value == RELEASE { + self.modifiers.remove(&key); } } } @@ -534,31 +501,6 @@ lazy_static! { //--- -#[derive(Clone)] -struct PressState { - left: bool, - right: bool, -} - -impl PressState { - fn new() -> PressState { - PressState { - left: false, - right: false, - } - } - - fn to_modifier_state(&self) -> ModifierState { - if self.left { - ModifierState::Left - } else if self.right { - ModifierState::Right - } else { - ModifierState::None - } - } -} - fn is_pressed(value: i32) -> bool { value == PRESS || value == REPEAT }