Added support for custom key modifiers

This commit is contained in:
cyber-sushi 2024-04-18 13:41:06 +02:00
parent a6dfe9dfd4
commit f5452cac5d
3 changed files with 180 additions and 128 deletions

View file

@ -1,4 +1,4 @@
use std::collections::{HashMap, BTreeMap}; use std::collections::HashMap;
use std::str::FromStr; use std::str::FromStr;
use evdev::Key; use evdev::Key;
use serde; use serde;
@ -14,21 +14,12 @@ pub struct Bindings {
#[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<Key, HashMap<Vec<Key>, Vec<Key>>>,
pub axis: HashMap<String, HashMap<String, Vec<Key>>>, pub axis: HashMap<String, HashMap<Vec<Key>, Vec<Key>>>,
pub keys_sh: HashMap<String, HashMap<Key, Vec<String>>>, pub keys_sh: HashMap<Key, HashMap<Vec<Key>, Vec<String>>>,
pub axis_sh: HashMap<String, HashMap<String, Vec<String>>>, pub axis_sh: HashMap<String, HashMap<Vec<Key>, Vec<String>>>,
} }
#[derive(Default, Debug, Clone)]
pub struct Modifiers {
pub keys: HashMap<BTreeMap<Key, i32>, HashMap<Key, 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 RawConfig { pub struct RawConfig {
#[serde(default)] #[serde(default)]
@ -38,6 +29,13 @@ pub struct RawConfig {
pub settings: HashMap<String, String>, pub settings: HashMap<String, String>,
} }
#[derive(Debug, Clone)]
pub struct MappedModifiers {
pub default: Vec<Key>,
pub custom: Vec<Key>,
pub all: Vec<Key>,
}
impl RawConfig { impl RawConfig {
fn new_from_file(file: &str) -> Self { fn new_from_file(file: &str) -> Self {
println!("Parsing config file:\n{:?}\n", file.rsplit_once("/").unwrap().1); println!("Parsing config file:\n{:?}\n", file.rsplit_once("/").unwrap().1);
@ -59,32 +57,55 @@ impl RawConfig {
pub struct Config { pub struct Config {
pub name: String, pub name: String,
pub bindings: Bindings, pub bindings: Bindings,
pub modifiers: Modifiers, pub combinations: Combinations,
pub settings: HashMap<String, String>, pub settings: HashMap<String, String>,
pub mapped_modifiers: MappedModifiers,
} }
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 {
let raw_config = RawConfig::new_from_file(file); let raw_config = RawConfig::new_from_file(file);
let (bindings, combinations, settings) = parse_raw_config(raw_config); let (bindings, combinations, settings, mapped_modifiers) = parse_raw_config(raw_config);
let bindings: Bindings = merge_axis_bindings(bindings); let bindings: Bindings = merge_axis_bindings(bindings);
let modifiers: Modifiers = parse_modifiers(combinations);
Self { Self {
name: file_name, name: file_name,
bindings, bindings,
modifiers, combinations,
settings, settings,
mapped_modifiers,
} }
} }
} }
fn parse_raw_config(raw_config: RawConfig) -> (Bindings, Combinations, HashMap<String, String>) { fn parse_raw_config(raw_config: RawConfig) -> (Bindings, Combinations, HashMap<String, String>, MappedModifiers) {
let remap: HashMap<String, Vec<Key>> = raw_config.remap; let remap: HashMap<String, Vec<Key>> = raw_config.remap;
let commands: HashMap<String, Vec<String>> = raw_config.commands; let commands: HashMap<String, Vec<String>> = raw_config.commands;
let settings: HashMap<String, String> = raw_config.settings; let settings: HashMap<String, String> = raw_config.settings;
let mut bindings: Bindings = Default::default(); let mut bindings: Bindings = Default::default();
let mut combinations: Combinations = Default::default(); let mut combinations: Combinations = Default::default();
let default_modifiers = vec![
Key::KEY_LEFTSHIFT,
Key::KEY_LEFTCTRL,
Key::KEY_LEFTALT,
Key::KEY_RIGHTSHIFT,
Key::KEY_RIGHTCTRL,
Key::KEY_RIGHTALT,
Key::KEY_LEFTMETA,
];
let mut mapped_modifiers = MappedModifiers {
default: default_modifiers.clone(),
custom: Vec::new(),
all: Vec::new(),
};
let custom_modifiers: Vec<Key> = match settings.get(&"CUSTOM_MODIFIERS".to_string()) {
Some(modifiers) => {
modifiers.split("-").collect::<Vec<&str>>().iter()
.map(|key_str| Key::from_str(key_str).expect("Invalid KEY value used as modifier in CUSTOM_MODIFIERS.")).collect()
},
None => Vec::new(),
};
mapped_modifiers.custom.extend(custom_modifiers);
let abs = [ let abs = [
"DPAD_UP", "DPAD_UP",
@ -108,24 +129,32 @@ fn parse_raw_config(raw_config: RawConfig) -> (Bindings, Combinations, HashMap<S
for (input, output) in remap.clone().into_iter() { for (input, output) in remap.clone().into_iter() {
if input.contains("-") { if input.contains("-") {
let (mods, key) = input.rsplit_once("-").unwrap(); let (mods, key) = input.rsplit_once("-").unwrap();
let mut modifiers: Vec<Key> = mods.split("-").collect::<Vec<&str>>().iter().map(|key_str| Key::from_str(key_str).expect("Invalid KEY value used as modifier.")).collect();
modifiers.sort();
modifiers.dedup();
for modifier in &modifiers {
if !mapped_modifiers.default.contains(&modifier) {
mapped_modifiers.custom.push(modifier.clone());
}
}
if abs.contains(&key) { if abs.contains(&key) {
if !combinations.axis.contains_key(&mods.to_string()) { if !combinations.axis.contains_key(&key.to_string()) {
combinations.axis.insert(mods.to_string(), HashMap::from([(key.to_string(), output)])); combinations.axis.insert(key.to_string(), HashMap::from([(modifiers , output)]));
} else { } else {
combinations.axis.get_mut(mods).unwrap().insert(key.to_string(), output); combinations.axis.get_mut(key).unwrap().insert(modifiers, output);
} }
} else { } else {
if !combinations.keys.contains_key(&mods.to_string()) { if !combinations.keys.contains_key(&Key::from_str(key).unwrap()) {
combinations.keys.insert(mods.to_string(), HashMap::from([(Key::from_str(key).expect("Invalid KEY value."), output)])); combinations.keys.insert(Key::from_str(key).unwrap(), HashMap::from([(modifiers, output)]));
} else { } else {
combinations.keys.get_mut(mods).unwrap().insert(Key::from_str(key).expect("Invalid KEY value."), output); combinations.keys.get_mut(&Key::from_str(key).unwrap()).unwrap().insert(modifiers, output);
} }
} }
} else { } else {
if abs.contains(&input.as_str()) { if abs.contains(&input.as_str()) {
bindings.axis.insert(input, output); bindings.axis.insert(input, output);
} else { } else {
bindings.keys.insert(Key::from_str(input.as_str()).expect("Invalid KEY value."), output); bindings.keys.insert(Key::from_str(input.as_str()).expect("Invalid KEY value used for rebinding."), output);
} }
} }
} }
@ -133,74 +162,44 @@ fn parse_raw_config(raw_config: RawConfig) -> (Bindings, Combinations, HashMap<S
for (input, output) in commands.clone().into_iter() { for (input, output) in commands.clone().into_iter() {
if input.contains("-") { if input.contains("-") {
let (mods, key) = input.rsplit_once("-").unwrap(); let (mods, key) = input.rsplit_once("-").unwrap();
let mut modifiers: Vec<Key> = mods.split("-").collect::<Vec<&str>>().iter().map(|key_str| Key::from_str(key_str).expect("Invalid KEY value used as modifier.")).collect();
modifiers.sort();
modifiers.dedup();
for modifier in &modifiers {
if !mapped_modifiers.default.contains(&modifier) {
mapped_modifiers.custom.push(modifier.clone());
}
}
if abs.contains(&key) { if abs.contains(&key) {
if !combinations.axis_sh.contains_key(&mods.to_string()) { if !combinations.axis_sh.contains_key(&key.to_string()) {
combinations.axis_sh.insert(mods.to_string(), HashMap::from([(key.to_string(), output)])); combinations.axis_sh.insert(key.to_string(), HashMap::from([(modifiers, output)]));
} else { } else {
combinations.axis_sh.get_mut(mods).unwrap().insert(key.to_string(), output); combinations.axis_sh.get_mut(key).unwrap().insert(modifiers, output);
} }
} else { } else {
if !combinations.keys_sh.contains_key(&mods.to_string()) { if !combinations.keys_sh.contains_key(&Key::from_str(key).unwrap()) {
combinations.keys_sh.insert(mods.to_string(), HashMap::from([(Key::from_str(key).expect("Invalid KEY value."), output)])); combinations.keys_sh.insert(Key::from_str(key).unwrap(), HashMap::from([(modifiers, output)]));
} else { } else {
combinations.keys_sh.get_mut(mods).unwrap().insert(Key::from_str(key).expect("Invalid KEY value."), output); combinations.keys_sh.get_mut(&Key::from_str(key).unwrap()).unwrap().insert(modifiers, output);
} }
} }
} else { } else {
if abs.contains(&input.as_str()) { if abs.contains(&input.as_str()) {
bindings.axis_sh.insert(input, output); bindings.axis_sh.insert(input, output);
} else { } else {
bindings.keys_sh.insert(Key::from_str(input.as_str()).expect("Invalid KEY value."), output); bindings.keys_sh.insert(Key::from_str(input.as_str()).expect("Invalid KEY value used for rebinding."), output);
} }
} }
} }
(bindings, combinations, settings)
}
fn parse_modifiers(combinations: Combinations) -> Modifiers { mapped_modifiers.custom.sort();
let empty_modmap = BTreeMap::from ([ mapped_modifiers.custom.dedup();
(Key::KEY_LEFTSHIFT, 0), mapped_modifiers.all.extend(mapped_modifiers.default.clone());
(Key::KEY_LEFTCTRL, 0), mapped_modifiers.all.extend(mapped_modifiers.custom.clone());
(Key::KEY_LEFTALT, 0), mapped_modifiers.all.sort();
(Key::KEY_RIGHTSHIFT, 0), mapped_modifiers.all.dedup();
(Key::KEY_RIGHTCTRL, 0),
(Key::KEY_RIGHTALT, 0), (bindings, combinations, settings, mapped_modifiers)
(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 { fn merge_axis_bindings(mut bindings: Bindings) -> Bindings {
@ -238,3 +237,5 @@ fn merge_axis_bindings(mut bindings: Bindings) -> Bindings {
bindings.axis.insert("RSTICK_Y".to_string(), rstick_y); bindings.axis.insert("RSTICK_Y".to_string(), rstick_y);
bindings bindings
} }

View file

@ -1,4 +1,4 @@
use std::{collections::{HashMap, BTreeMap}, sync::Arc, option::Option, process::Command}; use std::{collections::HashMap, 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};
@ -25,7 +25,8 @@ pub struct EventReader {
virt_dev: Arc<Mutex<VirtualDevices>>, virt_dev: Arc<Mutex<VirtualDevices>>,
lstick_position: Arc<Mutex<Vec<i32>>>, lstick_position: Arc<Mutex<Vec<i32>>>,
rstick_position: Arc<Mutex<Vec<i32>>>, rstick_position: Arc<Mutex<Vec<i32>>>,
modifiers: Arc<Mutex<BTreeMap<Key, i32>>>, modifiers: Arc<Mutex<Vec<Key>>>,
modifier_was_activated: Arc<Mutex<bool>>,
device_is_connected: Arc<Mutex<bool>>, device_is_connected: Arc<Mutex<bool>>,
current_desktop: Option<String>, current_desktop: Option<String>,
settings: Settings, settings: Settings,
@ -35,7 +36,8 @@ impl EventReader {
pub fn new( pub fn new(
config: HashMap<String, Config>, config: HashMap<String, Config>,
stream: Arc<Mutex<EventStream>>, stream: Arc<Mutex<EventStream>>,
modifiers: Arc<Mutex<BTreeMap<Key, i32>>>, modifiers: Arc<Mutex<Vec<Key>>>,
modifier_was_activated: Arc<Mutex<bool>>,
current_desktop: Option<String>, current_desktop: Option<String>,
) -> Self { ) -> Self {
let mut position_vector: Vec<i32> = Vec::new(); let mut position_vector: Vec<i32> = Vec::new();
@ -83,6 +85,7 @@ impl EventReader {
lstick_position, lstick_position,
rstick_position, rstick_position,
modifiers, modifiers,
modifier_was_activated,
device_is_connected, device_is_connected,
current_desktop, current_desktop,
settings, settings,
@ -252,13 +255,13 @@ impl EventReader {
async fn convert_key_events(&self, event: InputEvent) { async fn convert_key_events(&self, event: InputEvent) {
let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap(); let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap();
let modifiers = self.modifiers.lock().await.clone(); let modifiers = self.modifiers.lock().await.clone();
if let Some(event_hashmap) = path.modifiers.keys.get(&modifiers) { if let Some(event_hashmap) = path.combinations.keys.get(&Key(event.code())) {
if let Some(event_list) = event_hashmap.get(&Key(event.code())) { if let Some(event_list) = event_hashmap.get(&modifiers) {
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) { } else if let Some(command_hashmap) = path.combinations.keys_sh.get(&Key(event.code())) {
if let Some(command_list) = command_hashmap.get(&Key(event.code())) { if let Some(command_list) = command_hashmap.get(&modifiers) {
spawn_subprocess(command_list).await; spawn_subprocess(command_list).await;
return return
} }
@ -275,16 +278,16 @@ impl EventReader {
async fn convert_axis_events(&self, event: InputEvent, event_string: &String, send_zero: bool) { async fn convert_axis_events(&self, event: InputEvent, event_string: &String, send_zero: bool) {
let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap(); let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap();
let modifiers = self.modifiers.lock().await.clone(); let modifiers = self.modifiers.lock().await.clone();
if let Some(event_hashmap) = path.modifiers.axis.get(&modifiers) { if let Some(event_hashmap) = path.combinations.axis.get(event_string) {
if let Some(event_list) = event_hashmap.get(event_string) { if let Some(event_list) = event_hashmap.get(&modifiers) {
self.emit_event_without_modifiers(event_list, &modifiers, event.value()).await; self.emit_event_without_modifiers(event_list, &modifiers, 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;
} }
return return
} }
} else if let Some(command_hashmap) = path.modifiers.axis_sh.get(&modifiers) { } else if let Some(command_hashmap) = path.combinations.axis_sh.get(event_string) {
if let Some(command_list) = command_hashmap.get(event_string) { if let Some(command_list) = command_hashmap.get(&modifiers) {
spawn_subprocess(command_list).await; spawn_subprocess(command_list).await;
return return
} }
@ -302,8 +305,10 @@ impl EventReader {
} }
async fn emit_event(&self, event_list: &Vec<Key>, value: i32) { async fn emit_event(&self, event_list: &Vec<Key>, value: i32) {
let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap();
let mut virt_dev = self.virt_dev.lock().await; let mut virt_dev = self.virt_dev.lock().await;
let modifiers = self.modifiers.lock().await.clone(); let modifiers = self.modifiers.lock().await.clone();
let mut modifier_was_activated = self.modifier_was_activated.lock().await;
let released_keys: Vec<Key> = self.released_keys(&modifiers).await; let released_keys: Vec<Key> = self.released_keys(&modifiers).await;
for key in released_keys { for key in released_keys {
self.toggle_modifiers(key, 0).await; self.toggle_modifiers(key, 0).await;
@ -312,13 +317,28 @@ impl EventReader {
} }
for key in event_list { for key in event_list {
self.toggle_modifiers(*key, value).await; self.toggle_modifiers(*key, value).await;
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), value); if path.mapped_modifiers.custom.contains(&key) {
virt_dev.keys.emit(&[virtual_event]).unwrap(); if value == 0 && !*modifier_was_activated {
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 1);
virt_dev.keys.emit(&[virtual_event]).unwrap();
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 0);
virt_dev.keys.emit(&[virtual_event]).unwrap();
*modifier_was_activated = true;
} else if value == 1 {
*modifier_was_activated = false;
}
} else {
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), value);
virt_dev.keys.emit(&[virtual_event]).unwrap();
*modifier_was_activated = true;
}
} }
} }
async fn emit_default_event(&self, event: InputEvent) { async fn emit_default_event(&self, event: InputEvent) {
let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap();
let mut virt_dev = self.virt_dev.lock().await; let mut virt_dev = self.virt_dev.lock().await;
let mut modifier_was_activated = self.modifier_was_activated.lock().await;
match event.event_type() { match event.event_type() {
EventType::KEY => { EventType::KEY => {
let modifiers = self.modifiers.lock().await.clone(); let modifiers = self.modifiers.lock().await.clone();
@ -329,27 +349,53 @@ impl EventReader {
virt_dev.keys.emit(&[virtual_event]).unwrap() virt_dev.keys.emit(&[virtual_event]).unwrap()
} }
self.toggle_modifiers(Key(event.code()), event.value()).await; self.toggle_modifiers(Key(event.code()), event.value()).await;
virt_dev.keys.emit(&[event]).unwrap(); if path.mapped_modifiers.custom.contains(&Key(event.code())) {
if event.value() == 0 && !*modifier_was_activated {
let virtual_event: InputEvent = InputEvent::new_now(event.event_type(), event.code(), 1);
virt_dev.keys.emit(&[virtual_event]).unwrap();
let virtual_event: InputEvent = InputEvent::new_now(event.event_type(), event.code(), 0);
virt_dev.keys.emit(&[virtual_event]).unwrap();
*modifier_was_activated = true;
} else if event.value() == 1 {
*modifier_was_activated = false;
}
} else {
virt_dev.keys.emit(&[event]).unwrap();
*modifier_was_activated = true;
}
},
EventType::RELATIVE => {
virt_dev.axis.emit(&[event]).unwrap();
*modifier_was_activated = true;
}, },
EventType::RELATIVE => virt_dev.axis.emit(&[event]).unwrap(),
_ => {} _ => {}
} }
} }
async fn emit_event_without_modifiers(&self, event_list: &Vec<Key>, modifiers: &BTreeMap<Key, i32>, value: i32) { async fn emit_event_without_modifiers(&self, event_list: &Vec<Key>, modifiers: &Vec<Key>, value: i32) {
let modifiers_list = modifiers.iter() let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap();
.filter(|(_key, value)| value == &&1)
.collect::<HashMap<&Key, &i32>>()
.into_keys().copied()
.collect::<Vec<Key>>();
let mut virt_dev = self.virt_dev.lock().await; let mut virt_dev = self.virt_dev.lock().await;
for key in modifiers_list { let mut modifier_was_activated = self.modifier_was_activated.lock().await;
for key in modifiers {
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 0); let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 0);
virt_dev.keys.emit(&[virtual_event]).unwrap(); virt_dev.keys.emit(&[virtual_event]).unwrap();
} }
for key in event_list { for key in event_list {
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), value); if path.mapped_modifiers.custom.contains(&key) {
virt_dev.keys.emit(&[virtual_event]).unwrap(); if value == 0 && !*modifier_was_activated {
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 1);
virt_dev.keys.emit(&[virtual_event]).unwrap();
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 0);
virt_dev.keys.emit(&[virtual_event]).unwrap();
*modifier_was_activated = true;
} else if value == 1 {
*modifier_was_activated = false;
}
} else {
let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), value);
virt_dev.keys.emit(&[virtual_event]).unwrap();
*modifier_was_activated = true;
}
} }
} }
@ -366,20 +412,33 @@ impl EventReader {
} }
async fn toggle_modifiers(&self, key: Key, value: i32) { async fn toggle_modifiers(&self, key: Key, value: i32) {
let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap();
let mut modifiers = self.modifiers.lock().await; let mut modifiers = self.modifiers.lock().await;
if modifiers.contains_key(&key) && vec![0, 1].contains(&value) { if path.mapped_modifiers.all.contains(&key) {
modifiers.insert(key, value).unwrap(); match value {
1 => {
modifiers.push(key);
modifiers.sort();
modifiers.dedup();
},
0 => modifiers.retain(|&x| x != key),
_ => {},
}
} }
} }
async fn released_keys(&self, modifiers: &BTreeMap<Key, i32>) -> Vec<Key> { async fn released_keys(&self, modifiers: &Vec<Key>) -> Vec<Key> {
let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap(); let path = self.config.get(&get_active_window(&self.current_desktop, &self.config).await).unwrap();
let mut released_keys: Vec<Key> = Vec::new(); let mut released_keys: Vec<Key> = Vec::new();
if let Some(event_hashmap) = path.modifiers.keys.get(&modifiers) { for (_key, hashmap) in path.combinations.keys.iter() {
event_hashmap.iter().for_each(|(_modifiers, event_list)| released_keys.extend(event_list)); if let Some(event_list) = hashmap.get(modifiers) {
released_keys.extend(event_list);
}
} }
if let Some(event_hashmap) = path.modifiers.axis.get(&modifiers) { for (_key, hashmap) in path.combinations.axis.iter() {
event_hashmap.iter().for_each(|(_modifiers, event_list)| released_keys.extend(event_list)); if let Some(event_list) = hashmap.get(modifiers) {
released_keys.extend(event_list);
}
} }
released_keys released_keys
} }
@ -460,3 +519,6 @@ async fn spawn_subprocess(command_list: &Vec<String>) {
.expect("Failed to run command."); .expect("Failed to run command.");
} }
} }

View file

@ -1,4 +1,4 @@
use std::{collections::{HashMap, BTreeMap}, sync::Arc, path::Path, process::Command, env}; use std::{collections::HashMap, sync::Arc, path::Path, process::Command, env};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tokio_stream::StreamExt; use tokio_stream::StreamExt;
@ -16,7 +16,7 @@ pub async fn start_monitoring_udev(config_files: Vec<Config>, mut tasks: Vec<Joi
).unwrap(); ).unwrap();
while let Some(Ok(event)) = monitor.next().await { while let Some(Ok(event)) = monitor.next().await {
if is_mapped(&event.device(), &config_files) { if is_mapped(&event.device(), &config_files) {
println!("---------------------\nReinitializing...\n"); println!("---------------------\n\nReinitializing...\n");
for task in &tasks { for task in &tasks {
task.abort(); task.abort();
} }
@ -27,19 +27,8 @@ pub async fn start_monitoring_udev(config_files: Vec<Config>, mut tasks: Vec<Joi
} }
pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>) { pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>) {
let modifiers: Arc<Mutex<BTreeMap<Key, i32>>> = Arc::new ( let modifiers: Arc<Mutex<Vec<Key>>> = Arc::new(Mutex::new(Default::default()));
Mutex::new ( let modifier_was_activated: Arc<Mutex<bool>> = Arc::new(Mutex::new(true));
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 current_desktop: Option<String> = match (env::var("XDG_SESSION_TYPE"), env::var("XDG_CURRENT_DESKTOP")) { let current_desktop: Option<String> = match (env::var("XDG_SESSION_TYPE"), env::var("XDG_CURRENT_DESKTOP")) {
(Ok(session), Ok(desktop)) if session == "wayland".to_string() && vec!["Hyprland".to_string(), "sway".to_string()].contains(&desktop) => { (Ok(session), Ok(desktop)) if session == "wayland".to_string() && vec!["Hyprland".to_string(), "sway".to_string()].contains(&desktop) => {
println!(">> Running on {}, active window detection enabled.\n", desktop); println!(">> Running on {}, active window detection enabled.\n", desktop);
@ -68,7 +57,7 @@ pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>)
}; };
let user_has_access = match Command::new("groups").output() { let user_has_access = match Command::new("groups").output() {
Ok(groups) if std::str::from_utf8(&groups.stdout.as_slice()).unwrap().contains("input") => { Ok(groups) if std::str::from_utf8(&groups.stdout.as_slice()).unwrap().contains("input") => {
println!("Running with evdev permissions.\nScanning for event devices with a matching config file...\n"); //todo: make the config dir customizable through env variable println!("Running with evdev permissions.\nScanning for event devices with a matching config file...\n");
true true
}, },
Ok(groups) if std::str::from_utf8(&groups.stdout.as_slice()).unwrap().contains("root") => { Ok(groups) if std::str::from_utf8(&groups.stdout.as_slice()).unwrap().contains("root") => {
@ -105,7 +94,7 @@ pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>)
let event_device = device.0.as_path().to_str().unwrap().to_string(); let event_device = device.0.as_path().to_str().unwrap().to_string();
if !config_map.is_empty() { if !config_map.is_empty() {
let stream = Arc::new(Mutex::new(get_event_stream(Path::new(&event_device), config_map.clone()))); let stream = Arc::new(Mutex::new(get_event_stream(Path::new(&event_device), config_map.clone())));
let reader = EventReader::new(config_map.clone(), stream, modifiers.clone(), current_desktop.clone()); let reader = EventReader::new(config_map.clone(), stream, modifiers.clone(), modifier_was_activated.clone(), current_desktop.clone());
tasks.push(tokio::spawn(start_reader(reader))); tasks.push(tokio::spawn(start_reader(reader)));
devices_found += 1 devices_found += 1
} }