mirror of
https://github.com/k0kubun/xremap
synced 2024-11-02 03:40:25 +00:00
Add hotkey command support
This commit is contained in:
parent
7df4333ea1
commit
225f8019bd
10
example/hotkey_test.yml
Normal file
10
example/hotkey_test.yml
Normal file
@ -0,0 +1,10 @@
|
||||
hotkeys:
|
||||
- name: hotkey_test
|
||||
keys:
|
||||
- KEY_GRAVE
|
||||
application:
|
||||
not: [Google-chrome, konsole]
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-c"
|
||||
- "date > /tmp/hotkey_test"
|
32
src/command.rs
Normal file
32
src/command.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use std::process::{Command, Stdio};
|
||||
use std::thread;
|
||||
use log::{debug, error};
|
||||
|
||||
pub fn run_command(command: Vec<String>) {
|
||||
// To avoid defunct processes, spawn a thread to wait on the process.
|
||||
thread::spawn(move || {
|
||||
debug!("Running command: {:?}", command);
|
||||
match Command::new(&command[0])
|
||||
.args(&command[1..])
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.spawn()
|
||||
{
|
||||
Err(e) => {
|
||||
error!("Error running command: {:?}", e);
|
||||
}
|
||||
Ok(mut child) => {
|
||||
debug!("Process spawned: {:?}, pid {}", command, child.id());
|
||||
match child.wait() {
|
||||
Ok(status) => {
|
||||
debug!("Process exited: pid: {}, status: {:?}", child.id(), status);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Error from process: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
13
src/config/hotkey.rs
Normal file
13
src/config/hotkey.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use crate::config::application::Application;
|
||||
use crate::config::key_press::KeyPress;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Hotkey {
|
||||
#[serde(default = "String::new")]
|
||||
pub name: String,
|
||||
pub keys: Vec<KeyPress>,
|
||||
pub command: Vec<String>,
|
||||
pub application: Option<Application>,
|
||||
}
|
@ -3,6 +3,7 @@ pub mod application;
|
||||
pub mod key;
|
||||
pub mod key_action;
|
||||
pub mod key_press;
|
||||
mod hotkey;
|
||||
mod keymap;
|
||||
mod modmap;
|
||||
|
||||
@ -13,6 +14,7 @@ extern crate serde_yaml;
|
||||
|
||||
use keymap::Keymap;
|
||||
use modmap::Modmap;
|
||||
use hotkey::Hotkey;
|
||||
use serde::Deserialize;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
@ -24,6 +26,8 @@ pub struct Config {
|
||||
pub modmap: Vec<Modmap>,
|
||||
#[serde(default = "Vec::new")]
|
||||
pub keymap: Vec<Keymap>,
|
||||
#[serde(default = "Vec::new")]
|
||||
pub hotkeys: Vec<Hotkey>,
|
||||
}
|
||||
|
||||
pub fn load_config(filename: &str) -> Result<Config, Box<dyn Error>> {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::client::{build_client, WMClient};
|
||||
use crate::command::run_command;
|
||||
use crate::config::action::Action;
|
||||
use crate::config::application::Application;
|
||||
use crate::config::key_action::KeyAction;
|
||||
@ -57,9 +58,13 @@ impl EventHandler {
|
||||
|
||||
// Apply keymap
|
||||
for (key, value) in key_values.into_iter() {
|
||||
if MODIFIER_KEYS.contains(&key.code()) {
|
||||
let key_press = self.key_to_key_press(&key);
|
||||
// Run hotkey commands
|
||||
if self.handle_hotkey(&key_press, value, &config) {
|
||||
return Ok(());
|
||||
} else if MODIFIER_KEYS.contains(&key.code()) {
|
||||
self.update_modifier(key.code(), value);
|
||||
} else if let Some(actions) = self.find_keymap(config, &key, value) {
|
||||
} else if let Some(actions) = self.find_keymap(config, &key_press, value) {
|
||||
for action in &actions {
|
||||
self.dispatch_action(action)?;
|
||||
}
|
||||
@ -70,6 +75,25 @@ impl EventHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_hotkey(&mut self, key_press: &KeyPress, value: i32, config: &Config) -> bool {
|
||||
let mut hotkey_used = false;
|
||||
'outer_hotkey: for hotkey in &config.hotkeys {
|
||||
for hotkey_key_press in &hotkey.keys {
|
||||
if hotkey_key_press == key_press && is_pressed(value) {
|
||||
if let Some(app) = &hotkey.application {
|
||||
if !self.match_application(app) {
|
||||
continue 'outer_hotkey;
|
||||
}
|
||||
}
|
||||
run_command(hotkey.command.clone());
|
||||
hotkey_used = true;
|
||||
break 'outer_hotkey;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hotkey_used;
|
||||
}
|
||||
|
||||
pub fn send_event(&mut self, event: InputEvent) -> std::io::Result<()> {
|
||||
if event.event_type() == EventType::KEY {
|
||||
debug!("{}: {:?}", event.value(), Key::new(event.code()))
|
||||
@ -150,18 +174,21 @@ impl EventHandler {
|
||||
None
|
||||
}
|
||||
|
||||
fn find_keymap(&mut self, config: &Config, key: &Key, value: i32) -> Option<Vec<Action>> {
|
||||
if !is_pressed(value) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let key_press = KeyPress {
|
||||
fn key_to_key_press(&mut self, key: &Key) -> KeyPress {
|
||||
KeyPress {
|
||||
key: key.clone(),
|
||||
shift: self.shift.left || self.shift.right,
|
||||
control: self.control.left || self.control.right,
|
||||
alt: self.alt.left || self.alt.right,
|
||||
windows: self.windows.left || self.windows.right,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn find_keymap(&mut self, config: &Config, key_press: &KeyPress, value: i32) -> Option<Vec<Action>> {
|
||||
if !is_pressed(value) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(override_remap) = &self.override_remap {
|
||||
let override_remap = override_remap.clone();
|
||||
self.override_remap = None;
|
||||
|
@ -15,6 +15,7 @@ use std::process::exit;
|
||||
extern crate getopts;
|
||||
|
||||
mod client;
|
||||
mod command;
|
||||
mod config;
|
||||
mod device;
|
||||
mod event_handler;
|
||||
|
Loading…
Reference in New Issue
Block a user