mirror of
https://github.com/k0kubun/xremap
synced 2024-11-02 03:40:25 +00:00
Rename wm_class to application
This commit is contained in:
parent
4b251b1fce
commit
6547b4883d
@ -11,14 +11,14 @@ modmap:
|
||||
Henkan: Shift_L
|
||||
|
||||
- name: Kana -> Windows
|
||||
wm_class:
|
||||
application:
|
||||
not: jetbrains-idea
|
||||
remap:
|
||||
# Use Windows since Alt is annoying in Electron apps (Slack, Nocturn)
|
||||
KatakanaHiragana: Win_R
|
||||
|
||||
- name: Kana -> Alt
|
||||
wm_class:
|
||||
application:
|
||||
only: jetbrains-idea
|
||||
remap:
|
||||
# Use Alt since Windows is annoying in IDEA
|
||||
@ -34,7 +34,7 @@ keymap:
|
||||
C-j: C-m
|
||||
|
||||
- name: Default (Nocturn, etc.)
|
||||
wm_class:
|
||||
application:
|
||||
not: [Google-chrome, Slack, Gnome-terminal, jetbrains-idea]
|
||||
remap:
|
||||
# Emacs basic
|
||||
@ -69,7 +69,7 @@ keymap:
|
||||
Super-d: C-delete
|
||||
|
||||
- name: IDEA (modified from Default)
|
||||
wm_class:
|
||||
application:
|
||||
only: jetbrains-idea
|
||||
remap:
|
||||
# Emacs basic
|
||||
@ -113,7 +113,7 @@ keymap:
|
||||
C-c: Esc
|
||||
|
||||
- name: Chrome, Slack (modified from Default)
|
||||
wm_class:
|
||||
application:
|
||||
only: [Google-chrome, Slack]
|
||||
remap:
|
||||
# Emacs basic
|
||||
@ -152,7 +152,7 @@ keymap:
|
||||
Super-d: C-delete
|
||||
|
||||
- name: Tab changes + Alt-Enter simulation
|
||||
wm_class:
|
||||
application:
|
||||
not: [Gnome-terminal, Nocturn]
|
||||
remap:
|
||||
Super-o: C-Shift-tab
|
||||
@ -160,13 +160,13 @@ keymap:
|
||||
Super-Enter: M-Enter
|
||||
|
||||
- name: Google Search
|
||||
wm_class:
|
||||
application:
|
||||
only: Google-chrome
|
||||
remap:
|
||||
Super-s: C-f
|
||||
|
||||
- name: Terminal
|
||||
wm_class:
|
||||
application:
|
||||
only: Gnome-terminal
|
||||
remap:
|
||||
Super-o: M-o
|
||||
@ -185,7 +185,7 @@ keymap:
|
||||
Super-v: M-v
|
||||
|
||||
- name: Nocturn
|
||||
wm_class:
|
||||
application:
|
||||
only: Nocturn
|
||||
remap:
|
||||
Super-j: M-j
|
||||
@ -195,7 +195,7 @@ keymap:
|
||||
Super-Enter: Shift-Enter
|
||||
|
||||
- name: Slack
|
||||
wm_class:
|
||||
application:
|
||||
only: Slack
|
||||
remap:
|
||||
Super-n: C-k
|
||||
|
@ -4,7 +4,7 @@
|
||||
# a: b
|
||||
keymap:
|
||||
- name: Global
|
||||
wm_class:
|
||||
application:
|
||||
only: Slack
|
||||
remap:
|
||||
C-i: C-u
|
||||
|
@ -8,36 +8,54 @@ mod x11_client;
|
||||
mod null_client;
|
||||
|
||||
trait Client {
|
||||
fn current_wm_class(&mut self) -> Option<String>;
|
||||
fn supported(&mut self) -> bool;
|
||||
fn current_application(&mut self) -> Option<String>;
|
||||
}
|
||||
|
||||
pub struct WMClient {
|
||||
name: String,
|
||||
client: Box<dyn Client>,
|
||||
called: bool,
|
||||
last_application: String,
|
||||
}
|
||||
|
||||
impl WMClient {
|
||||
pub fn current_wm_class(&mut self) -> Option<String> {
|
||||
self.client.current_wm_class()
|
||||
fn new(name: &str, client: Box<dyn Client>) -> WMClient {
|
||||
WMClient {
|
||||
name: name.to_string(),
|
||||
client,
|
||||
called: false,
|
||||
last_application: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_application(&mut self) -> Option<String> {
|
||||
if !self.called {
|
||||
self.called = true;
|
||||
println!("application-client: {} (supported: {})", self.name, self.client.supported());
|
||||
}
|
||||
let result = self.client.current_application();
|
||||
if let Some(application) = &result {
|
||||
if &self.last_application != application {
|
||||
self.last_application = application.clone();
|
||||
println!("application: {}", application);
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sway")]
|
||||
pub fn build_client() -> WMClient {
|
||||
WMClient {
|
||||
client: Box::new(sway_client::SwayClient::new()),
|
||||
}
|
||||
WMClient::new("Sway", Box::new(sway_client::SwayClient::new()))
|
||||
}
|
||||
|
||||
#[cfg(feature = "x11")]
|
||||
pub fn build_client() -> WMClient {
|
||||
WMClient {
|
||||
client: Box::new(x11_client::X11Client::new()),
|
||||
}
|
||||
WMClient::new("X11", Box::new(x11_client::X11Client::new()))
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "sway", feature = "x11")))]
|
||||
pub fn build_client() -> WMClient {
|
||||
WMClient {
|
||||
client: Box::new(null_client::NullClient::new()),
|
||||
}
|
||||
WMClient::new("none", Box::new(null_client::NullClient))
|
||||
}
|
||||
|
@ -1,21 +1,13 @@
|
||||
use crate::client::Client;
|
||||
|
||||
pub struct NullClient {
|
||||
called: bool,
|
||||
}
|
||||
|
||||
impl NullClient {
|
||||
pub fn new() -> NullClient {
|
||||
NullClient { called: false }
|
||||
}
|
||||
}
|
||||
pub struct NullClient;
|
||||
|
||||
impl Client for NullClient {
|
||||
fn current_wm_class(&mut self) -> Option<String> {
|
||||
if !self.called {
|
||||
self.called = true;
|
||||
println!("NullClient.supported = false");
|
||||
}
|
||||
fn supported(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn current_application(&mut self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,9 @@ impl SwayClient {
|
||||
supported: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client for SwayClient {
|
||||
fn supported(&mut self) -> bool {
|
||||
match self.supported {
|
||||
Some(supported) => supported,
|
||||
@ -28,16 +30,13 @@ impl SwayClient {
|
||||
supported = true;
|
||||
}
|
||||
}
|
||||
println!("SwayClient.supported = {}", supported);
|
||||
self.supported = Some(supported);
|
||||
supported
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client for SwayClient {
|
||||
fn current_wm_class(&mut self) -> Option<String> {
|
||||
fn current_application(&mut self) -> Option<String> {
|
||||
if !self.supported() {
|
||||
return None;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ pub struct X11Client {
|
||||
// Both of them are lazily initialized
|
||||
display: Option<*mut xlib::Display>,
|
||||
supported: Option<bool>,
|
||||
last_wm_class: String,
|
||||
}
|
||||
|
||||
impl X11Client {
|
||||
@ -13,27 +12,6 @@ impl X11Client {
|
||||
X11Client {
|
||||
display: None,
|
||||
supported: None,
|
||||
last_wm_class: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn supported(&mut self) -> bool {
|
||||
match self.supported {
|
||||
Some(supported) => supported,
|
||||
None => {
|
||||
let display = self.display();
|
||||
let supported = if display.is_null() {
|
||||
false
|
||||
} else {
|
||||
let mut focused_window = 0;
|
||||
let mut focus_state = 0;
|
||||
unsafe { xlib::XGetInputFocus(display, &mut focused_window, &mut focus_state) };
|
||||
focused_window > 0
|
||||
};
|
||||
println!("X11Client.supported = {}", supported);
|
||||
self.supported = Some(supported);
|
||||
supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +28,26 @@ impl X11Client {
|
||||
}
|
||||
|
||||
impl Client for X11Client {
|
||||
fn current_wm_class(&mut self) -> Option<String> {
|
||||
fn supported(&mut self) -> bool {
|
||||
match self.supported {
|
||||
Some(supported) => supported,
|
||||
None => {
|
||||
let display = self.display();
|
||||
let supported = if display.is_null() {
|
||||
false
|
||||
} else {
|
||||
let mut focused_window = 0;
|
||||
let mut focus_state = 0;
|
||||
unsafe { xlib::XGetInputFocus(display, &mut focused_window, &mut focus_state) };
|
||||
focused_window > 0
|
||||
};
|
||||
self.supported = Some(supported);
|
||||
supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn current_application(&mut self) -> Option<String> {
|
||||
if !self.supported() {
|
||||
return None;
|
||||
}
|
||||
@ -114,11 +111,6 @@ impl Client for X11Client {
|
||||
}
|
||||
focused_window = parent;
|
||||
}
|
||||
|
||||
if &self.last_wm_class != &wm_class {
|
||||
self.last_wm_class = wm_class.clone();
|
||||
println!("wm_class: {}", &wm_class);
|
||||
}
|
||||
Some(wm_class)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use std::fmt;
|
||||
// TODO: Use trait to allow only either `only` or `not`
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WMClass {
|
||||
pub struct Application {
|
||||
#[serde(default, deserialize_with = "string_or_vec")]
|
||||
pub only: Option<Vec<String>>,
|
||||
#[serde(default, deserialize_with = "string_or_vec")]
|
@ -1,7 +1,7 @@
|
||||
use crate::config::action::Action;
|
||||
use crate::config::actions::Actions;
|
||||
use crate::config::key_press::KeyPress;
|
||||
use crate::config::wm_class::WMClass;
|
||||
use crate::config::application::Application;
|
||||
use serde::de::{MapAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::collections::HashMap;
|
||||
@ -14,7 +14,7 @@ pub struct Keymap {
|
||||
pub name: String,
|
||||
#[serde(deserialize_with = "keymap_remap")]
|
||||
pub remap: HashMap<KeyPress, Vec<Action>>,
|
||||
pub wm_class: Option<WMClass>,
|
||||
pub application: Option<Application>,
|
||||
}
|
||||
|
||||
fn keymap_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<Action>>, D::Error>
|
||||
|
@ -4,7 +4,7 @@ mod key;
|
||||
pub mod key_press;
|
||||
mod keymap;
|
||||
mod modmap;
|
||||
pub mod wm_class;
|
||||
pub mod application;
|
||||
|
||||
extern crate serde_yaml;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::config::key::parse_key;
|
||||
use crate::config::wm_class::WMClass;
|
||||
use crate::config::application::Application;
|
||||
use evdev::Key;
|
||||
use serde::de::{value, Error, MapAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
@ -12,7 +12,7 @@ pub struct Modmap {
|
||||
pub name: String,
|
||||
#[serde(deserialize_with = "modmap_remap")]
|
||||
pub remap: HashMap<Key, Key>,
|
||||
pub wm_class: Option<WMClass>,
|
||||
pub application: Option<Application>,
|
||||
}
|
||||
|
||||
fn modmap_remap<'de, D>(deserializer: D) -> Result<HashMap<Key, Key>, D::Error>
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::client::{build_client, WMClient};
|
||||
use crate::config::action::Action;
|
||||
use crate::config::key_press::{KeyPress, Modifier};
|
||||
use crate::config::wm_class::WMClass;
|
||||
use crate::config::application::Application;
|
||||
use crate::Config;
|
||||
use evdev::uinput::VirtualDevice;
|
||||
use evdev::{EventType, InputEvent, Key};
|
||||
@ -13,7 +13,7 @@ pub struct EventHandler {
|
||||
device: VirtualDevice,
|
||||
wm_client: WMClient,
|
||||
override_remap: Option<HashMap<KeyPress, Vec<Action>>>,
|
||||
wm_class_cache: Option<String>,
|
||||
application_cache: Option<String>,
|
||||
shift: PressState,
|
||||
control: PressState,
|
||||
alt: PressState,
|
||||
@ -26,7 +26,7 @@ impl EventHandler {
|
||||
device,
|
||||
wm_client: build_client(),
|
||||
override_remap: None,
|
||||
wm_class_cache: None,
|
||||
application_cache: None,
|
||||
shift: PressState::new(false),
|
||||
control: PressState::new(false),
|
||||
alt: PressState::new(false),
|
||||
@ -36,14 +36,14 @@ impl EventHandler {
|
||||
|
||||
// Handle EventType::KEY
|
||||
pub fn on_event(&mut self, event: InputEvent, config: &Config) -> Result<(), Box<dyn Error>> {
|
||||
self.wm_class_cache = None; // expire cache
|
||||
self.application_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 let Some(wm_class_matcher) = &modmap.application {
|
||||
if !self.match_wm_class(wm_class_matcher) {
|
||||
continue;
|
||||
}
|
||||
@ -98,7 +98,7 @@ impl EventHandler {
|
||||
}
|
||||
for keymap in &config.keymap {
|
||||
if let Some(actions) = keymap.remap.get(&key_press) {
|
||||
if let Some(wm_class_matcher) = &keymap.wm_class {
|
||||
if let Some(wm_class_matcher) = &keymap.application {
|
||||
if !self.match_wm_class(wm_class_matcher) {
|
||||
continue;
|
||||
}
|
||||
@ -210,21 +210,21 @@ impl EventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
fn match_wm_class(&mut self, wm_class_matcher: &WMClass) -> bool {
|
||||
fn match_wm_class(&mut self, application_matcher: &Application) -> bool {
|
||||
// Lazily fill the wm_class cache
|
||||
if let None = self.wm_class_cache {
|
||||
match self.wm_client.current_wm_class() {
|
||||
Some(wm_class) => self.wm_class_cache = Some(wm_class),
|
||||
None => self.wm_class_cache = Some(String::new()),
|
||||
if let None = self.application_cache {
|
||||
match self.wm_client.current_application() {
|
||||
Some(application) => self.application_cache = Some(application),
|
||||
None => self.application_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(application) = &self.application_cache {
|
||||
if let Some(application_only) = &application_matcher.only {
|
||||
return application_only.contains(application);
|
||||
}
|
||||
if let Some(wm_class_not) = &wm_class_matcher.not {
|
||||
return !wm_class_not.contains(wm_class);
|
||||
if let Some(application_not) = &application_matcher.not {
|
||||
return !application_not.contains(application);
|
||||
}
|
||||
}
|
||||
false
|
||||
|
Loading…
Reference in New Issue
Block a user