Skip to content

Commit

Permalink
fix(Device Hiding): Use static udev rule when ManageAllDevices is set.
Browse files Browse the repository at this point in the history
  • Loading branch information
pastaq authored and ShadowApex committed Feb 10, 2025
1 parent b5db5eb commit e3ddd14
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 15 deletions.
25 changes: 25 additions & 0 deletions rootfs/usr/lib/udev/hwdb.d/59-inputplumber.hwdb
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,28 @@ evdev:name:AT Translated Set 2 keyboard:dmi:*:svnOrangePi:pnNEO-01:*
KEYBOARD_KEY_66=f15
KEYBOARD_KEY_67=f16

# List of virtual devices provided by inputplumber
# Sony Dualsense Edge
hid:b0003g0001v0000054Cp00000DF2
INPUTPLUMBER_VIRT=1

# Valve Steam Deck
hid:b0003g0103v000028DEp00001205
INPUTPLUMBER_VIRT=1

# Horipad Steam Controller
hid:b0003g0001v00000F0Dp000001AB
INPUTPLUMBER_VIRT=1

# XBox 360
input:b0003v045Ep028EeACED-e0,1,3,15,k130,131,133,134,136,137,13A,13B,13C,13D,13E,2C0,2C1,2C2,2C3,ra0,1,2,3,4,5,10,11,mlsf50,51,58,59,5A,60,w
INPUTPLUMBER_VIRT=1

# Xbox Series
input:b0003v045Ep0B12eACED-e0,1,3,15,kA7,130,131,133,134,136,137,13A,13B,13C,13D,13E,2C0,2C1,2C2,2C3,ra0,1,2,3,4,5,10,11,mlsf50,51,58,59,5A,60,w
INPUTPLUMBER_VIRT=1

# Xbox Elite 2
input:b0003v045Ep0B00eACED-e0,1,3,15,kA7,130,131,133,134,136,137,13A,13B,13C,13D,13E,2C0,2C1,2C2,2C3,2C4,2C5,2C6,2C7,ra0,1,2,3,4,5,10,11,mlsf50,51,58,59,5A,60,w
INPUTPLUMBER_VIRT=1

10 changes: 5 additions & 5 deletions rootfs/usr/share/inputplumber/devices/60-horipad_steam.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ kind: CompositeDevice
# Name of the composite device mapping
name: Horipad Steam

# Only use this profile if *any* of the given matches matches. If this list is
# empty,then the source devices will *always* be checked.
# /sys/class/dmi/id/product_name
matches: []

# Only allow a CompositeDevice to manage at most the given number of
# source devices. When this limit is reached, a new CompositeDevice will be
# created for any new matching devices.
maximum_sources: 2

# Only use this profile if *any* of the given matches matches. If this list is
# empty,then the source devices will *always* be checked.
# /sys/class/dmi/id/product_name
matches: []

# One or more source devices to combine into a single virtual device. The events
# from these devices will be watched and translated according to the key map.
source_devices:
Expand Down
6 changes: 3 additions & 3 deletions rootfs/usr/share/inputplumber/devices/60-ps5_ds_gamepad.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ source_devices:
- group: gamepad
blocked: true
evdev:
name: "{Sony Interactive Entertainment DualSense Wireless Controller,DualSense Wireless Controller}"
name: "*DualSense Wireless Controller"
vendor_id: 054c
product_id: 0ce6
handler: event*
- group: gamepad
blocked: true
evdev:
name: "{Sony Interactive Entertainment DualSense Wireless Controller Touchpad,DualSense Wireless Controller Touchpad}"
name: "*DualSense Wireless Controller Touchpad"
vendor_id: 054c
product_id: 0ce6
handler: event*
- group: gamepad
blocked: true
evdev:
name: "{Sony Interactive Entertainment DualSense Wireless Controller Motion Sensors,DualSense Wireless Controller Motion Sensors}"
name: "*DualSense Wireless Controller Motion Sensors"
vendor_id: 054c
product_id: 0ce6
handler: event*
Expand Down
18 changes: 16 additions & 2 deletions src/input/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ use crate::input::source::iio;
use crate::input::target::TargetDevice;
use crate::input::target::TargetDeviceTypeId;
use crate::udev;
use crate::udev::block_joysticks;
use crate::udev::device::AttributeGetter;
use crate::udev::device::UdevDevice;
use crate::udev::unblock_joysticks;

