From 77f0a25d18d1a462bb2003f0f049487e4555686b Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sun, 9 Aug 2026 20:18:49 +0200 Subject: [PATCH] feat(drivers/pf-gamepad): ship the xinputhid bus filter, so Windows finally promotes our Xbox pad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../windows/drivers/pf-gamepad/pf_gamepad.inx | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/packaging/windows/drivers/pf-gamepad/pf_gamepad.inx b/packaging/windows/drivers/pf-gamepad/pf_gamepad.inx index b0dd2735..a7cd26be 100644 --- a/packaging/windows/drivers/pf-gamepad/pf_gamepad.inx +++ b/packaging/windows/drivers/pf-gamepad/pf_gamepad.inx @@ -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\{...}\. +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\. +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"