From cd89c53d5025e1e103f5701d6d3ea6ee7820b79f Mon Sep 17 00:00:00 2001 From: cyber-sushi <99445392+cyber-sushi@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:16:27 +0100 Subject: [PATCH] Main.rs split into other files, no functionality change --- src/main.rs | 382 ++-------------------------------------------------- 1 file changed, 8 insertions(+), 374 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4b2aba1..8d3b9df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,380 +1,14 @@ -use std::{collections::HashMap, fmt::Debug, ffi::OsStr, path::Path, sync::Arc, option::Option, env}; -use evdev::{Device, EventStream, Key, RelativeAxisType, AbsoluteAxisType, EventType, InputEvent}; -use evdev::uinput::{VirtualDevice, VirtualDeviceBuilder}; -use hyprland::{data::Client, prelude::*}; -use tokio::{sync::Mutex, task::JoinHandle}; -use tokio_stream::StreamExt; -use tokio_udev; +mod config; +mod virtual_devices; +mod event_reader; +mod udev_monitor; + use tokio; -use serde; use home; +use config::Config; +use tokio::task::JoinHandle; +use crate::udev_monitor::*; -struct EventReader { - config: HashMap, - stream: Arc>, - virt_dev: Arc>, - analog_position: Arc>>, - device_is_connected: Arc>, - current_desktop: Option, -} - -impl EventReader { - fn new(config: HashMap, stream: Arc>, virt_dev: Arc>) -> Self { - let mut position_vector: Vec = Vec::new(); - for i in [0, 0] {position_vector.push(i)}; - let position_vector_mutex = Arc::new(Mutex::new(position_vector)); - let device_is_connected: Arc> = Arc::new(Mutex::new(true)); - let current_desktop: Option = match env::var("XDG_CURRENT_DESKTOP") { - Ok(desktop) if desktop == "Hyprland".to_string() => { - println!("Running on {}, active window detection enabled.", desktop); - Option::Some(desktop) - } - Ok(desktop) => { - println!("Unsupported desktop: {}, won't be able to change bindings according to active window.\n - Currently supported desktops: Hyprland", desktop); - Option::None - }, - Err(_) => { - println!("Unable to retrieve current desktop based on XDG_CURRENT_DESKTOP env var.\n - Won't be able to change bindings according to active window."); - Option::None - }, - }; - Self { - config: config, - stream: stream, - virt_dev: virt_dev, - analog_position: position_vector_mutex, - device_is_connected: device_is_connected, - current_desktop: current_desktop, - } - } - - async fn start(&self) { - let mut stream = self.stream.lock().await; - let mut analog_mode: &str = "left"; - if let Some(stick) = self.config.get(&self.get_active_window().await).unwrap().settings.get("POINTER_STICK") { - analog_mode = stick.as_str(); - } - let mut has_signed_axis_value: &str = "false"; - if let Some(axis_value) = self.config.get(&self.get_active_window().await).unwrap().settings.get("SIGNED_AXIS_VALUE") { - has_signed_axis_value = axis_value.as_str(); - } - while let Some(Ok(event)) = stream.next().await { - match (event.event_type(), RelativeAxisType(event.code()), AbsoluteAxisType(event.code()), analog_mode) { - (EventType::KEY, _, _, _) => { - if let Some(event_list) = self.config.get(&self.get_active_window().await).unwrap().keys.get(&Key(event.code())) { - self.emit_event(event_list, event.value()).await - } else { - self.emit_default_event(event).await; - } - }, - (_, RelativeAxisType::REL_WHEEL | RelativeAxisType::REL_WHEEL_HI_RES, _, _) => { - let event_list_option: Option<&Vec> = match event.value() { - -1 => self.config.get(&self.get_active_window().await).unwrap().rel.get(&"SCROLL_WHEEL_DOWN".to_string()), - 1 => self.config.get(&self.get_active_window().await).unwrap().rel.get(&"SCROLL_WHEEL_UP".to_string()), - _ => None, - }; - if let Some(event_list) = event_list_option { - self.emit_event(event_list, event.value()).await; - self.emit_event(event_list, 0).await; - } else { - if !self.config.get(&self.get_active_window().await).unwrap().rel.contains_key("SCROLL_WHEEL_DOWN") - && !self.config.get(&self.get_active_window().await).unwrap().rel.contains_key("SCROLL_WHEEL_UP") { - self.emit_default_event(event).await; - } - } - }, - (_, _, AbsoluteAxisType::ABS_HAT0X, _) => { - let event_list_option: Option<&Vec> = match event.value() { - -1 => self.config.get(&self.get_active_window().await).unwrap().keys.get(&Key::BTN_DPAD_LEFT), - 0 => self.config.get(&self.get_active_window().await).unwrap().abs.get(&"NONE_X".to_string()), - 1 => self.config.get(&self.get_active_window().await).unwrap().keys.get(&Key::BTN_DPAD_RIGHT), - _ => self.config.get(&self.get_active_window().await).unwrap().abs.get(&"NONE_X".to_string()), - }; - if let Some(event_list) = event_list_option { - self.emit_event(event_list, event.value()).await; - } else { - println!("Button not set in the config file!"); - } - }, - (_, _, AbsoluteAxisType::ABS_HAT0Y, _) => { - let event_list_option: Option<&Vec> = match event.value() { - -1 => self.config.get(&self.get_active_window().await).unwrap().keys.get(&Key::BTN_DPAD_UP), - 0 => self.config.get(&self.get_active_window().await).unwrap().abs.get(&"NONE_Y".to_string()), - 1 => self.config.get(&self.get_active_window().await).unwrap().keys.get(&Key::BTN_DPAD_DOWN), - _ => self.config.get(&self.get_active_window().await).unwrap().abs.get(&"NONE_Y".to_string()), - }; - if let Some(event_list) = event_list_option { - self.emit_event(event_list, event.value()).await; - } else { - println!("Button not set in the config file!"); - } - }, - (EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_X | AbsoluteAxisType::ABS_Y, "left") => { - let rel_value = self.get_rel_value(&has_signed_axis_value, &event).await; - let mut analog_position = self.analog_position.lock().await; - analog_position[event.code() as usize] = rel_value; - }, - (EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_RX | AbsoluteAxisType::ABS_RY, "right") => { - let rel_value = self.get_rel_value(&has_signed_axis_value, &event).await; - let mut analog_position = self.analog_position.lock().await; - analog_position[(event.code() as usize) -3] = rel_value; - }, - (EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_Z, _) => { - if let Some(event_list) = self.config.get(&self.get_active_window().await).unwrap().keys.get(&Key::BTN_TL2) { - if event.value() == 0 { - self.emit_event(event_list, event.value()).await - } else { - self.emit_event(event_list, 1).await - }; - } else { - println!("Button not set in the config file!"); - }; - }, - (EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_RZ, _) => { - if let Some(event_list) = self.config.get(&self.get_active_window().await).unwrap().keys.get(&Key::BTN_TR2) { - if event.value() == 0 { - self.emit_event(event_list, event.value()).await - } else { - self.emit_event(event_list, 1).await - }; - } else { - println!("Button not set in the config file!"); - }; - }, - _ => {self.emit_default_event(event).await} - } - } - let mut device_is_connected = self.device_is_connected.lock().await; - *device_is_connected = false; - } - - async fn emit_event(&self, event_list: &Vec, value: i32) { - for key in event_list { - let virtual_event: InputEvent = InputEvent::new_now(EventType::KEY, key.code(), value); - let mut virt_dev = self.virt_dev.lock().await; - virt_dev.keys.emit(&[virtual_event]).unwrap(); - } - } - - async fn emit_default_event(&self, event: InputEvent) { - let mut virt_dev = self.virt_dev.lock().await; - match event.event_type() { - EventType::KEY => virt_dev.keys.emit(&[event]).unwrap(), - EventType::RELATIVE => virt_dev.relative_axes.emit(&[event]).unwrap(), - _ => {} - } - } - - async fn get_rel_value(&self, has_signed_axis_value: &str, event: &InputEvent) -> i32 { - let rel_value: i32 = match &has_signed_axis_value { - &"false" => { - let distance_from_center: i32 = event.value() as i32 - 128; - distance_from_center / 10 - } - _ => { - event.value() as i32 / 2000 - } - }; - return rel_value - } - - async fn cursor_loop(&self) { - if let Some(sensitivity) = self.config.get(&self.get_active_window().await).unwrap().settings.get("ANALOG_SENSITIVITY") { - let polling_rate: u64 = sensitivity.parse::().expect("Invalid analog sensitivity."); - while *self.device_is_connected.lock().await { - { - let analog_position = self.analog_position.lock().await; - if analog_position[0] != 0 || analog_position[1] != 0 { - let virtual_event_x: InputEvent = InputEvent::new_now(EventType::RELATIVE, 0, analog_position[0]); - let virtual_event_y: InputEvent = InputEvent::new_now(EventType::RELATIVE, 1, analog_position[1]); - let mut virt_dev = self.virt_dev.lock().await; - virt_dev.relative_axes.emit(&[virtual_event_x]).unwrap(); - virt_dev.relative_axes.emit(&[virtual_event_y]).unwrap(); - } - } - tokio::time::sleep(std::time::Duration::from_millis(polling_rate)).await; - } - } else { - return - } - } - - async fn get_active_window(&self) -> String { - let active_client = self.current_desktop.clone().unwrap_or(String::from("default")); - match active_client.as_str() { - "Hyprland" => { - let active_window: String = match Client::get_active_async().await.unwrap() { - Some(client) => client.class, - None => String::from("default") - }; - if self.config.contains_key(&active_window) { - active_window - } else { - String::from("default") - } - }, - _ => String::from("default") - } - } -} - -#[derive(serde::Deserialize, Debug, Clone)] -struct Config { - #[serde(skip)] - name: String, - #[serde(default)] - keys: HashMap>, - settings: HashMap, - #[serde(skip)] - abs: HashMap>, - #[serde(default)] - rel: HashMap>, -} - -impl Config { - fn new_from_file(file: &str, file_name: String) -> Self { - println!("Parsing config file at {:?}", file); - let file_content: String = std::fs::read_to_string(file).unwrap(); - let config: Config = toml::from_str(&file_content).expect("Couldn't parse config file."); - let keys: HashMap> = config.keys; - let rel: HashMap> = config.rel; - let mut abs: HashMap> = HashMap::new(); - let mut pad_horizontal: Vec = keys.get(&Key::BTN_DPAD_LEFT).unwrap_or(&Vec::new()).clone(); - pad_horizontal.extend(keys.get(&Key::BTN_DPAD_RIGHT).unwrap_or(&Vec::new())); - let mut pad_vertical: Vec = keys.get(&Key::BTN_DPAD_UP).unwrap_or(&Vec::new()).clone(); - pad_vertical.extend(keys.get(&Key::BTN_DPAD_DOWN).unwrap_or(&Vec::new())); - abs.insert("NONE_X".to_string(), pad_horizontal); - abs.insert("NONE_Y".to_string(), pad_vertical); - let settings: HashMap = config.settings; - Self { - name: file_name, - keys: keys, - settings: settings, - abs: abs, - rel: rel - } - } -} - -struct VirtualDevices { - keys: VirtualDevice, - relative_axes: VirtualDevice, -} - -impl VirtualDevices { - fn new(keys: VirtualDevice, relative_axes: VirtualDevice) -> Self { - Self { - keys: keys, - relative_axes: relative_axes, - } - } -} - -async fn create_new_reader(device: String, config: HashMap) { - let stream: Arc> = Arc::new(Mutex::new(get_event_stream(Path::new(&device), config.clone()))); - let virt_dev: Arc> = Arc::new(Mutex::new(new_virtual_devices())); - let reader = EventReader::new(config.clone(), stream, virt_dev); - println!("Mapped device detected at {}, reading events.", device); - tokio::join!( - reader.start(), - reader.cursor_loop(), - ); - println!("Disconnected device at {}.", device); -} - -async fn start_monitoring_udev(config_files: Vec, mut tasks: Vec>) { - launch_tasks(&config_files, &mut tasks); - let mut monitor = tokio_udev::AsyncMonitorSocket::new( - tokio_udev::MonitorBuilder::new().unwrap() - .match_subsystem(OsStr::new("input")).unwrap() - .listen().unwrap() - ).unwrap(); - while let Some(Ok(event)) = monitor.next().await { - if is_mapped(&event.device(), &config_files) { - println!("Reinitializing..."); - for task in &tasks { - task.abort(); - } - tasks.clear(); - launch_tasks(&config_files, &mut tasks) - } - } -} - -fn get_event_stream(path: &Path, config: HashMap) -> EventStream { - let mut device: Device = Device::open(path).expect("Couldn't open device path."); - if config.get("default").unwrap().settings.get("GRAB_DEVICE").expect("No GRAB_DEVICE setting specified, this device will be ignored.") == &"true".to_string() { - device.grab().unwrap(); - }; - let stream: EventStream = device.into_event_stream().unwrap(); - return stream -} - -fn new_virtual_devices() -> VirtualDevices { - let mut key_capabilities = evdev::AttributeSet::new(); - for i in 1..334 {key_capabilities.insert(Key(i));}; - let mut rel_capabilities = evdev::AttributeSet::new(); - for i in 0..13 {rel_capabilities.insert(evdev::RelativeAxisType(i));}; - let keys_builder = VirtualDeviceBuilder::new().unwrap() - .name("Makima Virtual Keyboard/Mouse") - .with_keys(&key_capabilities).unwrap(); - let rel_builder = VirtualDeviceBuilder::new().unwrap() - .name("Makima Virtual Pointer") - .with_relative_axes(&rel_capabilities).unwrap(); - let virtual_device_keys = keys_builder.build().unwrap(); - let virtual_device_rel = rel_builder.build().unwrap(); - let virtual_devices = VirtualDevices::new(virtual_device_keys, virtual_device_rel); - return virtual_devices; -} - -fn launch_tasks(config_files: &Vec, tasks: &mut Vec>) { - let devices: evdev::EnumerateDevices = evdev::enumerate(); - for device in devices { - let mut config_map: HashMap = HashMap::new(); - for config in config_files { - let split_config_name = config.name.split("::").collect::>(); - let associated_device_name = split_config_name[0]; - if associated_device_name == device.1.name().unwrap() { - let window_class = if split_config_name.len() == 1 { - String::from("default") - } else { - split_config_name[1].to_string() - }; - config_map.insert(window_class, config.clone()); - }; - } - if !config_map.is_empty() { - tasks.push( - tokio::spawn( - create_new_reader( - device.0.as_path().to_str().unwrap().to_string(), - config_map.clone() - ) - ) - ) - } - } -} - -fn is_mapped(udev_device: &tokio_udev::Device, config_files: &Vec) -> bool { - match udev_device.devnode() { - Some(devnode) => { - let evdev_devices: evdev::EnumerateDevices = evdev::enumerate(); - for evdev_device in evdev_devices { - for config in config_files { - if config.name.contains(&evdev_device.1.name().unwrap().to_string()) - && devnode.to_path_buf() == evdev_device.0 { - return true - } - } - } - } - _ => return false - } - return false -} #[tokio::main] async fn main() {