Skip to content

Commit

Permalink
fix(XBoxOne Bluetooth): manage all XBox BT controllers and properly h…
Browse files Browse the repository at this point in the history
…andle guide input from XBOne controller
  • Loading branch information
ShadowApex committed Nov 21, 2024
1 parent 38cc122 commit a632734
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 26 deletions.
27 changes: 18 additions & 9 deletions rootfs/usr/share/inputplumber/devices/60-xbox_one_bt_gamepad.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
33 changes: 24 additions & 9 deletions src/drivers/xpad_uhid/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -51,13 +48,19 @@ pub struct Driver {
impl Driver {
pub fn new(udevice: UdevDevice) -> Result<Self, Box<dyn Error + Send + Sync>> {
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,
Expand Down Expand Up @@ -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![];
Expand Down
1 change: 1 addition & 0 deletions src/input/source/evdev/blocked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
}
Expand Down
18 changes: 10 additions & 8 deletions src/input/source/hidraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit a632734

Please sign in to comment.