Added shell command invocation through bindings

This commit is contained in:
cyber-sushi 2024-04-13 05:39:22 +02:00
parent 3846a358c1
commit de0cc97475
9 changed files with 222 additions and 104 deletions

View file

@ -13,5 +13,12 @@ KEY_LEFTSHIFT.KEY_UP = ["KEY_LEFTSHIFT", "KEY_PAGEUP"]
KEY_LEFTSHIFT.KEY_DOWN = ["KEY_LEFTSHIFT", "KEY_PAGEDOWN"] KEY_LEFTSHIFT.KEY_DOWN = ["KEY_LEFTSHIFT", "KEY_PAGEDOWN"]
KEY_LEFTSHIFT-KEY_LEFTMETA-KEY_LEFTALT.BTN_RIGHT = ["KEY_LEFTCTRL", "KEY_C"] KEY_LEFTSHIFT-KEY_LEFTMETA-KEY_LEFTALT.BTN_RIGHT = ["KEY_LEFTCTRL", "KEY_C"]
[commands]
#Examples of Modifier + Key => run a shell command
KEY_LEFTCTRL.KEY_N = ["nautilus"]
KEY_LEFTMETA.KEY_F = ["firefox", "discord"]
KEY_LEFTALT.KEY_SPACE = ["foot sh -c 'pacman -Q | wc -l && sleep 1 && neofetch' && sleep 5"]
KEY_LEFTCTRL-KEY_LEFTALT-KEY_LEFTSHIFT.KEY_O = ["notify-send 'OwO'"]
[settings] [settings]
GRAB_DEVICE = "true" #gain exclusivity on the device GRAB_DEVICE = "true" #gain exclusivity on the device

View file

@ -15,8 +15,12 @@ KEY_LEFTCTRL.BTN_RIGHT = ["KEY_SYSRQ"]
KEY_LEFTCTRL-KEY_LEFTSHIFT.BTN_LEFT = ["KEY_LEFTSHIFT", "KEY_DELETE"] KEY_LEFTCTRL-KEY_LEFTSHIFT.BTN_LEFT = ["KEY_LEFTSHIFT", "KEY_DELETE"]
#Examples of Modifier(s) + Axis event => Key(s) #Examples of Modifier(s) + Axis event => Key(s)
KEY_LEFTCTRL-KEY_LEFTSHIFT.SCROLL_WHEEL_UP = ["KEY_HOME"] KEY_LEFTCTRL-KEY_LEFTSHIFT.SCROLL_WHEEL_UP = ["KEY_HOME"]
KEY_LEFTCTRL-KEY_LEFTSHIFT.SCROLL_WHEEL_DOWN = ["KEY_END"]
KEY_LEFTCTRL-KEY_LEFTSHIFT-KEY_LEFTALT.SCROLL_WHEEL_DOWN = ["KEY_LEFTALT", "KEY_F4"] KEY_LEFTCTRL-KEY_LEFTSHIFT-KEY_LEFTALT.SCROLL_WHEEL_DOWN = ["KEY_LEFTALT", "KEY_F4"]
[commands]
#Examples of Modifier + Key => run a shell command
KEY_LEFTCTRL-KEY_LEFTSHIFT.SCROLL_WHEEL_DOWN = ["foot sh -c 'pacman -Q | wc -l && sleep 1 && neofetch' && sleep 5"]
BTN_MIDDLE = ["notify-send 'OwO'"]
[settings] [settings]
GRAB_DEVICE = "true" #gain exclusivity on the device GRAB_DEVICE = "true" #gain exclusivity on the device

View file

@ -27,8 +27,10 @@ BTN_DPAD_DOWN = ["KEY_DOWN"] #directional pad down
BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left
RSTICK_UP = ["KEY_UP"] #right analog stick up RSTICK_UP = ["KEY_UP"] #right analog stick up
RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down
RSTICK_LEFT = ["KEY_LEFT"] #right analog stick left
RSTICK_RIGHT = ["KEY_RIGHT"] #right analog stick right [commands]
RSTICK_LEFT = ["foot sh -c 'pacman -Q | wc -l && sleep 1 && neofetch' && sleep 5"] #right analog stick left
RSTICK_RIGHT = ["firefox", "discord"] #right analog stick right
[settings] [settings]
LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1 LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1

