Skip to content

Commit

Permalink
feat(Manager): add gamepad reordering
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowApex committed Feb 11, 2025
1 parent 9b5bdff commit d42b6fd
Show file tree
Hide file tree
Showing 7 changed files with 387 additions and 70 deletions.
41 changes: 41 additions & 0 deletions src/cli/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ impl Display for InterceptMode {
pub enum DevicesCommand {
/// List all running composite devices
List,
/// List or set the player order of composite devices
Order { device_ids: Option<Vec<u8>> },
/// Enable/disable managing all supported input devices
ManageAll {
#[arg(long, action)]
Expand Down Expand Up @@ -223,6 +225,45 @@ pub async fn handle_devices(conn: Connection, cmd: DevicesCommand) -> Result<(),
let verb = if enable { "Enabled" } else { "Disabled" };
println!("{verb} management of all supported devices");
}
DevicesCommand::Order { device_ids } => {
let manager = ManagerInterfaceProxy::builder(&conn).build().await?;
if let Some(ids) = device_ids {
let paths: Vec<String> = ids
.into_iter()
.map(|id| format!("/org/shadowblip/InputPlumber/CompositeDevice{id}"))
.collect();
manager.set_gamepad_order(paths).await?;
}

// Fetch the current gamepad order
let order = manager.gamepad_order().await?;

// Query information about each device
let mut devices = Vec::with_capacity(order.len());
for path in order {
let device = CompositeDeviceInterfaceProxy::builder(&conn)
.path(path.clone())
.unwrap()
.build()
.await;
let Some(device) = device.ok() else {
continue;
};

let number = path.replace("/org/shadowblip/InputPlumber/CompositeDevice", "");
let name = device.name().await.unwrap_or_default();

let row = DeviceRow { id: number, name };

devices.push(row);
}

let mut table = Table::new(devices);
table
.with(Style::modern_rounded())
.with(Panel::header("Composite Devices"));
println!("{table}");
}
}

Ok(())
Expand Down
31 changes: 29 additions & 2 deletions src/dbus/interface/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,35 @@ impl ManagerInterface {
}

#[zbus(property)]
async fn intercept_mode(&self) -> fdo::Result<String> {
Ok("InputPlumber".to_string())
async fn gamepad_order(&self) -> fdo::Result<Vec<String>> {
let (sender, mut receiver) = mpsc::channel(1);
self.tx
.send_timeout(
ManagerCommand::GetGamepadOrder { sender },
Duration::from_millis(500),
)
.await
.map_err(|err| fdo::Error::Failed(err.to_string()))?;

// Read the response from the manager
let Some(response) = receiver.recv().await else {
return Err(fdo::Error::Failed("No response from manager".to_string()));
};

Ok(response)
}

#[zbus(property)]
async fn set_gamepad_order(&self, order: Vec<String>) -> zbus::Result<()> {
self.tx
.send_timeout(
ManagerCommand::SetGamepadOrder { dbus_paths: order },
Duration::from_millis(500),
)
.await
.map_err(|err| fdo::Error::Failed(err.to_string()))?;

Ok(())
}

/// If set to 'true', InputPlumber will try to manage all input devices
Expand Down
11 changes: 11 additions & 0 deletions src/input/composite_device/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,15 @@ impl CompositeDeviceClient {
}
Err(ClientError::ChannelClosed)
}

/// Returns true if the target devices are suspended
pub async fn is_suspended(&self) -> Result<bool, ClientError> {
let (tx, mut rx) = channel(1);
self.tx.send(CompositeCommand::IsSuspended(tx)).await?;

if let Some(result) = rx.recv().await {
return Ok(result);
}
Err(ClientError::ChannelClosed)
}
}
1 change: 1 addition & 0 deletions src/input/composite_device/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ pub enum CompositeCommand {
Stop,
Suspend(mpsc::Sender<()>),
Resume(mpsc::Sender<()>),
IsSuspended(mpsc::Sender<bool>),
}
34 changes: 11 additions & 23 deletions src/input/composite_device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,13 @@ impl CompositeDevice {
log::error!("Failed to send resume response: {e:?}");
}
}
CompositeCommand::IsSuspended(sender) => {
let is_suspended = !self.target_devices_suspended.is_empty();
log::debug!("Checking if device is suspended: {is_suspended}");
if let Err(e) = sender.send(is_suspended).await {
log::error!("Failed to send suspended response: {e:?}");
}
}
}
}

Expand Down Expand Up @@ -2064,9 +2071,6 @@ impl CompositeDevice {
// Clear the list of suspended target devices
self.target_devices_suspended.clear();

// Create a list of target devices that should be stopped on suspend
let mut targets_to_stop = HashMap::new();

// Record what target devices are currently used so they can be restored
// when the system is resumed.
for (path, target) in self.target_devices.clone().into_iter() {
Expand All @@ -2078,21 +2082,7 @@ impl CompositeDevice {
}
};

// The "deck" target device does not support suspend
if target_type.as_str() == "deck" {
targets_to_stop.insert(path, target);
}

self.target_devices_suspended.push(target_type);
}
log::info!(
"Target devices before suspend: {:?}",
self.target_devices_suspended
);

// Tear down any target devices that do not support suspend
for (path, target) in targets_to_stop.into_iter() {
log::info!("Stopping target device: {path}");
self.target_devices.remove(&path);
for (_, target_devices) in self.target_devices_by_capability.iter_mut() {
target_devices.remove(&path);
Expand All @@ -2104,6 +2094,10 @@ impl CompositeDevice {
// Wait a few beats to ensure that the target device is really gone
tokio::time::sleep(Duration::from_millis(200)).await;
}
log::info!(
"Target devices before suspend: {:?}",
self.target_devices_suspended
);
}

/// Called when notified by the input manager that system resume is about
Expand All @@ -2114,12 +2108,6 @@ impl CompositeDevice {
self.target_devices_suspended
);

// Only handle resume if a deck controller target device was used
if !self.target_devices_suspended.contains(&"deck".to_string()) {
self.target_devices_suspended.clear();
return;
}

// Set the target devices back to the ones used before suspend
if let Err(err) = self
.set_target_devices(self.target_devices_suspended.clone())
Expand Down
Loading

0 comments on commit d42b6fd

Please sign in to comment.