Implement launch action

This commit is contained in:
Takashi Kokubun 2021-12-30 00:23:45 -08:00
parent a7e9b92bad
commit dc5660754a
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD
7 changed files with 39 additions and 63 deletions

View File

@ -1,10 +0,0 @@
hotkeys:
- name: hotkey_test
keys:
- KEY_GRAVE
application:
not: [Google-chrome, konsole]
command:
- "/bin/sh"
- "-c"
- "date > /tmp/hotkey_test"

View File

@ -1,6 +1,6 @@
use log::{debug, error};
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.

View File

@ -12,6 +12,8 @@ pub enum Action {
KeyPress(KeyPress),
#[serde(deserialize_with = "deserialize_remap")]
Remap(HashMap<KeyPress, Vec<Action>>),
#[serde(deserialize_with = "deserialize_launch")]
Launch(Vec<String>),
}
fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<Action>>, D::Error>
@ -27,6 +29,19 @@ where
Err(de::Error::custom("not a map with a single \"remap\" key"))
}
fn deserialize_launch<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
D: Deserializer<'de>,
{
let mut action = HashMap::<String, Vec<String>>::deserialize(deserializer)?;
if let Some(launch) = action.remove("launch") {
if action.is_empty() {
return Ok(launch);
}
}
Err(de::Error::custom("not a map with a single \"launch\" key"))
}
// Used only for deserializing Vec<Action>
#[derive(Deserialize)]
#[serde(untagged)]

View File

@ -1,13 +0,0 @@
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>,
}

View File

@ -3,7 +3,6 @@ pub mod application;
mod key;
pub mod key_action;
pub mod key_press;
mod hotkey;
mod keymap;
mod modmap;
@ -14,7 +13,6 @@ extern crate serde_yaml;
use keymap::Keymap;
use modmap::Modmap;
use hotkey::Hotkey;
use serde::Deserialize;
use std::{error, fs};
@ -25,8 +23,6 @@ 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::Error>> {

View File

@ -101,6 +101,19 @@ fn test_keymap_remap() {
"})
}
#[test]
fn test_keymap_launch() {
assert_parse(indoc! {"
keymap:
- remap:
KEY_GRAVE:
launch:
- '/bin/sh'
- '-c'
- 'date > /tmp/hotkey_test'
"})
}
fn assert_parse(yaml: &str) {
let result: Result<Config, Error> = serde_yaml::from_str(&yaml);
if let Err(e) = result {

View File

@ -58,13 +58,9 @@ impl EventHandler {
// Apply keymap
for (key, value) in key_values.into_iter() {
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()) {
if MODIFIER_KEYS.contains(&key.code()) {
self.update_modifier(key.code(), value);
} else if let Some(actions) = self.find_keymap(config, &key_press, value) {
} else if let Some(actions) = self.find_keymap(config, &key, value) {
for action in &actions {
self.dispatch_action(action)?;
}
@ -75,25 +71,6 @@ 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()))
@ -172,21 +149,18 @@ impl EventHandler {
None
}
fn key_to_key_press(&mut self, key: &Key) -> KeyPress {
KeyPress {
fn find_keymap(&mut self, config: &Config, key: &Key, value: i32) -> Option<Vec<Action>> {
if !is_pressed(value) {
return None;
}
let key_press = 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;
@ -235,6 +209,7 @@ impl EventHandler {
}
self.override_remap = Some(override_remap)
}
Action::Launch(command) => run_command(command.clone()),
}
Ok(())
}