Skip to content

Commit

Permalink
feat(manager): Allow for multiple unique version of the same input type.
Browse files Browse the repository at this point in the history
  • Loading branch information
pastaq authored and Derek J. Clark committed Mar 13, 2024
1 parent 2bf8a31 commit 3075f0e
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 131 deletions.
8 changes: 7 additions & 1 deletion rootfs/usr/share/inputplumber/devices/50-legion_go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,17 @@ source_devices:
vendor_id: 0x17ef
product_id: 0x6182
interface_num: 0
- group: mouse # Touch Device
hidraw:
vendor_id: 0x17ef
product_id: 0x6182
interface_num: 1
- group: gamepad
hidraw:
vendor_id: 0x17ef
product_id: 0x6182
interface_num: 2
- group: mouse # Only for optical X/Y
- group: mouse # Only for optical X/Y
hidraw:
vendor_id: 0x17ef
product_id: 0x6182
Expand All @@ -51,6 +56,7 @@ source_devices:
product_id: "6182"
name: "Generic X-Box pad"
- group: keyboard
unique: false
evdev:
vendor_id: "17ef"
product_id: "618*"
Expand Down
4 changes: 4 additions & 0 deletions rootfs/usr/share/inputplumber/schema/composite_device_v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@
},
"hidraw": {
"$ref": "#/definitions/Hidraw"
},
"unique": {
"description": "If false, any devices matching this description will be added to the existing composite device. Defaults to true.",
"type": "boolean"
}
},
"required": [
Expand Down
117 changes: 54 additions & 63 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::error::Error;
use std::io;

use glob_match::glob_match;
use hidapi::{DeviceInfo, HidApi};
use hidapi::DeviceInfo;
use serde::Deserialize;
use thiserror::Error;

Expand Down Expand Up @@ -75,14 +74,14 @@ impl CapabilityMap {
}

/// Defines a platform match for loading a [CompositeDevice]
#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct Match {
pub dmi_data: Option<DMIMatch>,
}