use super::composite_device::client::CompositeDeviceClient;
use super::target::client::TargetDeviceClient;
Expand Down Expand Up @@ -350,8 +352,13 @@ impl Manager {
}
self.manage_all_devices = manage_all_devices;

// If management of all devices was enabled, trigger device discovery
// If management of all devices was enabled, add the needed udev rules and trigger
// device discovery
if manage_all_devices {
if let Err(e) = block_joysticks().await {
log::error!("Failed to set udev rules to block source devices. Double input is possible. {e:?}");
}

let cmd_tx = self.tx.clone();
tokio::task::spawn(async move {
if let Err(e) = Manager::discover_all_devices(&cmd_tx).await {
Expand All @@ -363,6 +370,10 @@ impl Manager {

// If management was disabled, stop any composite devices that
// are not auto-managed.
if let Err(e) = unblock_joysticks().await {
log::error!("Failed to unset udev rules blocking source devices. Input devices may be unavailable. {e:?}");
}

for (dbus_path, config) in self.used_configs.iter() {
if let Some(options) = config.options.as_ref() {
let auto_managed = options.auto_manage.unwrap_or(false);
Expand Down Expand Up @@ -1014,12 +1025,15 @@ impl Manager {

// Check if the virtual device is using the bluetooth bus
// TODO: Can we get properties from UdevDevice::get_attribute_from_tree?
let bus_id = device.get_attribute_from_tree("id/bustype");
let id_bus = device_info.properties.get("ID_BUS");

log::debug!("Bus ID for {dev_path}: {id_bus:?}");
log::debug!("Bus ID for {dev_path}: udev: {id_bus:?}, UdevDevice: {bus_id:?}");
let is_bluetooth = {
if let Some(bus) = id_bus {
bus == "bluetooth"
} else if let Some(bus) = bus_id {
bus == "0005"
} else {
false
}
Expand Down
2 changes: 1 addition & 1 deletion src/input/target/xb360.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl XBox360Controller {
ff.insert(FFEffectCode::FF_GAIN);

// Identify to the kernel as an Xbox One Elite
let id = InputId::new(BusType(3), 0x045e, 0x028e, 0x0001);
let id = InputId::new(BusType(3), 0x045e, 0x028e, 0xaced);

// Build the device
let device = VirtualDeviceBuilder::new()?
Expand Down
2 changes: 1 addition & 1 deletion src/input/target/xbox_elite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl XboxEliteController {
ff.insert(FFEffectCode::FF_GAIN);

// Identify to the kernel as an Xbox One Elite
let id = InputId::new(BusType(3), 0x045e, 0x0b00, 0x0001);
let id = InputId::new(BusType(3), 0x045e, 0x0b00, 0xaced);

// Build the device
let device = VirtualDeviceBuilder::new()?
Expand Down
2 changes: 1 addition & 1 deletion src/input/target/xbox_series.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl XboxSeriesController {
ff.insert(FFEffectCode::FF_GAIN);

// Identify to the kernel as an Xbox One Elite
let id = InputId::new(BusType(3), 0x045e, 0x0b12, 0x0001);
let id = InputId::new(BusType(3), 0x045e, 0x0b12, 0xaced);

// Build the device
let device = VirtualDeviceBuilder::new()?
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use clap::Parser;
use inputplumber::udev::unblock_joysticks;
use std::env;
use std::error::Error;
use std::process;
Expand Down Expand Up @@ -62,6 +63,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
tokio::spawn(async move {
tokio::signal::ctrl_c().await.unwrap();
log::info!("Un-hiding all devices");
if let Err(e) = unblock_joysticks().await {
log::error!("Unable to unblock normal joysticks: {e:?}");
}
if let Err(e) = unhide_all().await {
log::error!("Unable to un-hide devices: {:?}", e);
}
Expand Down
49 changes: 47 additions & 2 deletions src/udev/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,54 @@ use udev::Enumerator;

use self::device::Device;

const RULE_PRIORITY: &str = "73";
const RULE_PRIORITY: &str = "59";
const RULES_PREFIX: &str = "/run/udev/rules.d";

/// Hide all removable input devices from regular users.
pub async fn block_joysticks() -> Result<(), Box<dyn Error>> {
// Find the chmod command to use for hiding
let chmod_cmd = if Path::new("/bin/chmod").exists() {
"/bin/chmod"
} else {
"/usr/bin/chmod"
};

let rule = format!(
r#"# Hide all evdev devices that are not InputPlumber virtual devices
ACTION=="add|change", SUBSYSTEM=="input", KERNEL=="js[0-9]*|event[0-9]*", ENV{{ID_INPUT_JOYSTICK}}=="1", ENV{{INPUTPLUMBER_VIRT}}!="1", MODE:="0000", GROUP:="root", RUN:="{chmod_cmd} 000 %p"
# Hide all Horipad Steam Controller hidraw devices
ACTION=="add|change", SUBSYSTEM=="hidraw", KERNEL=="hidraw[0-9]*", ATTR{{idVendor}}=="0F0D", ATTR{{idProduct}}=="0196", ENV{{INPUTPLUMBER_VIRT}}!="1", MODE:="0000", GROUP:="root", RUN:="{chmod_cmd} 000 %p"
ACTION=="add|change", SUBSYSTEM=="hidraw", KERNEL=="hidraw[0-9]*", ATTR{{idVendor}}=="0F0D", ATTR{{idProduct}}=="01AB", ENV{{INPUTPLUMBER_VIRT}}!="1", MODE:="0000", GROUP:="root", RUN:="{chmod_cmd} 000 %p"
# Hide all PlayStation hidraw devices
ACTION=="add|change", SUBSYSTEMS=="hid", DRIVERS=="playstation", GOTO="playstation_start"
GOTO="playstation_end"
LABEL="playstation_start"
ACTION=="add|change", SUBSYSTEM=="hidraw", KERNEL=="hidraw[0-9]*", ENV{{INPUTPLUMBER_VIRT}}!="1", MODE:="0000", GROUP:="root", RUN:="{chmod_cmd} 000 %p"
LABEL="playstation_end"
"#
);

// Write the udev rule
fs::create_dir_all(RULES_PREFIX)?;
let rule_path = format!("{RULES_PREFIX}/51-inputplumber-hide-joysticks.rules");
fs::write(rule_path, rule)?;

reload_all().await?;

Ok(())
}

/// Unhide all removable input devices from regular users.
pub async fn unblock_joysticks() -> Result<(), Box<dyn Error>> {
let rule_path = format!("{RULES_PREFIX}/51-inputplumber-hide-joysticks.rules");
fs::remove_file(rule_path)?;
reload_all().await?;

Ok(())
}

/// Hide the given input device from regular users.
pub async fn hide_device(path: String) -> Result<(), Box<dyn Error>> {
// Get the device to hide
Expand Down Expand Up @@ -43,7 +88,7 @@ pub async fn hide_device(path: String) -> Result<(), Box<dyn Error>> {
{match_rule}, GOTO="inputplumber_valid"
GOTO="inputplumber_end"
LABEL="inputplumber_valid"
ACTION=="add", KERNEL=="hidraw[0-9]*|js[0-9]*|event[0-9]*", SUBSYSTEM=="{subsystem}", MODE="000", GROUP="root", SYMLINK+="inputplumber/%k", TAG-="uaccess", RUN:="{chmod_cmd} 000 {path}"
ACTION=="add|change", KERNEL=="hidraw[0-9]*|js[0-9]*|event[0-9]*", SUBSYSTEM=="{subsystem}", MODE:="0000", GROUP:="root", RUN:="{chmod_cmd} 000 {path}", SYMLINK+="inputplumber/%k"
LABEL="inputplumber_end"
"#
);
Expand Down

0 comments on commit e3ddd14

Please sign in to comment.