fix(drivers/windows): name each virtual pad for what it is — one shared description read as "the setting did nothing"
deb / build-publish (push) Successful in 9m31s
windows-drivers / probe-and-proto (push) Successful in 42s
ci / web (push) Successful in 54s
ci / docs-site (push) Successful in 1m9s
windows-drivers / driver-build (push) Successful in 2m1s
ci / bench (push) Successful in 7m35s
decky / build-publish (push) Successful in 20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
deb / build-publish-host (push) Successful in 10m4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
android / android (push) Successful in 12m30s
ci / rust-arm64 (push) Successful in 13m55s
apple / swift (push) Successful in 5m28s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m41s
deb / build-publish-client-arm64 (push) Successful in 11m7s
windows-host / package (push) Successful in 16m55s
arch / build-publish (push) Successful in 20m3s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 8m46s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9m7s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 10m54s
docker / deploy-docs (push) Successful in 34s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 4m4s
flatpak / build-publish (push) Failing after 8m23s
docker / build-push-arm64cross (push) Successful in 3m59s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 3m28s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m48s
ci / rust (push) Successful in 32m19s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 5m55s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 19m9s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 18m53s
release / apple (push) Successful in 29m51s
apple / screenshots (push) Successful in 24m26s

`pf_dualsense.inx` gave all four hardware ids a single %DeviceDesc%, so Device
Manager labelled an emulated DualShock 4, DualSense Edge and Steam Deck pad
"punktfunk Virtual DualSense". The HID layer was always per-type — device_type
picks the PID (09CC for DS4), the report descriptor and the product string — but
the one place a user goes to check said DualSense for every choice, which reads
exactly like the controller-type setting being ignored.

Split into four model lines over the same install section, one description each.
No binding, service or descriptor change; stampinf's 9.9.MMdd.HHmm DriverVer
increments on every build, so pnputil takes the update. InfVerif on the WDK
runner: INF is VALID.

Also correct the Slot.pref comment from the previous commit: emulating a
DualShock 4 gives up adaptive triggers by construction. HidOutput::Trigger is
emitted only by dualsense_proto, and a DS4 has no trigger-effect reports — the
host never generates any to send. Rumble and the lightbar remain.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-26 16:56:44 +02:00
co-authored by Claude Opus 5
parent 6edd700910
commit 0d9d78398c
2 changed files with 25 additions and 8 deletions
@@ -57,9 +57,11 @@ public final class GamepadCapture {
let pad: UInt32 let pad: UInt32
/// The controller KIND declared to the host (GamepadArrival) when the slot opened the /// The controller KIND declared to the host (GamepadArrival) when the slot opened the
/// user's explicit "Controller type" setting when they picked one, else the detected /// user's explicit "Controller type" setting when they picked one, else the detected
/// kind (`GamepadManager.declaredKind(for:)`). NOT the physical pad's kind: local /// kind (`GamepadManager.declaredKind(for:)`). NOT the physical pad's kind: local feedback
/// feedback keys off the live `GCController` subclass instead, so an emulated type never /// keys off the live `GCController` subclass instead, so whatever the host DOES send is
/// costs a DualSense its lightbar or adaptive triggers. /// applied natively to the pad in the user's hands. What the host sends is bounded by the
/// emulated type, though a virtual DualShock 4 has no adaptive-trigger reports in its
/// protocol, so emulating one gives those up by construction (rumble + lightbar remain).
let pref: PunktfunkConnection.GamepadType let pref: PunktfunkConnection.GamepadType
var buttons: UInt32 = 0 var buttons: UInt32 = 0
var axes: [Int32] = [0, 0, 0, 0, 0, 0] var axes: [Int32] = [0, 0, 0, 0, 0, 0]
@@ -1,5 +1,6 @@
;/*++ ;/*++
; punktfunk virtual DualSense — UMDF2 HID minidriver INF (M0 spike). ; punktfunk virtual PlayStation/Valve pads — UMDF2 HID minidriver INF (M0 spike).
; One package, four hardware ids: DualSense, DualShock 4, DualSense Edge, Steam Deck.
; Adapted from the WDK vhidmini2 UMDF2 sample (VhidminiUm.inx). ; Adapted from the WDK vhidmini2 UMDF2 sample (VhidminiUm.inx).
; Depends on MsHidUmdf.inf (build >= 22000). ; Depends on MsHidUmdf.inf (build >= 22000).
; Install: devgen /add /hardwareid "root\pf_dualsense" (after pnputil /add-driver /install) ; Install: devgen /add /hardwareid "root\pf_dualsense" (after pnputil /add-driver /install)
@@ -27,10 +28,19 @@ pf_dualsense.dll=1
[pf.NT$ARCH$.10.0...22000] [pf.NT$ARCH$.10.0...22000]
; Hardware ids: `root\pf_dualsense` for a root-enumerated devnode (devgen/devcon tests); `pf_dualsense` ; Hardware ids: `root\pf_dualsense` for a root-enumerated devnode (devgen/devcon tests); `pf_dualsense`
; for the host's SwDeviceCreate'd DualSense (the `root\` prefix is reserved for root enumeration, so ; for the host's SwDeviceCreate'd DualSense (the `root\` prefix is reserved for root enumeration, so
; SwDeviceCreate rejects it with E_INVALIDARG); `pf_dualshock4` / `pf_dualsenseedge` for the host's ; SwDeviceCreate rejects it with E_INVALIDARG); `pf_dualshock4` / `pf_dualsenseedge` / `pf_steamdeck`
; virtual DualShock 4 / DualSense Edge — the same driver binds all of them and serves the matching ; for the host's other virtual pads — ONE driver binds all of them (every model line below installs
; identity per the device_type byte the host stamps into shared memory. ; the same `pfDualSense` section) and serves the matching HID identity per the device_type byte the
%DeviceDesc%=pfDualSense, root\pf_dualsense, pf_dualsense, pf_dualshock4, pf_dualsenseedge, pf_steamdeck ; host stamps into shared memory.
;
; Each id carries its OWN description: Device Manager reads this string, and a single shared
; "Virtual DualSense" made an emulated DualShock 4 look like the controller-type setting had been
; ignored. The HID layer (VID/PID, report descriptor, product string) was always per-type; this
; makes the human-readable name agree with it.
%DeviceDesc%=pfDualSense, root\pf_dualsense, pf_dualsense
%DeviceDescDS4%=pfDualSense, pf_dualshock4
%DeviceDescEdge%=pfDualSense, pf_dualsenseedge
%DeviceDescDeck%=pfDualSense, pf_steamdeck
[pfDualSense.NT] [pfDualSense.NT]
CopyFiles=UMDriverCopy CopyFiles=UMDriverCopy
@@ -78,4 +88,9 @@ ProviderString ="punktfunk"
ManufacturerString ="punktfunk" ManufacturerString ="punktfunk"
ClassName ="HID device" ClassName ="HID device"
Disk_Description ="punktfunk DualSense Installation Disk" Disk_Description ="punktfunk DualSense Installation Disk"
; One per hardware id — these are what Device Manager shows. Keep them aligned with the product
; strings the driver serves per device_type (src/lib.rs `on_get_string`).
DeviceDesc ="punktfunk Virtual DualSense" DeviceDesc ="punktfunk Virtual DualSense"
DeviceDescDS4 ="punktfunk Virtual DualShock 4"
DeviceDescEdge ="punktfunk Virtual DualSense Edge"
DeviceDescDeck ="punktfunk Virtual Steam Deck Controller"