diff --git a/Cargo.lock b/Cargo.lock index 1c096e4..2da6b9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -604,7 +604,7 @@ dependencies = [ [[package]] name = "inputplumber" -version = "0.1.2" +version = "0.1.4" dependencies = [ "evdev", "glob-match", diff --git a/src/input/composite_device/mod.rs b/src/input/composite_device/mod.rs index d1f0c98..67bf030 100644 --- a/src/input/composite_device/mod.rs +++ b/src/input/composite_device/mod.rs @@ -13,7 +13,12 @@ use crate::{ udev::{hide_device, unhide_device}, }; -use super::{capability, event::Event, source::SourceDevice, target::TargetDevice}; +use super::{ + capability, + event::Event, + source::SourceDevice, + target::{TargetCommand, TargetDevice}, +}; const BUFFER_SIZE: usize = 2048; @@ -153,10 +158,10 @@ pub struct CompositeDevice { source_devices_used: Vec, /// Map of DBus paths to their respective transmitter channel. /// E.g. {"/org/shadowblip/InputPlumber/devices/target/gamepad0": } - target_devices: HashMap>, + target_devices: HashMap>, /// Map of DBusDevice DBus paths to their respective transmitter channel. /// E.g. {"/org/shadowblip/InputPlumber/devices/target/dbus0": } - target_dbus_devices: HashMap>, + target_dbus_devices: HashMap>, } impl CompositeDevice { @@ -248,7 +253,7 @@ impl CompositeDevice { /// devices to translate the events and send them to the appropriate target. pub async fn run( &mut self, - targets: HashMap>, + targets: HashMap>, ) -> Result<(), Box> { log::debug!("Starting composite device"); @@ -301,13 +306,25 @@ impl CompositeDevice { } log::debug!("CompositeDevice stopped"); + // Stop all target devices + log::debug!("Stopping target devices"); + for (_, target) in &self.target_devices { + target.send(TargetCommand::Stop).await?; + } + for (_, target) in &self.target_dbus_devices { + target.send(TargetCommand::Stop).await?; + } + // Unhide all source devices for source_path in self.source_device_paths.clone() { log::debug!("Un-hiding device: {}", source_path); - unhide_device(source_path).await?; + if let Err(e) = unhide_device(source_path.clone()).await { + log::debug!("Unable to unhide device {source_path}: {:?}", e); + } } // Wait on all tasks + log::debug!("Waiting for source device tasks to finish"); while let Some(res) = tasks.join_next().await { res?; } @@ -343,7 +360,7 @@ impl CompositeDevice { } /// Sets the DBus target devices on the [CompositeDevice]. - pub fn set_dbus_devices(&mut self, devices: HashMap>) { + pub fn set_dbus_devices(&mut self, devices: HashMap>) { self.target_dbus_devices = devices; } @@ -452,6 +469,8 @@ impl CompositeDevice { /// Writes the given event to the appropriate target device. async fn write_event(&self, event: NativeEvent) -> Result<(), Box> { + let event = TargetCommand::WriteEvent(event); + // If the device is in intercept mode, only send events to DBus // target devices. if matches!(self.intercept_mode, InterceptMode::Always) { diff --git a/src/input/manager.rs b/src/input/manager.rs index 86d3f1f..03f4729 100644 --- a/src/input/manager.rs +++ b/src/input/manager.rs @@ -28,6 +28,7 @@ use crate::procfs; use crate::watcher; use super::event::native::NativeEvent; +use super::target::TargetCommand; const DEV_PATH: &str = "/dev"; const INPUT_PATH: &str = "/dev/input"; @@ -116,9 +117,6 @@ pub struct Manager { /// Mapping of target devices to their respective handles /// E.g. {"/org/shadowblip/InputPlumber/devices/target/dbus0": } target_devices: HashMap>, - /// Mapping of target devices without a [CompositeDevice] - /// E.g. {"/org/shadowblip/InputPlumber/devices/target/dbus0": } - orphan_target_devices: HashMap, } impl Manager { @@ -139,7 +137,6 @@ impl Manager { source_devices_used: HashMap::new(), composite_devices: HashMap::new(), target_devices: HashMap::new(), - orphan_target_devices: HashMap::new(), } } @@ -263,7 +260,7 @@ impl Manager { async fn start_target_devices( &self, targets: Vec, - ) -> Result>, Box> { + ) -> Result>, Box> { let mut target_devices = HashMap::new(); for target in targets { match target { diff --git a/src/input/target/dbus.rs b/src/input/target/dbus.rs index ba3fef3..b7f4880 100644 --- a/src/input/target/dbus.rs +++ b/src/input/target/dbus.rs @@ -1,7 +1,7 @@ use std::error::Error; use tokio::sync::{broadcast, mpsc}; -use zbus::{fdo, Connection, SignalContext}; +use zbus::{fdo, zvariant::ObjectPath, Connection, SignalContext}; use zbus_macros::dbus_interface; use crate::input::{ @@ -12,6 +12,8 @@ use crate::input::{ }, }; +use super::TargetCommand; + const BUFFER_SIZE: usize = 2048; /// The [DBusInterface] provides a DBus interface that can be exposed for managing @@ -44,8 +46,8 @@ impl DBusInterface { pub struct DBusDevice { conn: Connection, dbus_path: Option, - tx: mpsc::Sender, - rx: mpsc::Receiver, + tx: mpsc::Sender, + rx: mpsc::Receiver, _composite_tx: Option>, } @@ -68,7 +70,7 @@ impl DBusDevice { } /// Returns a transmitter channel that can be used to send events to this device - pub fn transmitter(&self) -> mpsc::Sender { + pub fn transmitter(&self) -> mpsc::Sender { self.tx.clone() } @@ -91,10 +93,25 @@ impl DBusDevice { // Listen for send events log::debug!("Started listening for events to send"); - while let Some(event) = self.rx.recv().await { - //log::debug!("Got event to emit: {:?}", event); - let dbus_event = self.translate_event(event); - self.write_dbus_event(dbus_event).await?; + while let Some(command) = self.rx.recv().await { + match command { + TargetCommand::WriteEvent(event) => { + //log::debug!("Got event to emit: {:?}", event); + let dbus_event = self.translate_event(event); + self.write_dbus_event(dbus_event).await?; + } + TargetCommand::Stop => break, + }; + } + log::debug!("Stopping device"); + + // Remove the DBus interface + if let Some(path) = self.dbus_path.clone() { + log::debug!("Removing DBus interface"); + self.conn + .object_server() + .remove::(path) + .await?; } Ok(()) diff --git a/src/input/target/gamepad.rs b/src/input/target/gamepad.rs index 5342972..c83da3b 100644 --- a/src/input/target/gamepad.rs +++ b/src/input/target/gamepad.rs @@ -17,6 +17,8 @@ use crate::input::{ event::{evdev::EvdevEvent, native::NativeEvent}, }; +use super::TargetCommand; + const BUFFER_SIZE: usize = 2048; /// The [DBusInterface] provides a DBus interface that can be exposed for managing @@ -42,8 +44,8 @@ impl DBusInterface { pub struct GenericGamepad { conn: Connection, dbus_path: Option, - tx: mpsc::Sender, - rx: mpsc::Receiver, + tx: mpsc::Sender, + rx: mpsc::Receiver, _composite_tx: Option>, } @@ -76,7 +78,7 @@ impl GenericGamepad { } /// Returns a transmitter channel that can be used to send events to this device - pub fn transmitter(&self) -> mpsc::Sender { + pub fn transmitter(&self) -> mpsc::Sender { self.tx.clone() } @@ -106,11 +108,31 @@ impl GenericGamepad { // Listen for send events log::debug!("Started listening for events to send"); - while let Some(event) = self.rx.recv().await { - //log::debug!("Got event to emit: {:?}", event); - let evdev_events = self.translate_event(event, axes_map.clone()); - device.emit(evdev_events.as_slice())?; - device.emit(&[SynchronizationEvent::new(SynchronizationCode::SYN_REPORT, 0).into()])?; + while let Some(command) = self.rx.recv().await { + match command { + TargetCommand::WriteEvent(event) => { + //log::debug!("Got event to emit: {:?}", event); + let evdev_events = self.translate_event(event, axes_map.clone()); + device.emit(evdev_events.as_slice())?; + device.emit(&[SynchronizationEvent::new( + SynchronizationCode::SYN_REPORT, + 0, + ) + .into()])?; + } + TargetCommand::Stop => break, + }; + } + + log::debug!("Stopping device"); + + // Remove the DBus interface + if let Some(path) = self.dbus_path.clone() { + log::debug!("Removing DBus interface"); + self.conn + .object_server() + .remove::(path) + .await?; } Ok(()) diff --git a/src/input/target/keyboard.rs b/src/input/target/keyboard.rs index 203ebd7..e019900 100644 --- a/src/input/target/keyboard.rs +++ b/src/input/target/keyboard.rs @@ -14,6 +14,8 @@ use crate::input::{ event::{evdev::EvdevEvent, native::NativeEvent}, }; +use super::TargetCommand; + const BUFFER_SIZE: usize = 2048; /// The [DBusInterface] provides a DBus interface that can be exposed for managing @@ -40,8 +42,8 @@ impl DBusInterface { pub struct KeyboardDevice { conn: Connection, dbus_path: Option, - tx: mpsc::Sender, - rx: mpsc::Receiver, + tx: mpsc::Sender, + rx: mpsc::Receiver, _composite_tx: Option>, } @@ -63,7 +65,7 @@ impl KeyboardDevice { } /// Returns a transmitter channel that can be used to send events to this device - pub fn transmitter(&self) -> mpsc::Sender { + pub fn transmitter(&self) -> mpsc::Sender { self.tx.clone() } @@ -88,11 +90,31 @@ impl KeyboardDevice { // Listen for send events log::debug!("Started listening for events to send"); - while let Some(event) = self.rx.recv().await { - //log::debug!("Got event to emit: {:?}", event); - let evdev_events = self.translate_event(event, axis_map.clone()); - device.emit(evdev_events.as_slice())?; - device.emit(&[SynchronizationEvent::new(SynchronizationCode::SYN_REPORT, 0).into()])?; + while let Some(command) = self.rx.recv().await { + match command { + TargetCommand::WriteEvent(event) => { + //log::debug!("Got event to emit: {:?}", event); + let evdev_events = self.translate_event(event, axis_map.clone()); + device.emit(evdev_events.as_slice())?; + device.emit(&[SynchronizationEvent::new( + SynchronizationCode::SYN_REPORT, + 0, + ) + .into()])?; + } + TargetCommand::Stop => break, + }; + } + + log::debug!("Stopping device"); + + // Remove the DBus interface + if let Some(path) = self.dbus_path.clone() { + log::debug!("Removing DBus interface"); + self.conn + .object_server() + .remove::(path) + .await?; } Ok(()) diff --git a/src/input/target/mod.rs b/src/input/target/mod.rs index d643fe4..63728f6 100644 --- a/src/input/target/mod.rs +++ b/src/input/target/mod.rs @@ -1,3 +1,5 @@ +use super::event::native::NativeEvent; + pub mod dbus; pub mod gamepad; pub mod keyboard; @@ -14,3 +16,11 @@ pub enum TargetDevice { GenericGamepad(gamepad::GenericGamepad), XBox360(xb360::XBox360Controller), } + +/// A [TargetCommand] is a message that can be sent to a [TargetDevice] over +/// a channel. +#[derive(Debug, Clone)] +pub enum TargetCommand { + WriteEvent(NativeEvent), + Stop, +} diff --git a/src/input/target/mouse.rs b/src/input/target/mouse.rs index f6d3078..5a91d54 100644 --- a/src/input/target/mouse.rs +++ b/src/input/target/mouse.rs @@ -14,6 +14,8 @@ use crate::input::{ event::{evdev::EvdevEvent, native::NativeEvent}, }; +use super::TargetCommand; + const BUFFER_SIZE: usize = 2048; /// The [DBusInterface] provides a DBus interface that can be exposed for managing @@ -40,8 +42,8 @@ impl DBusInterface { pub struct MouseDevice { conn: Connection, dbus_path: Option, - tx: mpsc::Sender, - rx: mpsc::Receiver, + tx: mpsc::Sender, + rx: mpsc::Receiver, _composite_tx: Option>, } @@ -63,7 +65,7 @@ impl MouseDevice { } /// Returns a transmitter channel that can be used to send events to this device - pub fn transmitter(&self) -> mpsc::Sender { + pub fn transmitter(&self) -> mpsc::Sender { self.tx.clone() } @@ -88,11 +90,31 @@ impl MouseDevice { // Listen for send events log::debug!("Started listening for events to send"); - while let Some(event) = self.rx.recv().await { - //log::debug!("Got event to emit: {:?}", event); - let evdev_events = self.translate_event(event, axis_map.clone()); - device.emit(evdev_events.as_slice())?; - device.emit(&[SynchronizationEvent::new(SynchronizationCode::SYN_REPORT, 0).into()])?; + while let Some(command) = self.rx.recv().await { + match command { + TargetCommand::WriteEvent(event) => { + //log::debug!("Got event to emit: {:?}", event); + let evdev_events = self.translate_event(event, axis_map.clone()); + device.emit(evdev_events.as_slice())?; + device.emit(&[SynchronizationEvent::new( + SynchronizationCode::SYN_REPORT, + 0, + ) + .into()])?; + } + TargetCommand::Stop => break, + }; + } + + log::debug!("Stopping device"); + + // Remove the DBus interface + if let Some(path) = self.dbus_path.clone() { + log::debug!("Removing DBus interface"); + self.conn + .object_server() + .remove::(path) + .await?; } Ok(())