Skip to content

feat(CapabilityMap): add generic hidraw button driver#563

Open
honjow wants to merge 4 commits into
ShadowBlip:mainfrom
honjow:feat/generic_hidraw
Open

feat(CapabilityMap): add generic hidraw button driver#563
honjow wants to merge 4 commits into
ShadowBlip:mainfrom
honjow:feat/generic_hidraw

Conversation

@honjow
Copy link
Copy Markdown
Contributor

@honjow honjow commented Mar 24, 2026

Summary

Add a generic hidraw button driver that uses capability map YAML configs to define button mappings, following the same pattern as existing evdev capability maps. This removes the need to write per-device Rust driver modules for simple HID button devices.

Includes GPD Win 5 HID button support (new firmware) as the first use case. Supersedes #558, which implements the same functionality with a dedicated driver.

Approach

The existing evdev source already uses a declarative approach — devices like MSI Claw and GPD define button mappings in YAML capability maps without any device-specific Rust code. This PR extends that pattern to hidraw by:

  1. Extending HidrawConfig with flexible detection modes (non-zero byte, exact value match, specific bit check)
  2. Adding HidrawEventTranslator to translate raw HID reports based on the capability map
  3. Falling back to the generic driver automatically when DriverType::Unknown but a hidraw capability map is present

Adding support for a new simple HID button device now only requires a YAML capability map file — no Rust code or recompilation needed.

Test plan

  • Verify GPD Win 5 back buttons (mode switch, L4, R4) work with new firmware
  • Verify existing hidraw devices (DualSense, Legion Go, etc.) are unaffected

Copy link
Copy Markdown
Contributor

@pastaq pastaq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much needed feature, thanks for working on this. I want to discuss a few things, so before you change anything below lets get to a consensus.

Comment thread rootfs/usr/share/inputplumber/capability_maps/gpd_v2_hid1.yaml
Comment thread rootfs/usr/share/inputplumber/capability_maps/gpd_v2_hid1.yaml
Comment thread src/input/event/hidraw/translator.rs
Comment thread src/input/event/hidraw/translator.rs
Comment thread src/input/event/hidraw/translator.rs Outdated
Comment thread src/input/source/hidraw.rs Outdated
Copy link
Copy Markdown
Contributor

@pastaq pastaq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making those changes. I'll test it this week and verify there are no strange effects in other hid devices.

Copy link
Copy Markdown
Contributor

@pastaq pastaq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on Legion Go S and Legion Go 2 and experienced 0 conflicts.

Copy link
Copy Markdown
Contributor

@ShadowApex ShadowApex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this change! This is something we have wanted for a while. I left a few short comments, but we should be able to accept this with minimal changes. Thanks again!

Comment on lines +16 to +17
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<u8>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this field in decoding hidraw data?

Comment on lines +43 to +50
if hidraw.input_type != "button" {
log::warn!(
"Unsupported hidraw input_type '{}' in mapping '{}', skipping",
hidraw.input_type,
mapping.name,
);
continue;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this implementation only supports simple button decoding, it would be nice to add a TODO somewhere so we can ensure that we finish implementing decoding other types of input (e.g. axis info, gyro, etc.)

const READ_BUF_SIZE: usize = 64;

/// Generic hidraw button source device driven by a capability map.
pub struct GenericHidrawButtons {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this will eventually also support non-button input, we should probably call this simply GenericHidraw.

Comment on lines +299 to +302
Err(format!(
"No driver for hidraw interface found. VID: {vid:#06x}, PID: {pid:#06x}"
)
.into())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to further specify in the error here that no driver or capability map was found for this device.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants