feat(drivers/pf-gamepad): ship the xinputhid bus filter, so Windows finally promotes our Xbox pad

The field report that started this work was an Xbox controller that no game could see on a Windows
host for two weeks. Root cause was that our Xbox pad reaches no Windows input API a modern title
uses. This is the fix, and it is two registry values.

Windows promotes Xbox pads with `xinputhid`, whose INF is an explicit hardware-id ALLOW-LIST — its
own comment says "we can not use a Compatability ID for the loading of this driver, and so rely on
individual hardware IDs". A software-enumerated devnode can never match those ids, so we write what
the matching install sections would have written. `045E:0B13`, the PID this identity already
claimed, is on that allow-list twice, so the identity choice turned out to be exactly right.

🛑 THE PAIRING IS THE WHOLE FINDING, AND THE TWO VALUES GO IN DIFFERENT KEYS. `UpperFilters` is a
`.HW` AddReg (hardware key); `DevicePropertyFlags` is a DDInstall AddReg (software key). A live A/B
on .173: removing `DevicePropertyFlags` alone reverts EVERYTHING — no `IG_00`, no XUSB interface, no
XInput, no WGI entry — while `UpperFilters` alone is completely inert. `1` = `BusDevice`, which
Microsoft glosses as "a focused bus filter driver for the IG_ problem". It is not a description of
the device, it is the switch. An earlier session installed the filter WITHOUT it, measured a device
that produced nothing, and recorded "never ship it". The filter was never broken; it had never been
switched on. That conclusion is now retracted.

⚠️ The Xbox line gets its OWN DDInstall section, `pfGamepadXbox`. All five identities previously
shared `pfGamepad`, so an AddReg there would have handed a DualSense, DualShock 4, Edge and Steam
Deck to Microsoft's Xbox translator. The regression check below exists for exactly that.

