Skip to content

Commit

Permalink
fix(TargetDevice): implement proper device cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowApex committed Feb 16, 2024
1 parent 7159038 commit ae69331
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 44 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 25 additions & 6 deletions src/input/composite_device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -153,10 +158,10 @@ pub struct CompositeDevice {
source_devices_used: Vec<String>,
/// Map of DBus paths to their respective transmitter channel.
/// E.g. {"/org/shadowblip/InputPlumber/devices/target/gamepad0": <Sender>}
target_devices: HashMap<String, mpsc::Sender<NativeEvent>>,
target_devices: HashMap<String, mpsc::Sender<TargetCommand>>,
/// Map of DBusDevice DBus paths to their respective transmitter channel.
/// E.g. {"/org/shadowblip/InputPlumber/devices/target/dbus0": <Sender>}
target_dbus_devices: HashMap<String, mpsc::Sender<NativeEvent>>,
target_dbus_devices: HashMap<String, mpsc::Sender<TargetCommand>>,
}

impl CompositeDevice {
Expand Down Expand Up @@ -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<String, mpsc::Sender<NativeEvent>>,
targets: HashMap<String, mpsc::Sender<TargetCommand>>,
) -> Result<(), Box<dyn Error>> {
log::debug!("Starting composite device");

Expand Down Expand Up @@ -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?;
}
Expand Down Expand Up @@ -343,7 +360,7 @@ impl CompositeDevice {
}

/// Sets the DBus target devices on the [CompositeDevice].
pub fn set_dbus_devices(&mut self, devices: HashMap<String, mpsc::Sender<NativeEvent>>) {
pub fn set_dbus_devices(&mut self, devices: HashMap<String, mpsc::Sender<TargetCommand>>) {
self.target_dbus_devices = devices;
}

Expand Down Expand Up @@ -452,6 +469,8 @@ impl CompositeDevice {

/// Writes the given event to the appropriate target device.
async fn write_event(&self, event: NativeEvent) -> Result<(), Box<dyn Error>> {
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) {
Expand Down
7 changes: 2 additions & 5 deletions src/input/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -116,9 +117,6 @@ pub struct Manager {
/// Mapping of target devices to their respective handles
/// E.g. {"/org/shadowblip/InputPlumber/devices/target/dbus0": <Handle>}
target_devices: HashMap<String, mpsc::Sender<NativeEvent>>,
/// Mapping of target devices without a [CompositeDevice]
/// E.g. {"/org/shadowblip/InputPlumber/devices/target/dbus0": <TargetDevice>}
orphan_target_devices: HashMap<String, TargetDevice>,
}

impl Manager {
Expand All @@ -139,7 +137,6 @@ impl Manager {
source_devices_used: HashMap::new(),
composite_devices: HashMap::new(),
target_devices: HashMap::new(),
orphan_target_devices: HashMap::new(),
}
}

Expand Down Expand Up @@ -263,7 +260,7 @@ impl Manager {
async fn start_target_devices(
&self,
targets: Vec<TargetDevice>,
) -> Result<HashMap<String, mpsc::Sender<NativeEvent>>, Box<dyn Error>> {
) -> Result<HashMap<String, mpsc::Sender<TargetCommand>>, Box<dyn Error>> {
let mut target_devices = HashMap::new();
for target in targets {
match target {
Expand Down
33 changes: 25 additions & 8 deletions src/input/target/dbus.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -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
Expand Down Expand Up @@ -44,8 +46,8 @@ impl DBusInterface {
pub struct DBusDevice {
conn: Connection,
dbus_path: Option<String>,
tx: mpsc::Sender<NativeEvent>,
rx: mpsc::Receiver<NativeEvent>,
tx: mpsc::Sender<TargetCommand>,
rx: mpsc::Receiver<TargetCommand>,
_composite_tx: Option<broadcast::Sender<composite_device::Command>>,
}

Expand All @@ -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<NativeEvent> {
pub fn transmitter(&self) -> mpsc::Sender<TargetCommand> {
self.tx.clone()
}

Expand All @@ -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::<DBusInterface, String>(path)
.await?;
}

Ok(())
Expand Down
38 changes: 30 additions & 8 deletions src/input/target/gamepad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -42,8 +44,8 @@ impl DBusInterface {
pub struct GenericGamepad {
conn: Connection,
dbus_path: Option<String>,
tx: mpsc::Sender<NativeEvent>,
rx: mpsc::Receiver<NativeEvent>,
tx: mpsc::Sender<TargetCommand>,
rx: mpsc::Receiver<TargetCommand>,
_composite_tx: Option<broadcast::Sender<composite_device::Command>>,
}

Expand Down Expand Up @@ -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<NativeEvent> {
pub fn transmitter(&self) -> mpsc::Sender<TargetCommand> {
self.tx.clone()
}

Expand Down Expand Up @@ -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::<DBusInterface, String>(path)
.await?;
}

Ok(())
Expand Down
38 changes: 30 additions & 8 deletions src/input/target/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -40,8 +42,8 @@ impl DBusInterface {
pub struct KeyboardDevice {
conn: Connection,
dbus_path: Option<String>,
tx: mpsc::Sender<NativeEvent>,
rx: mpsc::Receiver<NativeEvent>,
tx: mpsc::Sender<TargetCommand>,
rx: mpsc::Receiver<TargetCommand>,
_composite_tx: Option<broadcast::Sender<composite_device::Command>>,
}

Expand All @@ -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<NativeEvent> {
pub fn transmitter(&self) -> mpsc::Sender<TargetCommand> {
self.tx.clone()
}

Expand All @@ -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::<DBusInterface, String>(path)
.await?;
}

Ok(())
Expand Down
10 changes: 10 additions & 0 deletions src/input/target/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use super::event::native::NativeEvent;

pub mod dbus;
pub mod gamepad;
pub mod keyboard;
Expand All @@ -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,
}
Loading

0 comments on commit ae69331

Please sign in to comment.