Skip to content

Commit

Permalink
feat(CompositeDevice): add GAMEPAD_ONLY intercept mode
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowApex committed Nov 18, 2024
1 parent c425c44 commit 6178865
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 7 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ of three values:
- `0` (NONE) - No inputs are intercepted and re-routed
- `1` (PASS) - No inputs are intercepted and re-routed *except* for gamepad `Guide` events. Upon receiving a gamepad `Guide` event, the device is automatically switched to intercept mode `2` (ALL).
- `2` (ALL) - All inputs are intercepted and re-routed over DBus
- `3` (GAMEPAD_ONLY) - All gamepad inputs are intercepted and re-routed over DBus

Typically the intercept mode should be handled by an external application, but
you can also set the intercept mode from the command line using `busctl`:
Expand Down
2 changes: 2 additions & 0 deletions src/dbus/interface/composite_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ impl CompositeDeviceInterface {
InterceptMode::None => Ok(0),
InterceptMode::Pass => Ok(1),
InterceptMode::Always => Ok(2),
InterceptMode::GamepadOnly => Ok(3),
}
}

Expand All @@ -323,6 +324,7 @@ impl CompositeDeviceInterface {
0 => InterceptMode::None,
1 => InterceptMode::Pass,
2 => InterceptMode::Always,
3 => InterceptMode::GamepadOnly,
_ => InterceptMode::None,
};
self.composite_device
Expand Down
37 changes: 30 additions & 7 deletions src/input/composite_device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ pub enum InterceptMode {
Pass,
/// Intercept all input and send nothing to the target devices
Always,
/// Intercept all gamepad input that would be routed to target devices and
/// send events over dbus instead
GamepadOnly,
}

/// A [CompositeDevice] represents any number source input devices that
Expand Down Expand Up @@ -828,7 +831,7 @@ impl CompositeDevice {
}
}

let intercept = matches!(self.intercept_mode.clone(), InterceptMode::Pass);
let intercept = self.intercept_mode == InterceptMode::Pass;

for event in events {
let cap = event.as_capability();
Expand Down Expand Up @@ -943,10 +946,21 @@ impl CompositeDevice {

// If the device is in intercept mode, only send events to DBus
// target devices.
if matches!(self.intercept_mode, InterceptMode::Always) {
if self.intercept_mode == InterceptMode::Always {
log::trace!("Emit intercepted event: {:?}", event);
#[allow(clippy::for_kv_map)]
for (_, target) in &self.target_dbus_devices {
for target in self.target_dbus_devices.values() {
target.write_event(event.clone()).await?;
}
return Ok(());
}

// If the device is in gamepad intercept mode, send gamepad events to
// DBus target devices.
if self.intercept_mode == InterceptMode::GamepadOnly
&& matches!(cap, Capability::Gamepad(_))
{
log::trace!("Emit intercepted event: {:?}", event);
for target in self.target_dbus_devices.values() {
target.write_event(event.clone()).await?;
}
return Ok(());
Expand Down Expand Up @@ -1059,12 +1073,21 @@ impl CompositeDevice {
log::debug!("Setting intercept mode to: {:?}", mode);
self.intercept_mode = mode;

// If intercept mode is being set to 'Always', clear the state from
// any target devices to prevent further input events.
if mode != InterceptMode::Always {
// Nothing else is required when turning off input interception.
if mode == InterceptMode::None || mode == InterceptMode::Pass {
return;
}

// If intercept mode is being turned on, clear the state from
// any target devices to prevent further input events.
for (path, device) in self.target_devices.iter() {
// If intercept is set to only intercept gamepad input, only target
// gamepad devices need to have their state cleared.
if mode == InterceptMode::GamepadOnly && !path.contains("gamepad") {
log::debug!("Intercept mode is set to GamepadOnly, skipping clearing state on target device {path}");
continue;
}

log::debug!("Clearing state on device: {path}");
if let Err(e) = device.clear_state().await {
log::error!("Failed to clear state on target device {path}: {e:?}");
Expand Down

0 comments on commit 6178865

Please sign in to comment.