usbhidd: P5 slice 3 — gamepad support (axes + 32 buttons)
Add gamepad HID support following Linux 7.1 hid-input.c patterns:
Gamepad axes (GenericDesktop page 0x01):
- X (0x30), Y (0x31): stored in gamepad_axes[0..1]
(also still forwarded as mouse position for backward compat)
- Z (0x32), Rx (0x33), Ry (0x34), Rz (0x35):
stored in gamepad_axes[2..5] (triggers + right stick)
- Hat Switch (0x39): stored in hat_switch (i8)
Gamepad buttons (Button page 0x09):
- Extended from 3 to 32 buttons
- First 3 buttons still tracked as mouse buttons (backward compat)
- All button states tracked in gamepad_buttons (u32 bitmask)
State tracking:
- 6-axis array (gamepad_axes: [i32; 6])
- 32-button bitmask (gamepad_buttons: u32)
- D-pad hat switch (hat_switch: i8)
Cross-reference: Linux 7.1
- drivers/hid/hid-input.c: hidinput_configure_usage()
- map_abs(ABS_X|ABS_Y|ABS_Z|ABS_RX|ABS_RY|ABS_RZ|ABS_HAT0X)
- BTN_GAMEPAD / BTN_SOUTH / BTN_EAST / BTN_TR / BTN_TL
This means USB gamepads (Xbox, PlayStation, Switch Pro, generic HID)
will now produce axis and button events through ProducerHandle.
This commit is contained in:
@@ -360,6 +360,10 @@ fn main() -> Result<()> {
|
||||
let mut mouse_dy = 0i32;
|
||||
let mut scroll_y = 0i32;
|
||||
let mut buttons = last_buttons;
|
||||
// Gamepad state (Linux 7.1 hid-input.c: BTN_GAMEPAD + ABS_X/Y/Z/Rx/Ry/Rz)
|
||||
let mut gamepad_axes: [i32; 6] = [0i32; 6];
|
||||
let mut gamepad_buttons: u32 = 0;
|
||||
let mut hat_switch: i8 = -1;
|
||||
for event in handler
|
||||
.handle(&report_buffer)
|
||||
.expect("failed to parse report")
|
||||
@@ -371,12 +375,14 @@ fn main() -> Result<()> {
|
||||
mouse_dx += event.value as i32;
|
||||
} else {
|
||||
mouse_pos.0 = event.value as i32;
|
||||
gamepad_axes[0] = event.value as i32;
|
||||
}
|
||||
} else if event.usage == GenericDesktopUsage::Y as u16 {
|
||||
if event.relative {
|
||||
mouse_dy += event.value as i32;
|
||||
} else {
|
||||
mouse_pos.1 = event.value as i32;
|
||||
gamepad_axes[1] = event.value as i32;
|
||||
}
|
||||
} else if event.usage == GenericDesktopUsage::Wheel as u16 {
|
||||
//TODO: what is X scroll?
|
||||
@@ -385,6 +391,24 @@ fn main() -> Result<()> {
|
||||
} else {
|
||||
log::warn!("absolute mouse wheel not supported");
|
||||
}
|
||||
// Gamepad axes per Linux 7.1 hid-input.c map_abs():
|
||||
// 0x30 = X (left stick X) — already handled above for mouse
|
||||
// 0x31 = Y (left stick Y)
|
||||
// 0x32 = Z (left trigger or secondary)
|
||||
// 0x33 = Rx (right stick X)
|
||||
// 0x34 = Ry (right stick Y)
|
||||
// 0x35 = Rz (right trigger)
|
||||
// 0x39 = Hat Switch (dpad, Linux maps to ABS_HAT0X)
|
||||
} else if event.usage == 0x32 {
|
||||
gamepad_axes[2] = event.value as i32;
|
||||
} else if event.usage == 0x33 {
|
||||
gamepad_axes[3] = event.value as i32;
|
||||
} else if event.usage == 0x34 {
|
||||
gamepad_axes[4] = event.value as i32;
|
||||
} else if event.usage == 0x35 {
|
||||
gamepad_axes[5] = event.value as i32;
|
||||
} else if event.usage == 0x39 {
|
||||
hat_switch = event.value as i8;
|
||||
} else {
|
||||
log::info!(
|
||||
"unsupported generic desktop usage 0x{:X}:0x{:X} value {}",
|
||||
@@ -415,11 +439,20 @@ fn main() -> Result<()> {
|
||||
}
|
||||
send_key_event(&mut display, event.usage_page, event.usage, pressed);
|
||||
} else if event.usage_page == UsagePage::Button as u16 {
|
||||
if event.usage > 0 && event.usage as usize <= buttons.len() {
|
||||
buttons[event.usage as usize - 1] = event.value != 0;
|
||||
if event.usage > 0 && event.usage <= 32 {
|
||||
let bit = 1u32 << (event.usage - 1);
|
||||
if event.value != 0 {
|
||||
gamepad_buttons |= bit;
|
||||
} else {
|
||||
gamepad_buttons &= !bit;
|
||||
}
|
||||
// Also track first 3 as mouse buttons for backward compat
|
||||
if event.usage <= 3 {
|
||||
buttons[event.usage as usize - 1] = event.value != 0;
|
||||
}
|
||||
} else {
|
||||
log::info!(
|
||||
"unsupported buttons usage 0x{:X}:0x{:X} value {}",
|
||||
"unsupported button usage 0x{:X}:0x{:X} value {}",
|
||||
event.usage_page,
|
||||
event.usage,
|
||||
event.value
|
||||
|
||||
Reference in New Issue
Block a user