Until now there was one Xbox identity, `device_type = 4` / `045E:0B13`, and Windows folded a
client's `XboxOne` request onto it because the only Windows Xbox backend was the XUSB companion,
which presents one fixed 360 identity and cannot vary it. The HID backend can, so the fold goes and
two identities join it:
devtype 4 045E:0B13 pf_xboxwireless Xbox Wireless Controller
devtype 5 045E:02FD pf_xboxones Xbox Wireless Controller (One S)
devtype 6 045E:0B22 pf_xboxelite Xbox Elite Wireless Controller Series 2
`GamepadPref::XboxElite` takes wire byte 11 — the first unassigned one, and the round-trip test
previously asserted `from_u8(11) == Auto` with a comment saying assigning it must update that; the
sentinel moved to 12. The C ABI mirror and the generated header moved with it.
⭐ ALL THREE SHARE ONE REPORT DESCRIPTOR, deliberately. In HID terms they are the same pad; the
descriptor is the report shape, not the identity. §3 of the handoff records that our single
hand-written descriptor already cost three separate bugs, and inventing two more would multiply
that debt for no measured gain. They differ in VID/PID, product string, hardware id and Device
Manager description only.
⚠️ All three install `pfGamepadXbox`, the section that attaches the `xinputhid` bus filter. That
was the open risk: Microsoft's `xinputhid.inf` promotes by an explicit hardware-id allow-list
containing `02D1, 02DD, 02E3, 02EA, 0B00, 0B0A, 0B13, 02FF` — and NEITHER `02FD` NOR `0B22` is on
it. Measured on .173: promotion does not care, because it comes from our own AddReg rather than
from matching Microsoft's ids. All three gain `IG_00`, register an XUSB interface, and are read
live by classic XInput. Had this gone the other way the two new identities would have been strictly
worse than the one they joined.
The XUSB escape hatch needed a runtime degrade to stay honest. `pick_gamepad` is compile-time only,
so with `PUNKTFUNK_XBOX_BACKEND=xusb` the host would have resolved and echoed `xboxelite` in its
`Welcome` while actually building a 360 pad. `degrade_xbox_identity` folds the identity back at
runtime, mirroring `degrade_if_no_uhid`.
VERIFIED ON WINDOWS (.173 — none of this compiles on macOS; the driver needs the WDK and the rest
is `cfg(windows)`):
* `cargo test -p pf-inject --lib` 104/104 — including `hwid_matches_inf`,
`hwid_devtype_table_matches_the_driver` and `only_the_xbox_identity_installs_the_xinputhid_section`,
all now sweeping the whole identity set and asserting the section split in both directions.
* `cargo test -p punktfunk-core --lib gamepad` 7/7; `cargo check -p punktfunk-host` clean.
* Driver builds and signs; the descriptor/`wReportLength` const asserts still hold with the
descriptor shared three ways.
* ON GLASS, per identity, via the new `--xboxones` / `--xboxelite` devtest legs: each gets its own
devnode (`PF_XBOX_0` / `PF_XBOX_ONES_0` / `PF_XBOX_ELITE_0`), each HID child gains `IG_00`, each
registers an XUSB interface, and XInput reads each live (packets advancing, `buttons=0x1000`).
* macOS: `cargo fmt --all --check` clean in both workspaces.
NOT VERIFIED / NOT DONE
* **Elite paddles are NOT implemented.** `BTN_PADDLE1..4` would need descriptor buttons, and once
`xinputhid` promotes the pad it claims the HID collection exclusively — XInput has no paddle
fields and the HID consumers that do may be locked out, so the buttons would likely reach
nobody. The decisive measurement is cheap and named in the code: hold a paddle bit set and see
whether a user-mode HID reader still gets reports. Until then the Edge remains the only virtual
pad with native back-button slots and nothing should be advertised otherwise.
* **No client picker offers the Elite**, and none can auto-detect it — SDL3's `GamepadType` has no
Elite variant. It is reachable today only via `PUNKTFUNK_GAMEPAD=xboxelite` or a hand-edited
client setting. All five clients ship the same curated six options by deliberate parity, so
adding one is a cross-client UX change, not part of this.
* Nothing here has run in a real streaming session; every measurement came from the devtest.