View file

@ -26,8 +26,10 @@ BTN_DPAD_DOWN = ["KEY_DOWN"] #directional pad down
BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left
RSTICK_UP = ["KEY_UP"] #right analog stick up RSTICK_UP = ["KEY_UP"] #right analog stick up
RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down
RSTICK_LEFT = ["KEY_LEFT"] #right analog stick left
RSTICK_RIGHT = ["KEY_RIGHT"] #right analog stick right [commands]
RSTICK_LEFT = ["foot sh -c 'pacman -Q | wc -l && sleep 1 && neofetch' && sleep 5"] #right analog stick left
RSTICK_RIGHT = ["firefox", "discord"] #right analog stick right
[settings] [settings]
LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1 LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1

View file

@ -29,8 +29,10 @@ BTN_DPAD_DOWN = ["KEY_DOWN"] #directional pad down
BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left
RSTICK_UP = ["KEY_UP"] #right analog stick up RSTICK_UP = ["KEY_UP"] #right analog stick up
RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down
RSTICK_LEFT = ["KEY_LEFT"] #right analog stick left
RSTICK_RIGHT = ["KEY_RIGHT"] #right analog stick right [commands]
RSTICK_LEFT = ["foot sh -c 'pacman -Q | wc -l && sleep 1 && neofetch' && sleep 5"] #right analog stick left
RSTICK_RIGHT = ["firefox", "discord"] #right analog stick right
[settings] [settings]
LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1 LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1

View file

@ -28,8 +28,10 @@ BTN_DPAD_DOWN = ["KEY_DOWN"] #directional pad down
BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left
RSTICK_UP = ["KEY_UP"] #right analog stick up RSTICK_UP = ["KEY_UP"] #right analog stick up
RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down
RSTICK_LEFT = ["KEY_LEFT"] #right analog stick left
RSTICK_RIGHT = ["KEY_RIGHT"] #right analog stick right [commands]
RSTICK_LEFT = ["foot sh -c 'pacman -Q | wc -l && sleep 1 && neofetch' && sleep 5"] #right analog stick left
RSTICK_RIGHT = ["firefox", "discord"] #right analog stick right
[settings] [settings]
LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1 LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1

View file

@ -27,8 +27,10 @@ BTN_DPAD_DOWN = ["KEY_DOWN"] #directional pad down
BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left BTN_DPAD_LEFT = ["KEY_LEFT"] #directional pad left
RSTICK_UP = ["KEY_UP"] #right analog stick up RSTICK_UP = ["KEY_UP"] #right analog stick up
RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down RSTICK_DOWN = ["KEY_DOWN"] #right analog stick down
RSTICK_LEFT = ["KEY_LEFT"] #right analog stick left
RSTICK_RIGHT = ["KEY_RIGHT"] #right analog stick right [commands]
RSTICK_LEFT = ["foot sh -c 'pacman -Q | wc -l && sleep 1 && neofetch' && sleep 5"] #right analog stick left
RSTICK_RIGHT = ["firefox", "discord"] #right analog stick right
[settings] [settings]
LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1 LSTICK_SENSITIVITY = "6" #sensitivity when scrolling or moving cursor, lower value is higher sensitivity, minimum 1

View file