/// Match DMI data for loading a [CompositeDevice]
#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct DMIMatch {
pub bios_release: Option<String>,
Expand All @@ -96,15 +95,16 @@ pub struct DMIMatch {
pub cpu_vendor: Option<String>,
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct SourceDevice {
pub group: String,
pub evdev: Option<Evdev>,
pub hidraw: Option<Hidraw>,
pub unique: Option<bool>,
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct Evdev {
pub name: Option<String>,
Expand All @@ -114,7 +114,7 @@ pub struct Evdev {
pub product_id: Option<String>,
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct Hidraw {
pub vendor_id: Option<u16>,
Expand All @@ -124,7 +124,7 @@ pub struct Hidraw {
}

/// Defines a combined device
#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct CompositeDeviceConfig {
pub version: u32,
Expand Down Expand Up @@ -167,92 +167,83 @@ impl CompositeDeviceConfig {
}

/// Returns true if a given hidraw device is within a list of hidraw configs.
pub fn has_matching_hidraw(&self, device: &DeviceInfo, hidraw_configs: &Vec<Hidraw>) -> bool {
log::debug!("Checking hidraw config: {:?}", hidraw_configs);
for hidraw_config in hidraw_configs.clone() {
let hidraw_config = hidraw_config.clone();
pub fn has_matching_hidraw(&self, device: &DeviceInfo, hidraw_config: &Hidraw) -> bool {
log::debug!("Checking hidraw config: {:?}", hidraw_config);
let hidraw_config = hidraw_config.clone();

if let Some(vendor_id) = hidraw_config.vendor_id {
if device.vendor_id() != vendor_id {
continue;
}
if let Some(vendor_id) = hidraw_config.vendor_id {
if device.vendor_id() != vendor_id {
return false;
}
}

if let Some(product_id) = hidraw_config.product_id {
if device.product_id() != product_id {
continue;
}
if let Some(product_id) = hidraw_config.product_id {
if device.product_id() != product_id {
return false;
}
}

if let Some(interface_num) = hidraw_config.interface_num {
if device.interface_number() != interface_num {
continue;
}
if let Some(interface_num) = hidraw_config.interface_num {
if device.interface_number() != interface_num {
return false;
}

return true;
}

false
true
}

/// Returns true if a given evdev device is within a list of evdev configs.
pub fn has_matching_evdev(
&self,
device: &procfs::device::Device,
evdev_configs: &Vec<Evdev>,
evdev_config: &Evdev,
) -> bool {
// TODO: Maybe in the future we will support virtual devices if we figure something
// out. Ignore virtual devices.
//TODO: Check if the evdev has no proterties defined, that would always match.

if is_virtual(device) {
log::debug!("{} is virtual, skipping.", device.name);
return false;
}

for evdev_config in evdev_configs.clone() {
let evdev_config = evdev_config.clone();
let evdev_config = evdev_config.clone();

if let Some(name) = evdev_config.name {
if !glob_match(name.as_str(), device.name.as_str()) {
continue;
}
if let Some(name) = evdev_config.name {
if !glob_match(name.as_str(), device.name.as_str()) {
return false;
}
}

if let Some(phys_path) = evdev_config.phys_path {
if !glob_match(phys_path.as_str(), device.phys_path.as_str()) {
continue;
}
if let Some(phys_path) = evdev_config.phys_path {
if !glob_match(phys_path.as_str(), device.phys_path.as_str()) {
return false;
}
}

if let Some(handler) = evdev_config.handler {
let mut has_matches = false;
for handle in device.handlers.clone() {
if !glob_match(handler.as_str(), handle.as_str()) {
continue;
}
has_matches = true;
}
if !has_matches {
if let Some(handler) = evdev_config.handler {
let mut has_matches = false;
for handle in device.handlers.clone() {
if !glob_match(handler.as_str(), handle.as_str()) {
continue;
}
has_matches = true;
}

if let Some(vendor_id) = evdev_config.vendor_id {
if !glob_match(vendor_id.as_str(), device.id.vendor.as_str()) {
continue;
}
if !has_matches {
return false;
}
}

if let Some(product_id) = evdev_config.product_id {
if !glob_match(product_id.as_str(), device.id.product.as_str()) {
continue;
}
if let Some(vendor_id) = evdev_config.vendor_id {
if !glob_match(vendor_id.as_str(), device.id.vendor.as_str()) {
return false;
}

return true;
}

false
if let Some(product_id) = evdev_config.product_id {
if !glob_match(product_id.as_str(), device.id.product.as_str()) {
return false;
}
}
true
}

/// Returns true if the configuration has a valid set of matches. This will
Expand Down Expand Up @@ -350,12 +341,12 @@ impl CompositeDeviceConfig {

/// Determines if a procfs device is virtual or real.
fn is_virtual(device: &procfs::device::Device) -> bool {
if device.phys_path != "" {
if !device.phys_path.is_empty() {
return false;
}

if device.sysfs_path.contains("/devices/virtual") {
return true;
}
return false;
false
}
39 changes: 18 additions & 21 deletions src/input/composite_device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,6 @@ pub struct CompositeDevice {
source_devices: Vec<SourceDevice>,
/// Physical device path for source devices. E.g. ["/dev/input/event0"]
source_device_paths: Vec<String>,
/// Unique identifiers for source devices. E.g. ["evdev://event0"]
source_device_ids: Vec<String>,
/// All currently running source device threads
source_device_tasks: JoinSet<()>,
/// Unique identifiers for running source devices. E.g. ["evdev://event0"]
Expand Down Expand Up @@ -228,7 +226,6 @@ impl CompositeDevice {
rx,
source_devices: Vec::new(),
source_device_paths: Vec::new(),
source_device_ids: Vec::new(),
source_device_tasks: JoinSet::new(),
source_devices_used: Vec::new(),
target_devices: HashMap::new(),
Expand Down Expand Up @@ -311,22 +308,22 @@ impl CompositeDevice {
}
}
Command::SourceDeviceStopped(device_id) => {
log::debug!("Detected source device removal: {}", device_id);
let idx = self
.source_devices_used
.iter()
.position(|v| v.clone() == device_id);
if let Some(idx) = idx {
self.source_devices_used.remove(idx);
log::debug!("Detected source device stopped: {}", device_id);
if let Err(e) = self.on_source_device_removed(device_id).await {
log::error!("Failed to remove source device: {:?}", e);
}
if self.source_devices_used.is_empty() {
break;
}
}
Command::SourceDeviceRemoved(id) => {
if let Err(e) = self.on_source_device_removed(id).await {
Command::SourceDeviceRemoved(device_id) => {
log::debug!("Detected source device removed: {}", device_id);
if let Err(e) = self.on_source_device_removed(device_id).await {
log::error!("Failed to remove source device: {:?}", e);
}
if self.source_devices_used.is_empty() {
break;
}
}
Command::Stop => {
log::debug!("Stopping CompositeDevice");
Expand Down Expand Up @@ -393,8 +390,8 @@ impl CompositeDevice {
}

/// Returns an array of all source devices ids being used by this device.
pub fn get_source_device_ids(&self) -> Vec<String> {
self.source_device_ids.clone()
pub fn get_source_devices_used(&self) -> Vec<String> {
self.source_devices_used.clone()
}

/// Sets the DBus target devices on the [CompositeDevice].
Expand Down Expand Up @@ -806,7 +803,7 @@ impl CompositeDevice {
self.run_source_devices().await?;
log::debug!(
"Finished adding source device. All sources: {:?}",
self.source_device_ids
self.source_devices_used
);
Ok(())
}
Expand All @@ -820,11 +817,11 @@ impl CompositeDevice {
self.source_device_paths.remove(idx);
};

let Some(idx) = self.source_device_ids.iter().position(|str| str == &id) else {
let Some(idx) = self.source_devices_used.iter().position(|str| str == &id) else {
return Ok(());
};

self.source_device_ids.remove(idx);
self.source_devices_used.remove(idx);
}
if id.starts_with("hidraw://") {
let name = id.strip_prefix("hidraw://").unwrap();
Expand All @@ -834,11 +831,11 @@ impl CompositeDevice {
self.source_device_paths.remove(idx);
};

let Some(idx) = self.source_device_ids.iter().position(|str| str == &id) else {
let Some(idx) = self.source_devices_used.iter().position(|str| str == &id) else {
return Ok(());
};

self.source_device_ids.remove(idx);
self.source_devices_used.remove(idx);
}

Ok(())
Expand All @@ -862,7 +859,7 @@ impl CompositeDevice {
let source_device = source::SourceDevice::EventDevice(device);
self.source_devices.push(source_device);
self.source_device_paths.push(device_path);
self.source_device_ids.push(id);
self.source_devices_used.push(id);
}

SourceDeviceInfo::HIDRawDeviceInfo(info) => {
Expand All @@ -877,7 +874,7 @@ impl CompositeDevice {
let source_device = source::SourceDevice::HIDRawDevice(device);
self.source_devices.push(source_device);
self.source_device_paths.push(device_path);
self.source_device_ids.push(id);
self.source_devices_used.push(id);
}
}
Ok(())
Expand Down
Loading

0 comments on commit 3075f0e

Please sign in to comment.