use std::{collections::HashMap, sync::Arc, option::Option, process::{Command, Stdio}}; use tokio::sync::Mutex; use tokio_stream::StreamExt; use fork::{fork, Fork, setsid}; use evdev::{EventStream, Key, RelativeAxisType, AbsoluteAxisType, EventType, InputEvent}; use crate::virtual_devices::VirtualDevices; use crate::Config; use crate::config::{Event, Axis, parse_modifiers}; use crate::active_client::*; use crate::udev_monitor::{Environment, Client}; struct Stick { function: String, sensitivity: u64, deadzone: i32, activation_modifiers: Vec, } struct Settings { lstick: Stick, rstick: Stick, axis_16_bit: bool, chain_only: bool, } pub struct EventReader { config: HashMap, stream: Arc>, virt_dev: Arc>, lstick_position: Arc>>, rstick_position: Arc>>, modifiers: Arc>>, modifier_was_activated: Arc>, device_is_connected: Arc>, environment: Environment, settings: Settings, } impl EventReader { pub fn new ( config: HashMap, stream: Arc>, modifiers: Arc>>, modifier_was_activated: Arc>, environment: Environment, ) -> Self { let mut position_vector: Vec = Vec::new(); for i in [0, 0] {position_vector.push(i)}; let lstick_position = Arc::new(Mutex::new(position_vector.clone())); let rstick_position = Arc::new(Mutex::new(position_vector.clone())); let device_is_connected: Arc> = Arc::new(Mutex::new(true)); let virt_dev = Arc::new(Mutex::new(VirtualDevices::new())); let lstick_function = config.get(&Client::Default).unwrap() .settings.get("LSTICK").unwrap_or(&"cursor".to_string()).to_string(); let lstick_sensitivity: u64 = config.get(&Client::Default).unwrap() .settings.get("LSTICK_SENSITIVITY").unwrap_or(&"0".to_string()).parse::().expect("Invalid value for LSTICK_SENSITIVITY, please use an integer value >= 0"); let lstick_deadzone: i32 = config.get(&Client::Default).unwrap() .settings.get("LSTICK_DEADZONE").unwrap_or(&"5".to_string()).parse::().expect("Invalid value for LSTICK_DEADZONE, please use an integer between 0 and 128."); let lstick_activation_modifiers: Vec = parse_modifiers(&config.get(&Client::Default).unwrap().settings, "LSTICK_ACTIVATION_MODIFIERS"); let lstick = Stick { function: lstick_function, sensitivity: lstick_sensitivity, deadzone: lstick_deadzone, activation_modifiers: lstick_activation_modifiers, }; let rstick_function: String = config.get(&Client::Default).unwrap() .settings.get("RSTICK").unwrap_or(&"scroll".to_string()).to_string(); let rstick_sensitivity: u64 = config.get(&Client::Default).unwrap() .settings.get("RSTICK_SENSITIVITY").unwrap_or(&"0".to_string()).parse::().expect("Invalid value for RSTICK_SENSITIVITY, please use an integer value >= 0"); let rstick_deadzone: i32 = config.get(&Client::Default).unwrap() .settings.get("RSTICK_DEADZONE").unwrap_or(&"5".to_string()).parse::().expect("Invalid value for RSTICK_DEADZONE, please use an integer between 0 and 128."); let rstick_activation_modifiers: Vec = parse_modifiers(&config.get(&Client::Default).unwrap().settings, "RSTICK_ACTIVATION_MODIFIERS"); let rstick = Stick { function: rstick_function, sensitivity: rstick_sensitivity, deadzone: rstick_deadzone, activation_modifiers: rstick_activation_modifiers, }; let axis_16_bit: bool = config.get(&Client::Default).unwrap() .settings.get("16_BIT_AXIS").unwrap_or(&"false".to_string()).parse().expect("16_BIT_AXIS can only be true or false."); let chain_only: bool = config.get(&Client::Default).unwrap() .settings.get("CHAIN_ONLY").unwrap_or(&"true".to_string()).parse().expect("CHAIN_ONLY can only be true or false."); let settings = Settings { lstick, rstick, axis_16_bit, chain_only, }; Self { config, stream, virt_dev, lstick_position, rstick_position, modifiers, modifier_was_activated, device_is_connected, environment, settings, } } pub async fn start(&self) { println!("{:?} detected, reading events.\n", self.config.get(&get_active_window(&self.environment.server, &self.config).await).unwrap().name); tokio::join!( self.event_loop(), self.cursor_loop(), self.scroll_loop(), ); } pub async fn event_loop(&self) { let (mut dpad_values, mut lstick_values, mut rstick_values, mut triggers_values) = ((0, 0), (0, 0), (0, 0), (0, 0)); let mut stream = self.stream.lock().await; while let Some(Ok(event)) = stream.next().await { match (event.event_type(), RelativeAxisType(event.code()), AbsoluteAxisType(event.code())) { (EventType::KEY, _, _) => { match event.code() { 312 | 313 => {}, _ => self.convert_event(event, Event::Key(Key(event.code())), event.value()).await, } }, (_, RelativeAxisType::REL_WHEEL | RelativeAxisType::REL_WHEEL_HI_RES, _) => { match event.value() { -1 => { self.convert_event(event, Event::Axis(Axis::SCROLL_WHEEL_DOWN), 1).await; self.convert_event(event, Event::Axis(Axis::SCROLL_WHEEL_DOWN), 0).await; }, 1 => { self.convert_event(event, Event::Axis(Axis::SCROLL_WHEEL_UP), 1).await; self.convert_event(event, Event::Axis(Axis::SCROLL_WHEEL_UP), 0).await; }, _ => {} } }, (_, _, AbsoluteAxisType::ABS_HAT0X) => { match event.value() { -1 => { self.convert_event(event, Event::Axis(Axis::BTN_DPAD_LEFT), 1).await; dpad_values.0 = -1; }, 1 => { self.convert_event(event, Event::Axis(Axis::BTN_DPAD_RIGHT), 1).await; dpad_values.0 = 1; }, 0 => { match dpad_values.0 { -1 => self.convert_event(event, Event::Axis(Axis::BTN_DPAD_LEFT), 0).await, 1 => self.convert_event(event, Event::Axis(Axis::BTN_DPAD_RIGHT), 0).await, _ => {}, } dpad_values.0 = 0; }, _ => {} }; }, (_, _, AbsoluteAxisType::ABS_HAT0Y) => { match event.value() { -1 => { self.convert_event(event, Event::Axis(Axis::BTN_DPAD_UP), 1).await; dpad_values.1 = -1; }, 1 => { self.convert_event(event, Event::Axis(Axis::BTN_DPAD_DOWN), 1).await; dpad_values.1 = 1; }, 0 => { match dpad_values.1 { -1 => self.convert_event(event, Event::Axis(Axis::BTN_DPAD_UP), 0).await, 1 => self.convert_event(event, Event::Axis(Axis::BTN_DPAD_DOWN), 0).await, _ => {}, } dpad_values.1 = 0; }, _ => {} }; }, (EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_X | AbsoluteAxisType::ABS_Y) => { match self.settings.lstick.function.as_str() { "cursor" | "scroll" => { let axis_value = self.get_axis_value(&event, &self.settings.lstick.deadzone).await; let mut lstick_position = self.lstick_position.lock().await; lstick_position[event.code() as usize] = axis_value; }, "bind" => { let axis_value = self.get_axis_value(&event, &self.settings.lstick.deadzone).await; let clamped_value = if axis_value < 0 { -1 } else if axis_value > 0 { 1 } else { 0 }; match AbsoluteAxisType(event.code()) { AbsoluteAxisType::ABS_Y => { match clamped_value { -1 if lstick_values.1 != -1 => { self.convert_event(event, Event::Axis(Axis::LSTICK_UP), 1).await; lstick_values.1 = -1 }, 1 if lstick_values.1 != 1 => { self.convert_event(event, Event::Axis(Axis::LSTICK_DOWN), 1).await; lstick_values.1 = 1 }, 0 => if lstick_values.1 != 0 { match lstick_values.1 { -1 => self.convert_event(event, Event::Axis(Axis::LSTICK_UP), 0).await, 1 => self.convert_event(event, Event::Axis(Axis::LSTICK_DOWN), 0).await, _ => {}, } lstick_values.1 = 0; }, _ => {}, } }, AbsoluteAxisType::ABS_X => { match clamped_value { -1 if lstick_values.0 != -1 => { self.convert_event(event, Event::Axis(Axis::LSTICK_LEFT), 1).await; lstick_values.0 = -1 }, 1 => if lstick_values.0 != 1 { self.convert_event(event, Event::Axis(Axis::LSTICK_RIGHT), 1).await; lstick_values.0 = 1 }, 0 => if lstick_values.0 != 0 { match lstick_values.0 { -1 => self.convert_event(event, Event::Axis(Axis::LSTICK_LEFT), 0).await, 1 => self.convert_event(event, Event::Axis(Axis::LSTICK_RIGHT), 0).await, _ => {}, } lstick_values.0 = 0; }, _ => {}, } }, _ => {}, } }, _ => {}, } }, (EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_RX | AbsoluteAxisType::ABS_RY) => { match self.settings.rstick.function.as_str() { "cursor" | "scroll" => { let axis_value = self.get_axis_value(&event, &self.settings.rstick.deadzone).await; let mut rstick_position = self.rstick_position.lock().await; rstick_position[event.code() as usize -3] = axis_value; }, "bind" => { let axis_value = self.get_axis_value(&event, &self.settings.rstick.deadzone).await; let clamped_value = if axis_value < 0 { -1 } else if axis_value > 0 { 1 } else { 0 }; match AbsoluteAxisType(event.code()) { AbsoluteAxisType::ABS_RY => { match clamped_value { -1 => if rstick_values.1 != -1 { self.convert_event(event, Event::Axis(Axis::RSTICK_UP), 1).await; rstick_values.1 = -1 }, 1 => if rstick_values.1 != 1 { self.convert_event(event, Event::Axis(Axis::RSTICK_DOWN), 1).await; rstick_values.1 = 1 }, 0 => if rstick_values.1 != 0 { match rstick_values.1 { -1 => self.convert_event(event, Event::Axis(Axis::RSTICK_UP), 0).await, 1 => self.convert_event(event, Event::Axis(Axis::RSTICK_DOWN), 0).await, _ => {}, } rstick_values.1 = 0; }, _ => {}, } }, AbsoluteAxisType::ABS_RX => { match clamped_value { -1 if rstick_values.0 != -1 => { self.convert_event(event, Event::Axis(Axis::RSTICK_LEFT), 1).await; rstick_values.0 = -1 }, 1 => if rstick_values.0 != 1 { self.convert_event(event, Event::Axis(Axis::RSTICK_RIGHT), 1).await; rstick_values.0 = 1 }, 0 => if rstick_values.0 != 0 { match rstick_values.0 { -1 => self.convert_event(event, Event::Axis(Axis::RSTICK_LEFT), 0).await, 1 => self.convert_event(event, Event::Axis(Axis::RSTICK_RIGHT), 0).await, _ => {}, } rstick_values.0 = 0; }, _ => {}, } }, _ => {}, } }, _ => {}, } }, (EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_Z) => { match (event.value(), triggers_values.0) { (0, 1) => { self.convert_event(event, Event::Axis(Axis::BTN_TL2), 0).await; triggers_values.0 = 0; }, (_, 0) => { self.convert_event(event, Event::Axis(Axis::BTN_TL2), 1).await; triggers_values.0 = 1; }, _ => {}, } }, (EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_RZ) => { match (event.value(), triggers_values.1) { (0, 1) => { self.convert_event(event, Event::Axis(Axis::BTN_TR2), 0).await; triggers_values.1 = 0; }, (_, 0) => { self.convert_event(event, Event::Axis(Axis::BTN_TR2), 1).await; triggers_values.1 = 1; }, _ => {}, } }, _ => self.emit_default_event(event).await, } } let mut device_is_connected = self.device_is_connected.lock().await; *device_is_connected = false; println!("Disconnected device \"{}\".\n", self.config.get(&get_active_window(&self.environment.server, &self.config).await).unwrap().name); } async fn convert_event(&self, default_event: InputEvent, event: Event, value: i32) { let path = self.config.get(&get_active_window(&self.environment.server, &self.config).await).unwrap(); let modifiers = self.modifiers.lock().await.clone(); if let Some(map) = path.bindings.remap.get(&event) { if let Some(event_list) = map.get(&modifiers) { self.emit_event(event_list, value, &modifiers, modifiers.is_empty(), !modifiers.is_empty()).await; return } else if let Some(event_list) = map.get(&vec![Event::Hold]) { if !modifiers.is_empty() || self.settings.chain_only == false { self.emit_event(event_list, value, &modifiers, false, false).await; return } else if let Some(event_list) = map.get(&Vec::new()) { self.emit_event(event_list, value, &modifiers, true, false).await; return } } else if let Some(event_list) = map.get(&Vec::new()) { self.emit_event(event_list, value, &modifiers, true, false).await; return } } if let Some(map) = path.bindings.commands.get(&event) { if let Some(command_list) = map.get(&modifiers) { if value == 1 {self.spawn_subprocess(command_list).await}; return } } self.emit_nonmapped_event(default_event, event, value, &modifiers).await; } async fn emit_event(&self, event_list: &Vec, value: i32, modifiers: &Vec, release_keys: bool, ignore_modifiers: bool) { let path = self.config.get(&get_active_window(&self.environment.server, &self.config).await).unwrap(); let mut virt_dev = self.virt_dev.lock().await; let mut modifier_was_activated = self.modifier_was_activated.lock().await; if release_keys { let released_keys: Vec = self.released_keys(&modifiers).await; for key in released_keys { self.toggle_modifiers(Event::Key(key), 0).await; let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 0); virt_dev.keys.emit(&[virtual_event]).unwrap(); } } else if ignore_modifiers { for key in modifiers.iter() { if let Event::Key(key) = key { let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 0); virt_dev.keys.emit(&[virtual_event]).unwrap(); } } } for key in event_list { if release_keys { self.toggle_modifiers(Event::Key(*key), value).await; } if path.mapped_modifiers.custom.contains(&Event::Key(*key)) { 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_nonmapped_event(&self, default_event: InputEvent, event: Event, value: i32, modifiers: &Vec) { let path = self.config.get(&get_active_window(&self.environment.server, &self.config).await).unwrap(); let mut virt_dev = self.virt_dev.lock().await; let mut modifier_was_activated = self.modifier_was_activated.lock().await; let released_keys: Vec = self.released_keys(&modifiers).await; for key in released_keys { self.toggle_modifiers(Event::Key(key), 0).await; let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), 0); virt_dev.keys.emit(&[virtual_event]).unwrap() } self.toggle_modifiers(event, value).await; if path.mapped_modifiers.custom.contains(&event) { if value == 0 && !*modifier_was_activated { let virtual_event: InputEvent = InputEvent::new_now(default_event.event_type(), default_event.code(), 1); virt_dev.keys.emit(&[virtual_event]).unwrap(); let virtual_event: InputEvent = InputEvent::new_now(default_event.event_type(), default_event.code(), 0); virt_dev.keys.emit(&[virtual_event]).unwrap(); *modifier_was_activated = true; } else if value == 1 { *modifier_was_activated = false; } } else { *modifier_was_activated = true; match default_event.event_type() { EventType::KEY => { virt_dev.keys.emit(&[default_event]).unwrap(); }, EventType::RELATIVE => { if value == 1 { virt_dev.axis.emit(&[default_event]).unwrap(); } }, _ => {}, } } } async fn emit_default_event(&self, event: InputEvent) { match event.event_type() { EventType::KEY => { let mut virt_dev = self.virt_dev.lock().await; virt_dev.keys.emit(&[event]).unwrap(); }, EventType::RELATIVE => { let mut virt_dev = self.virt_dev.lock().await; virt_dev.axis.emit(&[event]).unwrap(); }, _ => {}, } } async fn spawn_subprocess(&self, command_list: &Vec) { let mut modifier_was_activated = self.modifier_was_activated.lock().await; *modifier_was_activated = true; let (user, running_as_root) = if let Ok(sudo_user) = &self.environment.sudo_user { (Option::Some(sudo_user), true) } else if let Ok(user) = &self.environment.user { (Option::Some(user), false) } else { (Option::None, false) }; if let Some(user) = user { for command in command_list { let cmd = if running_as_root { let cmd = format!("runuser {} -c '{}'", user, command); cmd } else { command.clone() }; match fork() { Ok(Fork::Child) => { match fork() { Ok(Fork::Child) => { setsid().unwrap(); Command::new("sh") .arg("-c") .arg(cmd) .stdin(Stdio::null()) .stdout(Stdio::null()) .stderr(Stdio::null()) .spawn() .unwrap(); std::process::exit(0); } Ok(Fork::Parent(_)) => std::process::exit(0), Err(_) => std::process::exit(1), } } Ok(Fork::Parent(_)) => (), Err(_) => std::process::exit(1), } } } } async fn get_axis_value(&self, event: &InputEvent, deadzone: &i32) -> i32 { let distance_from_center: i32 = match self.settings.axis_16_bit { false => (event.value() as i32 - 128) * 200, _ => event.value() as i32 }; if distance_from_center.abs() <= deadzone * 200 { 0 } else { (distance_from_center + 2000 - 1) / 2000 } } async fn toggle_modifiers(&self, modifier: Event, value: i32) { let path = self.config.get(&get_active_window(&self.environment.server, &self.config).await).unwrap(); let mut modifiers = self.modifiers.lock().await; if path.mapped_modifiers.all.contains(&modifier) { match value { 1 => { modifiers.push(modifier); modifiers.sort(); modifiers.dedup(); }, 0 => modifiers.retain(|&x| x != modifier), _ => {}, } } } async fn released_keys(&self, modifiers: &Vec) -> Vec { let path = self.config.get(&get_active_window(&self.environment.server, &self.config).await).unwrap(); let mut released_keys: Vec = Vec::new(); for (_key, hashmap) in path.bindings.remap.iter() { if let Some(event_list) = hashmap.get(modifiers) { released_keys.extend(event_list); } } released_keys } pub async fn cursor_loop(&self) { let (cursor, sensitivity, activation_modifiers) = if self.settings.lstick.function.as_str() == "cursor" { ("left", self.settings.lstick.sensitivity, self.settings.lstick.activation_modifiers.clone()) } else if self.settings.rstick.function.as_str() == "cursor" { ("right", self.settings.rstick.sensitivity, self.settings.rstick.activation_modifiers.clone()) } else { ("disabled", 0, vec![]) }; if sensitivity != 0 { while *self.device_is_connected.lock().await { { let stick_position = if cursor == "left" { self.lstick_position.lock().await } else if cursor == "right" { self.rstick_position.lock().await } else { break }; if stick_position[0] != 0 || stick_position[1] != 0 { let modifiers = self.modifiers.lock().await; if activation_modifiers.len() == 0 || activation_modifiers == *modifiers { let virtual_event_x: InputEvent = InputEvent::new_now(EventType::RELATIVE, 0, stick_position[0]); let virtual_event_y: InputEvent = InputEvent::new_now(EventType::RELATIVE, 1, stick_position[1]); let mut virt_dev = self.virt_dev.lock().await; virt_dev.axis.emit(&[virtual_event_x]).unwrap(); virt_dev.axis.emit(&[virtual_event_y]).unwrap(); } } } tokio::time::sleep(std::time::Duration::from_millis(sensitivity)).await; } } else { return } } pub async fn scroll_loop(&self) { let (scroll, sensitivity, activation_modifiers) = if self.settings.lstick.function.as_str() == "scroll" { ("left", self.settings.lstick.sensitivity, self.settings.lstick.activation_modifiers.clone()) } else if self.settings.rstick.function.as_str() == "scroll" { ("right", self.settings.rstick.sensitivity, self.settings.rstick.activation_modifiers.clone()) } else { ("disabled", 0, vec![]) }; if sensitivity != 0 { while *self.device_is_connected.lock().await { { let stick_position = if scroll == "left" { self.lstick_position.lock().await } else if scroll == "right" { self.rstick_position.lock().await } else { break }; if stick_position[0] != 0 || stick_position[1] != 0 { let modifiers = self.modifiers.lock().await; if activation_modifiers.len() == 0 || activation_modifiers == *modifiers { let virtual_event_x: InputEvent = InputEvent::new_now(EventType::RELATIVE, 12, stick_position[0]); let virtual_event_y: InputEvent = InputEvent::new_now(EventType::RELATIVE, 11, stick_position[1]); let mut virt_dev = self.virt_dev.lock().await; virt_dev.axis.emit(&[virtual_event_x]).unwrap(); virt_dev.axis.emit(&[virtual_event_y]).unwrap(); } } } tokio::time::sleep(std::time::Duration::from_millis(sensitivity)).await; } } else { return } } }