Implement conditional modmap properly

pull/39/head
Takashi Kokubun 3 years ago
parent 39dbc8a1fe
commit bcc4598069
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD

@ -1,6 +1,6 @@
modmap: modmap:
- name: Global - name: Global
remap: remap:
# CapsLock/Ctrl_L -> Esc # CapsLock/Ctrl_L -> Esc
CapsLock: Esc CapsLock: Esc
Ctrl_L: Esc Ctrl_L: Esc
@ -15,7 +15,7 @@ modmap:
not: jetbrains-idea not: jetbrains-idea
remap: remap:
# Use Windows since Alt is annoying in Electron apps (Slack, Nocturn) # Use Windows since Alt is annoying in Electron apps (Slack, Nocturn)
KatakanaHiragana: Win_L KatakanaHiragana: Win_R
- name: Kana -> Alt - name: Kana -> Alt
wm_class: wm_class:

@ -21,17 +21,19 @@ impl X11Client {
let display = self.display(); let display = self.display();
let mut focused_window = 0; let mut focused_window = 0;
let mut focus_state = 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; let supported = focused_window > 0;
self.supported = Some(supported); self.supported = Some(supported);
supported supported
}, }
} }
} }
pub fn current_wm_class(&mut self) -> Option<String> { pub fn current_wm_class(&mut self) -> Option<String> {
if !self.supported() { if !self.supported() {
return None return None;
} }
let display = self.display(); let display = self.display();

@ -1,7 +1,7 @@
use crate::config::key::parse_key; use crate::config::key::parse_key;
use evdev::Key; use evdev::Key;
use serde::de; use serde::de;
use serde::de::{Visitor}; use serde::de::Visitor;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use std::error; use std::error;
use std::fmt::Formatter; use std::fmt::Formatter;

@ -4,7 +4,7 @@ mod key;
pub mod key_press; pub mod key_press;
mod keymap; mod keymap;
mod modmap; mod modmap;
mod wm_class; pub mod wm_class;
extern crate serde_yaml; extern crate serde_yaml;

@ -1,17 +1,19 @@
use crate::client::x11_client::X11Client;
use crate::config::action::Action; use crate::config::action::Action;
use crate::config::key_press::{KeyPress, Modifier}; use crate::config::key_press::{KeyPress, Modifier};
use crate::config::wm_class::WMClass;
use crate::Config; use crate::Config;
use evdev::uinput::VirtualDevice; use evdev::uinput::VirtualDevice;
use evdev::{EventType, InputEvent, Key}; use evdev::{EventType, InputEvent, Key};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use crate::client::x11_client::X11Client;
pub struct EventHandler { pub struct EventHandler {
device: VirtualDevice, device: VirtualDevice,
x11_client: X11Client, x11_client: X11Client,
override_remap: Option<HashMap<KeyPress, Vec<Action>>>, override_remap: Option<HashMap<KeyPress, Vec<Action>>>,
wm_class_cache: Option<String>,
shift: bool, shift: bool,
control: bool, control: bool,
alt: bool, alt: bool,
@ -24,6 +26,7 @@ impl EventHandler {
device, device,
x11_client: X11Client::new(), x11_client: X11Client::new(),
override_remap: None, override_remap: None,
wm_class_cache: None,
shift: false, shift: false,
control: false, control: false,
alt: false, alt: false,
@ -33,12 +36,18 @@ impl EventHandler {
// Handle EventType::KEY // Handle EventType::KEY
pub fn on_event(&mut self, event: InputEvent, config: &Config) -> Result<(), Box<dyn Error>> { pub fn on_event(&mut self, event: InputEvent, config: &Config) -> Result<(), Box<dyn Error>> {
self.wm_class_cache = None; // expire cache
let mut key = Key::new(event.code()); let mut key = Key::new(event.code());
// println!("=> {}: {:?}", event.value(), &key); // println!("=> {}: {:?}", event.value(), &key);
// Apply modmap // Apply modmap
for modmap in &config.modmap { for modmap in &config.modmap {
if let Some(modmap_key) = modmap.remap.get(&key) { 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(); key = modmap_key.clone();
break; break;
} }
@ -72,7 +81,6 @@ impl EventHandler {
if !is_pressed(value) { if !is_pressed(value) {
return None; return None;
} }
let mut wm_class_cache: Option<String> = None;
let key_press = KeyPress { let key_press = KeyPress {
key: key.clone(), key: key.clone(),
@ -90,28 +98,11 @@ impl EventHandler {
} }
for keymap in &config.keymap { for keymap in &config.keymap {
if let Some(actions) = keymap.remap.get(&key_press) { 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 Some(wm_class_matcher) = &keymap.wm_class {
if let None = &wm_class_cache { if !self.match_wm_class(wm_class_matcher) {
match self.x11_client.current_wm_class() { continue;
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;
}
}
} }
} }
return Some(actions.iter().map(|a| a.clone()).collect()); return Some(actions.iter().map(|a| a.clone()).collect());
} }
} }
@ -158,6 +149,26 @@ impl EventHandler {
Ok(()) 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) { fn update_modifier(&mut self, modifier: &Modifier, value: i32) {
match modifier { match modifier {
Modifier::Shift => self.shift = is_pressed(value), Modifier::Shift => self.shift = is_pressed(value),
@ -193,8 +204,8 @@ lazy_static! {
(Key::KEY_RIGHTMETA.code(), Modifier::Windows), (Key::KEY_RIGHTMETA.code(), Modifier::Windows),
].into_iter().collect(); ].into_iter().collect();
static ref SHIFT_KEY: Key = Key::new(Key::KEY_LEFTSHIFT.code()); static ref SHIFT_KEY: Key = Key::new(Key::KEY_RIGHTSHIFT.code());
static ref CONTROL_KEY: Key = Key::new(Key::KEY_LEFTCTRL.code()); static ref CONTROL_KEY: Key = Key::new(Key::KEY_RIGHTCTRL.code());
static ref ALT_KEY: Key = Key::new(Key::KEY_LEFTALT.code()); static ref ALT_KEY: Key = Key::new(Key::KEY_RIGHTALT.code());
static ref WINDOWS_KEY: Key = Key::new(Key::KEY_LEFTMETA.code()); static ref WINDOWS_KEY: Key = Key::new(Key::KEY_RIGHTMETA.code());
} }

Loading…
Cancel
Save