From bcc45980694664b717c70ca3cda491129efb49c6 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Mon, 20 Dec 2021 21:13:47 -0800 Subject: [PATCH] Implement conditional modmap properly --- example/config.yml | 4 +-- src/client/x11_client.rs | 8 ++++-- src/config/key_press.rs | 2 +- src/config/mod.rs | 2 +- src/event_handler.rs | 61 ++++++++++++++++++++++++---------------- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/example/config.yml b/example/config.yml index a93df36..ac781ed 100644 --- a/example/config.yml +++ b/example/config.yml @@ -1,6 +1,6 @@ modmap: - name: Global - remap: + remap: # CapsLock/Ctrl_L -> Esc CapsLock: Esc Ctrl_L: Esc @@ -15,7 +15,7 @@ modmap: not: jetbrains-idea remap: # Use Windows since Alt is annoying in Electron apps (Slack, Nocturn) - KatakanaHiragana: Win_L + KatakanaHiragana: Win_R - name: Kana -> Alt wm_class: diff --git a/src/client/x11_client.rs b/src/client/x11_client.rs index 8b6c064..41e59f3 100644 --- a/src/client/x11_client.rs +++ b/src/client/x11_client.rs @@ -21,17 +21,19 @@ impl X11Client { let display = self.display(); let mut focused_window = 0; let mut focus_state = 0; - unsafe { x11::xlib::XGetInputFocus(display, &mut focused_window, &mut focus_state) }; + unsafe { + x11::xlib::XGetInputFocus(display, &mut focused_window, &mut focus_state) + }; let supported = focused_window > 0; self.supported = Some(supported); supported - }, + } } } pub fn current_wm_class(&mut self) -> Option { if !self.supported() { - return None + return None; } let display = self.display(); diff --git a/src/config/key_press.rs b/src/config/key_press.rs index 1c452ea..03cdcfc 100644 --- a/src/config/key_press.rs +++ b/src/config/key_press.rs @@ -1,7 +1,7 @@ use crate::config::key::parse_key; use evdev::Key; use serde::de; -use serde::de::{Visitor}; +use serde::de::Visitor; use serde::{Deserialize, Deserializer}; use std::error; use std::fmt::Formatter; diff --git a/src/config/mod.rs b/src/config/mod.rs index 0e07533..a1c5710 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -4,7 +4,7 @@ mod key; pub mod key_press; mod keymap; mod modmap; -mod wm_class; +pub mod wm_class; extern crate serde_yaml; diff --git a/src/event_handler.rs b/src/event_handler.rs index 5a6c488..4347b64 100644 --- a/src/event_handler.rs +++ b/src/event_handler.rs @@ -1,17 +1,19 @@ +use crate::client::x11_client::X11Client; use crate::config::action::Action; use crate::config::key_press::{KeyPress, Modifier}; +use crate::config::wm_class::WMClass; use crate::Config; use evdev::uinput::VirtualDevice; use evdev::{EventType, InputEvent, Key}; use lazy_static::lazy_static; use std::collections::HashMap; use std::error::Error; -use crate::client::x11_client::X11Client; pub struct EventHandler { device: VirtualDevice, x11_client: X11Client, override_remap: Option>>, + wm_class_cache: Option, shift: bool, control: bool, alt: bool, @@ -24,6 +26,7 @@ impl EventHandler { device, x11_client: X11Client::new(), override_remap: None, + wm_class_cache: None, shift: false, control: false, alt: false, @@ -33,12 +36,18 @@ impl EventHandler { // Handle EventType::KEY pub fn on_event(&mut self, event: InputEvent, config: &Config) -> Result<(), Box> { + self.wm_class_cache = None; // expire cache let mut key = Key::new(event.code()); // println!("=> {}: {:?}", event.value(), &key); // Apply modmap for modmap in &config.modmap { if let Some(modmap_key) = modmap.remap.get(&key) { + if let Some(wm_class_matcher) = &modmap.wm_class { + if !self.match_wm_class(wm_class_matcher) { + continue; + } + } key = modmap_key.clone(); break; } @@ -72,7 +81,6 @@ impl EventHandler { if !is_pressed(value) { return None; } - let mut wm_class_cache: Option = None; let key_press = KeyPress { key: key.clone(), @@ -90,28 +98,11 @@ impl EventHandler { } for keymap in &config.keymap { if let Some(actions) = keymap.remap.get(&key_press) { - // Lazily check wm_class as needed if let Some(wm_class_matcher) = &keymap.wm_class { - if let None = &wm_class_cache { - match self.x11_client.current_wm_class() { - Some(wm_class) => wm_class_cache = Some(wm_class), - None => wm_class_cache = Some(String::new()), - } - } - if let Some(wm_class) = &wm_class_cache { - if let Some(wm_class_only) = &wm_class_matcher.only { - if !wm_class_only.contains(wm_class) { - continue; - } - } - if let Some(wm_class_not) = &wm_class_matcher.not { - if wm_class_not.contains(wm_class) { - continue; - } - } + if !self.match_wm_class(wm_class_matcher) { + continue; } } - return Some(actions.iter().map(|a| a.clone()).collect()); } } @@ -158,6 +149,26 @@ impl EventHandler { Ok(()) } + fn match_wm_class(&mut self, wm_class_matcher: &WMClass) -> bool { + // Lazily fill the wm_class cache + if let None = self.wm_class_cache { + match self.x11_client.current_wm_class() { + Some(wm_class) => self.wm_class_cache = Some(wm_class), + None => self.wm_class_cache = Some(String::new()), + } + } + + if let Some(wm_class) = &self.wm_class_cache { + if let Some(wm_class_only) = &wm_class_matcher.only { + return wm_class_only.contains(wm_class); + } + if let Some(wm_class_not) = &wm_class_matcher.not { + return !wm_class_not.contains(wm_class); + } + } + false + } + fn update_modifier(&mut self, modifier: &Modifier, value: i32) { match modifier { Modifier::Shift => self.shift = is_pressed(value), @@ -193,8 +204,8 @@ lazy_static! { (Key::KEY_RIGHTMETA.code(), Modifier::Windows), ].into_iter().collect(); - static ref SHIFT_KEY: Key = Key::new(Key::KEY_LEFTSHIFT.code()); - static ref CONTROL_KEY: Key = Key::new(Key::KEY_LEFTCTRL.code()); - static ref ALT_KEY: Key = Key::new(Key::KEY_LEFTALT.code()); - static ref WINDOWS_KEY: Key = Key::new(Key::KEY_LEFTMETA.code()); + static ref SHIFT_KEY: Key = Key::new(Key::KEY_RIGHTSHIFT.code()); + static ref CONTROL_KEY: Key = Key::new(Key::KEY_RIGHTCTRL.code()); + static ref ALT_KEY: Key = Key::new(Key::KEY_RIGHTALT.code()); + static ref WINDOWS_KEY: Key = Key::new(Key::KEY_RIGHTMETA.code()); }