diff --git a/rootfs/usr/share/inputplumber/devices/60-xbox_one_bt_gamepad.yaml b/rootfs/usr/share/inputplumber/devices/60-xbox_one_bt_gamepad.yaml index 17b7155..7d4ff97 100644 --- a/rootfs/usr/share/inputplumber/devices/60-xbox_one_bt_gamepad.yaml +++ b/rootfs/usr/share/inputplumber/devices/60-xbox_one_bt_gamepad.yaml @@ -13,22 +13,31 @@ name: Microsoft X-Box One pad # /sys/class/dmi/id/product_name matches: [] -# Only allow a single source device per composite device of this type. -single_source: false +# 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 # 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: - group: gamepad blocked: true - evdev: - vendor_id: "045e" - product_id: "0b13" - handler: event* + udev: + attributes: + - name: name + value: Xbox Wireless Controller + properties: + - name: ID_BUS + value: bluetooth + driver: microsoft + sys_name: "event*" + subsystem: input - group: gamepad - hidraw: - vendor_id: 0x045e - product_id: 0x0b13 + udev: + # NOTE: This might also capture other non-xbox microsoft devices :( + driver: microsoft + subsystem: hidraw # The target input device(s) to emulate by default target_devices: diff --git a/src/drivers/xpad_uhid/driver.rs b/src/drivers/xpad_uhid/driver.rs index e73dc71..6d6ce42 100644 --- a/src/drivers/xpad_uhid/driver.rs +++ b/src/drivers/xpad_uhid/driver.rs @@ -13,12 +13,9 @@ use super::{ hid_report::{XpadUhidOutputData, XpadUhidOutputReport}, }; -// Hardware ID's -pub const VIDS: [u16; 1] = [0x045e]; -pub const PIDS: [u16; 1] = [0x0b13]; - // Report ID pub const DATA: u8 = 0x01; +pub const GUIDE: u8 = 0x02; // Input report size const PACKET_SIZE: usize = 17; @@ -51,13 +48,19 @@ pub struct Driver { impl Driver { pub fn new(udevice: UdevDevice) -> Result> { let path = udevice.devnode(); + let driver = udevice.drivers(); + if !driver.contains(&"microsoft".to_string()) { + return Err(format!("Device '{path}' is not using the hid-microsoft driver").into()); + } + let syspath = udevice.syspath(); + if !syspath.contains("uhid") { + return Err(format!("Device '{path}' is not a uhid virtual device").into()); + } + let cs_path = CString::new(path.clone())?; let api = hidapi::HidApi::new()?; let device = api.open_path(&cs_path)?; - let info = device.get_device_info()?; - if !VIDS.contains(&info.vendor_id()) || !PIDS.contains(&info.product_id()) { - return Err(format!("Device '{path}' is not an xpad_uhid controller").into()); - } + Ok(Self { device, state: None, @@ -104,13 +107,25 @@ impl Driver { DATA => { log::trace!("Got input data."); if bytes_read != PACKET_SIZE { - return Err("Invalid packet size for Keyboard or Touchpad Data.".into()); + return Err("Invalid packet size for input data.".into()); } // Handle the incoming input report let sized_buf = slice.try_into()?; self.handle_input_report(sized_buf)? } + // XBox One gamepads have a separate report for guide button presses + // for some reason. + GUIDE => { + log::trace!("Got guide input data."); + // This report is only 2 bytes, with the first byte representing + // the report id and the second byte being the guide button state + let value = buf[1]; + let event = Event::Button(ButtonEvent::Guide(BinaryInput { + pressed: value == 1, + })); + vec![event] + } _ => { //log::debug!("Invalid Report ID."); let events = vec![]; diff --git a/src/input/source/evdev/blocked.rs b/src/input/source/evdev/blocked.rs index 4eed36f..f89c966 100644 --- a/src/input/source/evdev/blocked.rs +++ b/src/input/source/evdev/blocked.rs @@ -23,6 +23,7 @@ impl BlockedEventDevice { log::debug!("Opening device at: {}", path); let mut device = Device::open(path.clone())?; device.grab()?; + log::info!("Blocking input events from {path}"); Ok(Self { device }) } diff --git a/src/input/source/hidraw.rs b/src/input/source/hidraw.rs index 5422fbf..d47309b 100644 --- a/src/input/source/hidraw.rs +++ b/src/input/source/hidraw.rs @@ -149,20 +149,22 @@ impl HidRawDevice { return DriverType::Fts3528Touchscreen; } - // XpadUhid - if drivers::xpad_uhid::driver::VIDS.contains(&vid) - && drivers::xpad_uhid::driver::PIDS.contains(&pid) - { - log::info!("Detected UHID XPAD"); - return DriverType::XpadUhid; - } - // Rog Ally if vid == drivers::rog_ally::driver::VID && drivers::rog_ally::driver::PIDS.contains(&pid) { log::info!("Detected ROG Ally"); return DriverType::RogAlly; } + // XpadUhid + let drivers = device.drivers(); + if drivers.contains(&"microsoft".to_string()) { + let syspath = device.syspath(); + if syspath.contains("uhid") { + log::info!("Detected UHID XPAD"); + return DriverType::XpadUhid; + } + } + // Unknown log::warn!("No driver for hidraw interface found. VID: {vid}, PID: {pid}"); DriverType::Unknown