MEASURED ON .173 (Win11 26200), INF-SHIPPED — no hand-written registry values:
  * `UpperFilters=xinputhid` lands on the hardware key and `DevicePropertyFlags=1` on the software
    key, applied by the INF at install.
  * The HID child gains the `IG_00` token: `HID\PUNKTFUNK&IG_00\...`.
  * An XUSB interface appears: `\\?\hid#punktfunk&ig_00#...#{ec87f1e3-...}`.
  * classic XInput reads it live — packets ADVANCING, `buttons=0x1000` (the devtest's A), and the
    stick sweeping. XInput had NEVER seen this backend before.
  * `XInputSetState` rumble round-trips: `rumble from game: pad=0 low=65535 high=32767`.
  * REGRESSION CHECK PASSED: with the DualSense identity up, its devnode has an EMPTY
    `UpperFilters` and no `DevicePropertyFlags`. The PlayStation pads are untouched.

WGI `Gamepad` lists the pad but reads `ts=0`. That is NOT ours: a real Xbox Elite Series 2, promoted
by Microsoft's own driver on the same box, reads `ts=0` in WGI at the very moment classic XInput is
reading live data from it (`buttons=0x1000 LY=-32768`). Our pad is behaviourally indistinguishable
from real hardware here; the row is a property of the non-interactive session.

NOT VERIFIED
  * On-glass in a console session. Everything above ran over ssh, which is what makes the WGI row
    unreadable; the real-Elite control is what settles it, not a clean WGI reading.
  * GameInput — no binding in the `windows` crate, still unmeasured for this backend.
  * `PUNKTFUNK_XBOX_BACKEND` still defaults to XUSB. This changes what the HID backend CAN do; it
    does not change which backend is chosen. That is WP-E and it is a separate decision.
  * Trigger-actuator enable bits, still conjecture — `XINPUT_VIBRATION` has two members and cannot
    exercise them.
This commit is contained in:
2026-08-09 20:18:49 +02:00
parent f9fe496dbc
commit 77f0a25d18
@@ -47,7 +47,11 @@ pf_gamepad.dll=1
%DeviceDescDS4%=pfGamepad, pf_dualshock4
%DeviceDescEdge%=pfGamepad, pf_dualsenseedge
%DeviceDescDeck%=pfGamepad, pf_steamdeck
%DeviceDescXbox%=pfGamepad, root\pf_xboxwireless, pf_xboxwireless
; ⚠️ The Xbox line installs its OWN section, `pfGamepadXbox`, and must keep doing so. Every other
; identity shares `pfGamepad`; the Xbox one additionally attaches the `xinputhid` bus filter, and
; putting that on a DualSense / DualShock 4 / Edge / Steam Deck would hand a PlayStation pad to
; Microsoft's Xbox translator. The two sections are otherwise identical — keep them in step.
%DeviceDescXbox%=pfGamepadXbox, root\pf_xboxwireless, pf_xboxwireless
[pfGamepad.NT]
CopyFiles=UMDriverCopy
@@ -83,6 +87,77 @@ UmdfFsContextUsePolicy=CanUseFsContext2
; across multiple simultaneous controllers (multi-pad).
UmdfHostProcessSharing=ProcessSharingDisabled
; ---------------------------------------------------------------------------------------------
; The Xbox identity: `pfGamepad` plus the two registry values that make Windows PROMOTE the pad.
;
; Measured on .173, 2026-08-09. Without these, our HID Xbox pad is invisible to classic XInput and
; to WGI `Gamepad`, and gets no rumble — the exact field symptom that started this work. With them
; the HID child gains the `IG_00` token, an XUSB interface appears, XInput reads it (full stick
; range and buttons) and `XInputSetState` rumble arrives back as HID output report 0x03.
;
; ⭐ Both values come straight out of Microsoft's own `xinputhid.inf`, which promotes Xbox pads by
; an explicit hardware-id ALLOW-LIST (its own comment: "we can not use a Compatability ID … and so
; rely on individual hardware IDs"). A software-enumerated devnode can never match those ids, so we
; write what the matching install sections would have written. `045E:0B13`, the PID this identity
; claims, is on that allow-list — twice.
;
; 🛑 THE PAIRING IS LOAD-BEARING AND THE TWO VALUES GO IN DIFFERENT KEYS. An A/B on the live box:
; removing `DevicePropertyFlags` alone reverts ALL of it — no `IG_00`, no XUSB interface, no XInput,
; no WGI entry — while `UpperFilters` alone is completely inert. `DevicePropertyFlags = 1` is
; `BusDevice` in `xinputhid.h`, which Microsoft's comment glosses as "a focused bus filter driver
; for the IG_ problem". It is not a description of the device; it is the switch that tells the
; filter what job to do. An earlier session installed the filter WITHOUT it, measured a device that
; produced nothing, and concluded the filter was broken and must never ship. It was not broken; it
; had never been switched on.
;
; ⚠️ Both go on THIS node — the parent/transport devnode — not on the HID child. That is where a
; real Xbox pad carries them: the Elite's Bluetooth transport node has `DevicePropertyFlags=1` and
; the filter, while its HID child has plain `input.inf` and neither.
[pfGamepadXbox.NT]
CopyFiles=UMDriverCopy
Include=MsHidUmdf.inf
Needs=MsHidUmdf.NT
Include=WUDFRD.inf
Needs=WUDFRD_LowerFilter.NT
; HKR in a DDInstall section is the SOFTWARE (driver) key — Control\Class\{...}\<NNNN>.
AddReg=pfGamepadXbox_SW_AddReg
[pfGamepadXbox.NT.hw]
Include=MsHidUmdf.inf
Needs=MsHidUmdf.NT.hw
Include=WUDFRD.inf
Needs=WUDFRD_LowerFilter.NT.hw
; HKR in a .HW section is the HARDWARE (device) key — Enum\<instance>.
AddReg=pfGamepadXbox_HW_AddReg
[pfGamepadXbox.NT.Services]
Include=MsHidUmdf.inf
Needs=MsHidUmdf.NT.Services
Include=WUDFRD.inf
Needs=WUDFRD_LowerFilter.NT.Services
[pfGamepadXbox.NT.Filters]
Include=WUDFRD.inf
Needs=WUDFRD_LowerFilter.NT.Filters
[pfGamepadXbox.NT.Wdf]
UmdfService="pf_gamepad", pf_gamepad_Install
UmdfServiceOrder=pf_gamepad
UmdfKernelModeClientPolicy=AllowKernelModeClients
UmdfFileObjectPolicy=AllowNullAndUnknownFileObjects
UmdfMethodNeitherAction=Copy
UmdfFsContextUsePolicy=CanUseFsContext2
UmdfHostProcessSharing=ProcessSharingDisabled
[pfGamepadXbox_SW_AddReg]
; 1 = BusDevice. See the block above — this is the half that actually does the work.
HKR,,"DevicePropertyFlags",0x00010001,1
[pfGamepadXbox_HW_AddReg]
; 0x00010008 = REG_MULTI_SZ | APPEND, matching xinputhid.inf: append rather than replace, so we
; never clobber a filter someone else put on the stack.
HKR,,"UpperFilters",0x00010008,"xinputhid"
[pf_gamepad_Install]
UmdfLibraryVersion=$UMDFVERSION$
ServiceBinary="%13%\pf_gamepad.dll"