From 77d8a5d6ade4a9b10235a925232aad53b8dbf024 Mon Sep 17 00:00:00 2001 From: cyber-sushi Date: Tue, 24 Dec 2024 18:32:49 +0100 Subject: [PATCH] Implemented cursor and scroll movements through keys --- src/config.rs | 123 +++++++++++++++++++++++++++++ src/event_reader.rs | 184 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 305 insertions(+), 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index a6a25b7..806d2c8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -60,6 +60,47 @@ impl FromStr for Axis { } } +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +pub enum Relative { + Cursor(Cursor), + Scroll(Scroll), +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +pub enum Cursor { + CURSOR_UP, + CURSOR_DOWN, + CURSOR_LEFT, + CURSOR_RIGHT, +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +pub enum Scroll { + SCROLL_UP, + SCROLL_DOWN, + SCROLL_LEFT, + SCROLL_RIGHT, +} + +impl FromStr for Relative { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "CURSOR_UP" => Ok(Relative::Cursor(Cursor::CURSOR_UP)), + "CURSOR_DOWN" => Ok(Relative::Cursor(Cursor::CURSOR_DOWN)), + "CURSOR_LEFT" => Ok(Relative::Cursor(Cursor::CURSOR_LEFT)), + "CURSOR_RIGHT" => Ok(Relative::Cursor(Cursor::CURSOR_RIGHT)), + "SCROLL_UP" => Ok(Relative::Scroll(Scroll::SCROLL_UP)), + "SCROLL_DOWN" => Ok(Relative::Scroll(Scroll::SCROLL_DOWN)), + "SCROLL_LEFT" => Ok(Relative::Scroll(Scroll::SCROLL_LEFT)), + "SCROLL_RIGHT" => Ok(Relative::Scroll(Scroll::SCROLL_RIGHT)), + _ => Err(s.to_string()), + } + } +} + #[derive(Debug, PartialEq, Eq, Default, Clone)] pub struct Associations { pub client: Client, @@ -70,6 +111,7 @@ pub struct Associations { pub struct Bindings { pub remap: HashMap, Vec>>, pub commands: HashMap, Vec>>, + pub movements: HashMap, Relative>>, } #[derive(Default, Debug, Clone)] @@ -86,6 +128,8 @@ pub struct RawConfig { #[serde(default)] pub commands: HashMap>, #[serde(default)] + pub movements: HashMap, + #[serde(default)] pub settings: HashMap, } @@ -100,10 +144,12 @@ impl RawConfig { toml::from_str(&file_content).expect("Couldn't parse config file."); let remap = raw_config.remap; let commands = raw_config.commands; + let movements = raw_config.movements; let settings = raw_config.settings; Self { remap, commands, + movements, settings, } } @@ -147,6 +193,7 @@ impl Config { fn parse_raw_config(raw_config: RawConfig) -> (Bindings, HashMap, MappedModifiers) { let remap: HashMap> = raw_config.remap; let commands: HashMap> = raw_config.commands; + let movements: HashMap = raw_config.movements; let settings: HashMap = raw_config.settings; let mut bindings: Bindings = Default::default(); let default_modifiers = vec![ @@ -322,6 +369,82 @@ fn parse_raw_config(raw_config: RawConfig) -> (Bindings, HashMap } } + for (input, output) in movements.clone() { + if let Some((mods, event)) = input.rsplit_once("-") { + let str_modifiers = mods.split("-").collect::>(); + let mut modifiers: Vec = Vec::new(); + for event in str_modifiers.clone() { + if let Ok(axis) = Axis::from_str(event) { + modifiers.push(Event::Axis(axis)); + } else if let Ok(key) = Key::from_str(event) { + modifiers.push(Event::Key(key)); + } + } + modifiers.sort(); + modifiers.dedup(); + for modifier in &modifiers { + if !mapped_modifiers.default.contains(&modifier) { + mapped_modifiers.custom.push(modifier.clone()); + } + } + if str_modifiers[0] == "" { + modifiers.push(Event::Hold); + } + if let Ok(event) = Axis::from_str(event) { + if !bindings.movements.contains_key(&Event::Axis(event)) { + bindings + .movements + .insert(Event::Axis(event), HashMap::from([(modifiers, Relative::from_str(output.as_str()).expect("Invalid movement in [movements]."))])); + } else { + bindings + .movements + .get_mut(&Event::Axis(event)) + .unwrap() + .insert(modifiers, Relative::from_str(output.as_str()).expect("Invalid movement in [movements].")); + } + } else if let Ok(event) = Key::from_str(event) { + if !bindings.movements.contains_key(&Event::Key(event)) { + bindings + .movements + .insert(Event::Key(event), HashMap::from([(modifiers, Relative::from_str(output.as_str()).expect("Invalid movement in [movements]."))])); + } else { + bindings + .movements + .get_mut(&Event::Key(event)) + .unwrap() + .insert(modifiers, Relative::from_str(output.as_str()).expect("Invalid movement in [movements].")); + } + } + } else { + let modifiers: Vec = Vec::new(); + if let Ok(event) = Axis::from_str(input.as_str()) { + if !bindings.movements.contains_key(&Event::Axis(event)) { + bindings + .movements + .insert(Event::Axis(event), HashMap::from([(modifiers, Relative::from_str(output.as_str()).expect("Invalid movement in [movements]."))])); + } else { + bindings + .movements + .get_mut(&Event::Axis(event)) + .unwrap() + .insert(modifiers, Relative::from_str(output.as_str()).expect("Invalid movement in [movements].")); + } + } else if let Ok(event) = Key::from_str(input.as_str()) { + if !bindings.movements.contains_key(&Event::Key(event)) { + bindings + .movements + .insert(Event::Key(event), HashMap::from([(modifiers, Relative::from_str(output.as_str()).expect("Invalid movement in [movements]."))])); + } else { + bindings + .movements + .get_mut(&Event::Key(event)) + .unwrap() + .insert(modifiers, Relative::from_str(output.as_str()).expect("Invalid movement in [movements].")); + } + } + } + } + mapped_modifiers.custom.sort(); mapped_modifiers.custom.dedup(); mapped_modifiers diff --git a/src/event_reader.rs b/src/event_reader.rs index b343f78..04b14e0 100644 --- a/src/event_reader.rs +++ b/src/event_reader.rs @@ -1,5 +1,5 @@ use crate::active_client::*; -use crate::config::{parse_modifiers, Associations, Axis, Event}; +use crate::config::{parse_modifiers, Associations, Axis, Event, Relative, Cursor, Scroll}; use crate::udev_monitor::Environment; use crate::virtual_devices::VirtualDevices; use crate::Config; @@ -23,6 +23,11 @@ struct Stick { activation_modifiers: Vec, } +struct Movement { + speed: i32, + acceleration: f32, +} + struct Settings { lstick: Stick, rstick: Stick, @@ -30,6 +35,8 @@ struct Settings { invert_scroll_axis: bool, axis_16_bit: bool, stadia: bool, + cursor: Movement, + scroll: Movement, chain_only: bool, layout_switcher: Key, notify_layout_switch: bool, @@ -41,6 +48,8 @@ pub struct EventReader { virt_dev: Arc>, lstick_position: Arc>>, rstick_position: Arc>>, + cursor_movement: Arc>, + scroll_movement: Arc>, modifiers: Arc>>, modifier_was_activated: Arc>, device_is_connected: Arc>, @@ -65,6 +74,8 @@ impl EventReader { } let lstick_position = Arc::new(Mutex::new(position_vector.clone())); let rstick_position = Arc::new(Mutex::new(position_vector.clone())); + let cursor_movement = Arc::new(Mutex::new((0, 0))); + let scroll_movement = Arc::new(Mutex::new((0, 0))); let device_is_connected: Arc> = Arc::new(Mutex::new(true)); let active_layout: Arc> = Arc::new(Mutex::new(0)); let current_config: Arc> = Arc::new(Mutex::new( @@ -206,6 +217,56 @@ impl EventReader { .parse() .expect("INVERT_SCROLL_AXIS can only be true or false."); + let cursor_speed: i32 = config + .iter() + .find(|&x| x.associations == Associations::default()) + .unwrap() + .settings + .get("CURSOR_SPEED") + .unwrap_or(&"0".to_string()) + .parse() + .expect("Invalid value for CURSOR_SPEED, please use an integer value."); + + let cursor_acceleration: f32 = config + .iter() + .find(|&x| x.associations == Associations::default()) + .unwrap() + .settings + .get("CURSOR_ACCEL") + .unwrap_or(&"0".to_string()) + .parse() + .expect("Invalid value for CURSOR_ACCEL, please use an float value between 0 and 1."); + + let scroll_speed: i32 = config + .iter() + .find(|&x| x.associations == Associations::default()) + .unwrap() + .settings + .get("SCROLL_SPEED") + .unwrap_or(&"0".to_string()) + .parse() + .expect("Invalid value for SCROLL_SPEED, please use an integer value."); + + let scroll_acceleration: f32 = config + .iter() + .find(|&x| x.associations == Associations::default()) + .unwrap() + .settings + .get("SCROLL_ACCEL") + .unwrap_or(&"0".to_string()) + .parse() + .expect("Invalid value for SCROLL_ACCEL, please use a float value between 0 and 1."); + + let cursor = Movement { + speed: cursor_speed, + acceleration: cursor_acceleration, + }; + + let scroll = Movement { + speed: scroll_speed, + acceleration: scroll_acceleration, + }; + let layout_switcher: Key = Key::from_str( config .iter() @@ -234,6 +295,8 @@ impl EventReader { invert_scroll_axis, axis_16_bit, stadia, + cursor, + scroll, chain_only, layout_switcher, notify_layout_switch, @@ -244,6 +307,8 @@ impl EventReader { virt_dev, lstick_position, rstick_position, + cursor_movement, + scroll_movement, modifiers, modifier_was_activated, device_is_connected, @@ -263,7 +328,7 @@ impl EventReader { .unwrap() .name ); - tokio::join!(self.event_loop(), self.cursor_loop(), self.scroll_loop(),); + tokio::join!(self.event_loop(), self.cursor_loop(), self.scroll_loop(), self.key_cursor_loop(), self.key_scroll_loop()); } pub async fn event_loop(&self) { @@ -964,6 +1029,14 @@ impl EventReader { return; } } + if let Some(map) = config.bindings.movements.get(&event) { + if let Some(movement) = map.get(&modifiers) { + if value <= 1 { + self.emit_movement(movement, value).await; + } + }; + return; + } if let Some(event_list) = map.get(&Vec::new()) { self.emit_event(event_list, value, &modifiers, &config, true, false) .await; @@ -983,6 +1056,14 @@ impl EventReader { return; } } + if let Some(map) = config.bindings.movements.get(&event) { + if let Some(movement) = map.get(&modifiers) { + if value <= 1 { + self.emit_movement(movement, value).await; + } + }; + return; + } self.emit_nonmapped_event(default_event, event, value, &modifiers, &config) .await; } @@ -1117,6 +1198,21 @@ impl EventReader { } } + async fn emit_movement(&self, movement: &Relative, value: i32) { + let mut cursor_movement = self.cursor_movement.lock().await; + let mut scroll_movement = self.scroll_movement.lock().await; + match movement { + Relative::Cursor(Cursor::CURSOR_UP) => cursor_movement.1 = -value, + Relative::Cursor(Cursor::CURSOR_DOWN) => cursor_movement.1 = value, + Relative::Cursor(Cursor::CURSOR_LEFT) => cursor_movement.0 = -value, + Relative::Cursor(Cursor::CURSOR_RIGHT) => cursor_movement.0 = value, + Relative::Scroll(Scroll::SCROLL_UP) => scroll_movement.1 = -value, + Relative::Scroll(Scroll::SCROLL_DOWN) => scroll_movement.1 = value, + Relative::Scroll(Scroll::SCROLL_LEFT) => scroll_movement.0 = -value, + Relative::Scroll(Scroll::SCROLL_RIGHT) => scroll_movement.0 = value, + }; + } + async fn spawn_subprocess(&self, command_list: &Vec) { let mut modifier_was_activated = self.modifier_was_activated.lock().await; *modifier_was_activated = true; @@ -1348,4 +1444,88 @@ impl EventReader { return; } } + + pub async fn key_cursor_loop(&self) { + let (speed, acceleration, mut current_speed) = ( + if self.settings.cursor.speed == 0 { + return + } else { + self.settings.cursor.speed + }, + if self.settings.cursor.acceleration.abs() > 1.0 { + 1.0 + } else { + self.settings.cursor.acceleration.abs() + }, + self.settings.cursor.speed as f32 + ); + while *self.device_is_connected.lock().await { + { + let cursor_movement = self.cursor_movement.lock().await; + if *cursor_movement == (0, 0) { + current_speed = 0.0 + } else { + current_speed += speed as f32 * acceleration / 10.0; + if current_speed > speed as f32 { + current_speed = speed as f32 + } + if cursor_movement.0 != 0 { + let mut virt_dev = self.virt_dev.lock().await; + let virtual_event_x: InputEvent = + InputEvent::new_now(EventType::RELATIVE, 0, cursor_movement.0 * current_speed as i32); + virt_dev.axis.emit(&[virtual_event_x]).unwrap(); + } + if cursor_movement.1 != 0 { + let mut virt_dev = self.virt_dev.lock().await; + let virtual_event_y: InputEvent = + InputEvent::new_now(EventType::RELATIVE, 1, cursor_movement.1 * current_speed as i32); + virt_dev.axis.emit(&[virtual_event_y]).unwrap(); + } + } + } + tokio::time::sleep(std::time::Duration::from_millis(10)).await; + } + } + + pub async fn key_scroll_loop(&self) { + let (speed, acceleration, mut current_speed) = ( + if self.settings.scroll.speed == 0 { + return + } else { + self.settings.scroll.speed + }, + if self.settings.scroll.acceleration.abs() > 1.0 { + 1.0 + } else { + self.settings.scroll.acceleration.abs() + }, + self.settings.scroll.speed as f32 + ); + while *self.device_is_connected.lock().await { + { + let scroll_movement = self.scroll_movement.lock().await; + if *scroll_movement == (0, 0) { + current_speed = 0.0 + } else { + current_speed += speed as f32 * acceleration / 10.0; + if current_speed > speed as f32 { + current_speed = speed as f32 + } + if scroll_movement.0 != 0 { + let mut virt_dev = self.virt_dev.lock().await; + let virtual_event_x: InputEvent = + InputEvent::new_now(EventType::RELATIVE, 12, scroll_movement.0 * current_speed as i32); + virt_dev.axis.emit(&[virtual_event_x]).unwrap(); + } + if scroll_movement.1 != 0 { + let mut virt_dev = self.virt_dev.lock().await; + let virtual_event_y: InputEvent = + InputEvent::new_now(EventType::RELATIVE, 11, scroll_movement.1 * current_speed as i32); + virt_dev.axis.emit(&[virtual_event_y]).unwrap(); + } + } + } + tokio::time::sleep(std::time::Duration::from_millis(10)).await; + } + } }