@ -8,118 +8,202 @@ use serde;
pub struct Bindings { pub struct Bindings {
pub keys: HashMap<Key, Vec<Key>>, pub keys: HashMap<Key, Vec<Key>>,
pub axis: HashMap<String, Vec<Key>>, pub axis: HashMap<String, Vec<Key>>,
pub keys_sh: HashMap<Key, Vec<String>>,
pub axis_sh: HashMap<String, Vec<String>>,
} }
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct Combinations { pub struct Combinations {
pub keys: HashMap<String, HashMap<Key, Vec<Key>>>, pub keys: HashMap<String, HashMap<Key, Vec<Key>>>,
pub axis: HashMap<String, HashMap<String, Vec<Key>>>, pub axis: HashMap<String, HashMap<String, Vec<Key>>>,
pub keys_sh: HashMap<String, HashMap<Key, Vec<String>>>,
pub axis_sh: HashMap<String, HashMap<String, Vec<String>>>,
} }
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct Modifiers { pub struct Modifiers {
pub keys: HashMap<BTreeMap<Key, i32>, HashMap<Key, Vec<Key>>>, pub keys: HashMap<BTreeMap<Key, i32>, HashMap<Key, Vec<Key>>>,
pub axis: HashMap<BTreeMap<Key, i32>, HashMap<String, Vec<Key>>>, pub axis: HashMap<BTreeMap<Key, i32>, HashMap<String, Vec<Key>>>,
pub keys_sh: HashMap<BTreeMap<Key, i32>, HashMap<Key, Vec<String>>>,
pub axis_sh: HashMap<BTreeMap<Key, i32>, HashMap<String, Vec<String>>>,
} }
#[derive(serde::Deserialize, Debug, Clone)] #[derive(serde::Deserialize, Debug, Clone)]
pub struct Config { pub struct RawConfig {
#[serde(skip)]
pub name: String,
#[serde(default)] #[serde(default)]
pub remap: HashMap<String, Vec<Key>>, pub remap: HashMap<String, Vec<Key>>,
#[serde(skip)] #[serde(default)]
pub commands: HashMap<String, Vec<String>>,
pub settings: HashMap<String, String>,
}
impl RawConfig {
fn new_from_file(file: &str) -> Self {
println!("Parsing config file:\n{:?}\n", file);
let file_content: String = std::fs::read_to_string(file).unwrap();
let raw_config: RawConfig = toml::from_str(&file_content)
.expect("Couldn't parse config file.");
let remap = raw_config.remap;
let commands = raw_config.commands;
let settings = raw_config.settings;
Self {
remap,
commands,
settings,
}
}
}
#[derive(Debug, Clone)]
pub struct Config {
pub name: String,
pub bindings: Bindings, pub bindings: Bindings,
#[serde(skip)]
pub combinations: Combinations,
#[serde(skip)]
pub modifiers: Modifiers, pub modifiers: Modifiers,
pub settings: HashMap<String, String>, pub settings: HashMap<String, String>,
} }
impl Config { impl Config {
pub fn new_from_file(file: &str, file_name: String) -> Self { pub fn new_from_file(file: &str, file_name: String) -> Self {
println!("Parsing config file:\n{:?}\n", file); let raw_config = RawConfig::new_from_file(file);
let file_content: String = std::fs::read_to_string(file).unwrap(); let (bindings, combinations, settings) = parse_raw_config(raw_config);
let config: Config = toml::from_str(&file_content) let bindings: Bindings = merge_axis_bindings(bindings);
.expect("Couldn't parse config file."); let modifiers: Modifiers = parse_modifiers(combinations);
let settings: HashMap<String, String> = config.settings;
let remap: HashMap<String, Vec<Key>> = config.remap;
let mut bindings: Bindings = Default::default();
let mut combinations: Combinations = Default::default();
let abs = [ Self {
"DPAD_UP", name: file_name,
"DPAD_DOWN", bindings,
"DPAD_LEFT", modifiers,
"DPAD_RIGHT", settings,
"LSTICK_UP", }
"LSTICK_DOWN", }
"LSTICK_LEFT", }
"LSTICK_RIGHT",
"RSTICK_UP", fn parse_raw_config(raw_config: RawConfig) -> (Bindings, Combinations, HashMap<String, String>) {
"RSTICK_DOWN", let remap: HashMap<String, Vec<Key>> = raw_config.remap;
"RSTICK_LEFT", let commands: HashMap<String, Vec<String>> = raw_config.commands;
"RSTICK_RIGHT", let settings: HashMap<String, String> = raw_config.settings;
"SCROLLWHEEL_UP", let mut bindings: Bindings = Default::default();
"SCROLLWHEEL_DOWN", let mut combinations: Combinations = Default::default();
"BTN_TL2",
"BTN_TR2", let abs = [
]; "DPAD_UP",
for (input, output) in remap.clone().into_iter() { "DPAD_DOWN",
if input.contains(".") { "DPAD_LEFT",
let (mods, key) = input.split_once(".").unwrap(); "DPAD_RIGHT",
if abs.contains(&key) { "LSTICK_UP",
if !combinations.axis.contains_key(&mods.to_string()) { "LSTICK_DOWN",
combinations.axis.insert(mods.to_string(), HashMap::from([(key.to_string(), output)])); "LSTICK_LEFT",
} else { "LSTICK_RIGHT",
combinations.axis.get_mut(mods).unwrap().insert(key.to_string(), output); "RSTICK_UP",
} "RSTICK_DOWN",
"RSTICK_LEFT",
"RSTICK_RIGHT",
"SCROLLWHEEL_UP",
"SCROLLWHEEL_DOWN",
"BTN_TL2",
"BTN_TR2",
];
for (input, output) in remap.clone().into_iter() {
if input.contains(".") {
let (mods, key) = input.split_once(".").unwrap();
if abs.contains(&key) {
if !combinations.axis.contains_key(&mods.to_string()) {
combinations.axis.insert(mods.to_string(), HashMap::from([(key.to_string(), output)]));
} else { } else {
if !combinations.keys.contains_key(&mods.to_string()) { combinations.axis.get_mut(mods).unwrap().insert(key.to_string(), output);
combinations.keys.insert(mods.to_string(), HashMap::from([(Key::from_str(key).expect("Invalid KEY value."), output)]));
} else {
combinations.keys.get_mut(mods).unwrap().insert(Key::from_str(key).expect("Invalid KEY value."), output);
}
} }
} else { } else {
if abs.contains(&input.as_str()) { if !combinations.keys.contains_key(&mods.to_string()) {
bindings.axis.insert(input, output); combinations.keys.insert(mods.to_string(), HashMap::from([(Key::from_str(key).expect("Invalid KEY value."), output)]));
} else { } else {
bindings.keys.insert(Key::from_str(input.as_str()).expect("Invalid KEY value."), output); combinations.keys.get_mut(mods).unwrap().insert(Key::from_str(key).expect("Invalid KEY value."), output);
} }
} }
} } else {
if abs.contains(&input.as_str()) {
let empty_modmap = BTreeMap::from ([ bindings.axis.insert(input, output);
(Key::KEY_LEFTSHIFT, 0), } else {
(Key::KEY_LEFTCTRL, 0), bindings.keys.insert(Key::from_str(input.as_str()).expect("Invalid KEY value."), output);
(Key::KEY_LEFTALT, 0),
(Key::KEY_RIGHTSHIFT, 0),
(Key::KEY_RIGHTCTRL, 0),
(Key::KEY_RIGHTALT, 0),
(Key::KEY_LEFTMETA, 0)
]);
let mut modifiers: Modifiers = Default::default();
for (mods, key) in combinations.keys.iter() {
let mods_vector = mods.split("+").map(str::to_string).collect::<Vec<String>>();
let mut modmap = empty_modmap.clone();
for modifier in mods_vector {
modmap.insert(Key::from_str(&modifier).unwrap(), 1);
} }
modifiers.keys.insert(modmap, key.clone());
}
for (mods, key) in combinations.axis.iter() {
let mods_vector = mods.split("+").map(str::to_string).collect::<Vec<String>>();
let mut modmap = empty_modmap.clone();
for modifier in mods_vector {
modmap.insert(Key::from_str(&modifier).unwrap(), 1);
}
modifiers.axis.insert(modmap, key.clone());
} }
}
for (input, output) in commands.clone().into_iter() {
if input.contains(".") {
let (mods, key) = input.split_once(".").unwrap();
if abs.contains(&key) {
if !combinations.axis_sh.contains_key(&mods.to_string()) {
combinations.axis_sh.insert(mods.to_string(), HashMap::from([(key.to_string(), output)]));
} else {
combinations.axis_sh.get_mut(mods).unwrap().insert(key.to_string(), output);
}
} else {
if !combinations.keys_sh.contains_key(&mods.to_string()) {
combinations.keys_sh.insert(mods.to_string(), HashMap::from([(Key::from_str(key).expect("Invalid KEY value."), output)]));
} else {
combinations.keys_sh.get_mut(mods).unwrap().insert(Key::from_str(key).expect("Invalid KEY value."), output);
}
}
} else {
if abs.contains(&input.as_str()) {
bindings.axis_sh.insert(input, output);
} else {
bindings.keys_sh.insert(Key::from_str(input.as_str()).expect("Invalid KEY value."), output);
}
}
}
(bindings, combinations, settings)
}
fn parse_modifiers(combinations: Combinations) -> Modifiers {
let empty_modmap = BTreeMap::from ([
(Key::KEY_LEFTSHIFT, 0),
(Key::KEY_LEFTCTRL, 0),
(Key::KEY_LEFTALT, 0),
(Key::KEY_RIGHTSHIFT, 0),
(Key::KEY_RIGHTCTRL, 0),
(Key::KEY_RIGHTALT, 0),
(Key::KEY_LEFTMETA, 0)
]);
let mut modifiers: Modifiers = Default::default();
for (mods, key) in combinations.keys.iter() {
let mods_vector = mods.split("-").map(str::to_string).collect::<Vec<String>>();
let mut modmap = empty_modmap.clone();
for modifier in mods_vector {
modmap.insert(Key::from_str(&modifier).unwrap(), 1);
}
modifiers.keys.insert(modmap, key.clone());
}
for (mods, key) in combinations.axis.iter() {
let mods_vector = mods.split("-").map(str::to_string).collect::<Vec<String>>();
let mut modmap = empty_modmap.clone();
for modifier in mods_vector {
modmap.insert(Key::from_str(&modifier).unwrap(), 1);
}
modifiers.axis.insert(modmap, key.clone());
}
for (mods, key) in combinations.keys_sh.iter() {
let mods_vector = mods.split("-").map(str::to_string).collect::<Vec<String>>();
let mut modmap = empty_modmap.clone();
for modifier in mods_vector {
modmap.insert(Key::from_str(&modifier).unwrap(), 1);
}
modifiers.keys_sh.insert(modmap, key.clone());
}
for (mods, key) in combinations.axis_sh.iter() {
let mods_vector = mods.split("-").map(str::to_string).collect::<Vec<String>>();
let mut modmap = empty_modmap.clone();
for modifier in mods_vector {
modmap.insert(Key::from_str(&modifier).unwrap(), 1);
}
modifiers.axis_sh.insert(modmap, key.clone());
}
modifiers
}
fn merge_axis_bindings(mut bindings: Bindings) -> Bindings {
let mut pad_x: Vec<Key> = bindings.axis.get("BTN_DPAD_LEFT") let mut pad_x: Vec<Key> = bindings.axis.get("BTN_DPAD_LEFT")
.unwrap_or(&Vec::new()).clone(); .unwrap_or(&Vec::new()).clone();
pad_x.extend(bindings.axis.get("BTN_DPAD_RIGHT") pad_x.extend(bindings.axis.get("BTN_DPAD_RIGHT")
@ -128,8 +212,8 @@ impl Config {
.unwrap_or(&Vec::new()).clone(); .unwrap_or(&Vec::new()).clone();
pad_y.extend(bindings.axis.get("BTN_DPAD_DOWN") pad_y.extend(bindings.axis.get("BTN_DPAD_DOWN")
.unwrap_or(&Vec::new())); .unwrap_or(&Vec::new()));
bindings.axis.insert("NONE_X".to_string(), pad_x); bindings.axis.insert("BTN_DPAD_X".to_string(), pad_x);
bindings.axis.insert("NONE_Y".to_string(), pad_y); bindings.axis.insert("BTN_DPAD_y".to_string(), pad_y);
let mut lstick_x: Vec<Key> = bindings.axis.get("LSTICK_LEFT") let mut lstick_x: Vec<Key> = bindings.axis.get("LSTICK_LEFT")
.unwrap_or(&Vec::new()).clone(); .unwrap_or(&Vec::new()).clone();
@ -152,14 +236,5 @@ impl Config {
.unwrap_or(&Vec::new())); .unwrap_or(&Vec::new()));
bindings.axis.insert("RSTICK_X".to_string(), rstick_x); bindings.axis.insert("RSTICK_X".to_string(), rstick_x);
bindings.axis.insert("RSTICK_Y".to_string(), rstick_y); bindings.axis.insert("RSTICK_Y".to_string(), rstick_y);
bindings
Self {
name: file_name,
remap,
bindings,
combinations,
modifiers,
settings,
}
}
} }

View file

@ -1,4 +1,4 @@
use std::{collections::{HashMap, BTreeMap}, sync::Arc, option::Option}; use std::{collections::{HashMap, BTreeMap}, sync::Arc, option::Option, process::Command};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tokio_stream::StreamExt; use tokio_stream::StreamExt;
use evdev::{EventStream, Key, RelativeAxisType, AbsoluteAxisType, EventType, InputEvent}; use evdev::{EventStream, Key, RelativeAxisType, AbsoluteAxisType, EventType, InputEvent};
@ -257,9 +257,16 @@ impl EventReader {
self.emit_event_without_modifiers(event_list, &modifiers, event.value()).await; self.emit_event_without_modifiers(event_list, &modifiers, event.value()).await;
return return
} }
} else if let Some(command_hashmap) = path.modifiers.keys_sh.get(&modifiers) {
if let Some(command_list) = command_hashmap.get(&Key(event.code())) {
spawn_subprocess(command_list).await;
return
}
} }
if let Some(event_list) = path.bindings.keys.get(&Key(event.code())) { if let Some(event_list) = path.bindings.keys.get(&Key(event.code())) {
self.emit_event(event_list, event.value()).await; self.emit_event(event_list, event.value()).await;
} else if let Some(command_list) = path.bindings.keys_sh.get(&Key(event.code())) {
spawn_subprocess(command_list).await;
} else { } else {
self.emit_default_event(event).await; self.emit_default_event(event).await;
} }
@ -276,13 +283,19 @@ impl EventReader {
} }
return return
} }
} else if let Some(command_hashmap) = path.modifiers.axis_sh.get(&modifiers) {
if let Some(command_list) = command_hashmap.get(event_string) {
spawn_subprocess(command_list).await;
return
}
} }
if let Some(event_list) = path.bindings.axis.get(event_string) { if let Some(event_list) = path.bindings.axis.get(event_string) {
println!("{:?}", event_list);
self.emit_event(event_list, event.value()).await; self.emit_event(event_list, event.value()).await;
if send_zero { if send_zero {
self.emit_event_without_modifiers(event_list, &modifiers, 0).await; self.emit_event_without_modifiers(event_list, &modifiers, 0).await;
} }
} else if let Some(command_list) = path.bindings.axis_sh.get(event_string) {
spawn_subprocess(command_list).await;
} else { } else {
self.emit_default_event(event).await; self.emit_default_event(event).await;
} }
@ -339,7 +352,7 @@ impl EventReader {
virt_dev.keys.emit(&[virtual_event]).unwrap(); virt_dev.keys.emit(&[virtual_event]).unwrap();
} }
} }
async fn get_axis_value(&self, event: &InputEvent, deadzone: &i32) -> i32 { async fn get_axis_value(&self, event: &InputEvent, deadzone: &i32) -> i32 {
let distance_from_center: i32 = match self.settings.axis_16_bit { let distance_from_center: i32 = match self.settings.axis_16_bit {
false => (event.value() as i32 - 128) * 200, false => (event.value() as i32 - 128) * 200,
@ -438,3 +451,12 @@ impl EventReader {
} }
} }
async fn spawn_subprocess(command_list: &Vec<String>) {
for command in command_list {
Command::new("sh")
.arg("-c")
.arg(command)
.spawn()
.expect("Failed to run command.");
}
}