[PR #251] [CLOSED] Fix DS4 descriptor, PS Create/Options remap, and PS motion axes #259

Closed
opened 2026-10-22 05:08:21 +00:00 by roman · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/safijari/openpuck/pull/251
Author: @safijari
Created: 8/24/2026
Status: ❌ Closed

Base: main ← Head: fix-playstation-modes


📝 Commits (5)

  • 268dd50 Fix DS4 descriptor, PS Create/Options remap, and PS motion axes
  • 0a9bd78 Merge branch 'main' into fix-playstation-modes
  • 571864b Guarantee the clean PlayStation modes are non-composite
  • 4b28a68 Add the clean PlayStation modes to the panel's mode buttons
  • ee6f148 DS4: declare the full genuine report descriptor, not just the reports we use

📊 Changes

7 files changed (+178 additions, -57 deletions)

View changed files

📝 OpenPuck/OpenPuck.ino (+10 -1)
📝 OpenPuck/gamepad_util.cpp (+40 -12)
📝 OpenPuck/gamepad_util.h (+23 -2)
📝 OpenPuck/mode_hidgyro.cpp (+63 -25)
📝 OpenPuck/mode_ps5.cpp (+12 -15)
📝 README.md (+25 -0)
📝 docs/index.html (+5 -2)

📄 Description

Fixes #223, fixes #118, and most of #202.

All three issues turned out to be separate PlayStation-mode bugs.

DS4 mode was dead on Windows/macOS

#202 ("DS4 does not work whatsoever"), #118 ("as if the thing was bricked"), and @ming1455's comment.

The DS4 report descriptor declared the four stick usages (X/Y/Z/Rz) with the hat's item — Logical Max 7, Report Size 4, Report Count 1 — so the whole stick block collapsed into a single 4-bit field. Walking the descriptor, input report 0x01 declared 60 bytes while hidGyroBuild() sends 64.

Two consequences, both fatal:

  • Hosts that parse the descriptor (Windows HIDClass, macOS IOHIDManager) size every read from the declared length, so all field offsets shift.
  • SDL's PS4 driver drops any USB state packet under 64 bytes outright (HIDAPI_DriverPS4_IsPacketValid, SDL_hidapi_ps4.c: if (size >= 64 && !(data[31] & 0x04))) — every report thrown away.

Linux hidraw hands back the full 64 bytes the device actually wrote, which is why the mode worked there and nowhere else. Replaced with the genuine DualShock 4 descriptor (verified: 63 payload + id = 64, output 0x05 = 31 B, features 0x04/0x02 = 36 B).

"Create" pressed Options, "Options" pressed nothing

#223.

The config panel offers remap code 9 = Create and 10 = Options (and Back/Start, Minus/Plus for the other types). But tritonFromCode/psOrBackCode mapped 9 → TB_VIEW, which psShouldersByte emits as Options, and 10 → TB_QAM, which no mode turns into a host button at all. TB_VIEW/TB_MENU are named backwards with respect to the physical buttons (see the note in triton.h).

Now 9 → TB_MENU (Create / Back / Minus) and 10 → TB_VIEW (Options / Start / Plus). This also fixes the same inversion for a QAM remap in Xbox mode, where code 9 ("Back") was landing on Start.

DS5/DS4 motion axes and sensitivity

#118, and the reversed Cemu gyro reported in #202.

Ground truth is SDL's own SC2 driver (SDL_hidapi_steam_triton.c), which maps both gyro and accel as X ← +x, Y ← +z, Z ← −y. The gyro used exactly that permutation; the accel was passed through unpermuted. That put gravity on PS Z instead of PS Y and gave the accel the opposite handedness to the gyro — so anything that fuses the two (Cemu, rpcs3, console motion) latched into a rotated solution, while Steam and Switch modes read correctly. Same class of bug as the Switch IMU handedness fix.

Both modes now share psImuPack(), which applies the one permutation to gyro and accel alike and halves the accel into the PS pads' 8192-counts/g scale (the SC2 is ±2g over the full int16, ~16384 counts/g).

The calibration feature report was wrong too: the old 2844/2844 gyro pair makes hid-playstation/hid-sony — and rpcs3, which parses the same report — compute a sensitivity 16× too high. SDL escaped it only by rejecting the calibration as "bad" and falling back to raw. 4096 / 256 lands the correct raw/16 deg/s on every stack, so the "super sensitive G" @Surge4315 attributed to rpcs3 should be gone as well. Windows/Steam sensitivity is unchanged (it was already using the correct fallback); Linux/SteamOS and rpcs3 are the ones that change.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/safijari/openpuck/pull/251 **Author:** [@safijari](https://github.com/safijari) **Created:** 8/24/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix-playstation-modes` --- ### 📝 Commits (5) - [`268dd50`](https://github.com/safijari/openpuck/commit/268dd50d094fdc745454b5f37ea3d4091bf5e66e) Fix DS4 descriptor, PS Create/Options remap, and PS motion axes - [`0a9bd78`](https://github.com/safijari/openpuck/commit/0a9bd78744faea0d783c9b36eac08f4772aed80e) Merge branch 'main' into fix-playstation-modes - [`571864b`](https://github.com/safijari/openpuck/commit/571864ba4bbf93dc75990395e84a41ef4a104130) Guarantee the clean PlayStation modes are non-composite - [`4b28a68`](https://github.com/safijari/openpuck/commit/4b28a68eeb435eee034a7f29050f629757c97a7d) Add the clean PlayStation modes to the panel's mode buttons - [`ee6f148`](https://github.com/safijari/openpuck/commit/ee6f14867e59e429fd839fca6bcc6bf30057b0b2) DS4: declare the full genuine report descriptor, not just the reports we use ### 📊 Changes **7 files changed** (+178 additions, -57 deletions) <details> <summary>View changed files</summary> 📝 `OpenPuck/OpenPuck.ino` (+10 -1) 📝 `OpenPuck/gamepad_util.cpp` (+40 -12) 📝 `OpenPuck/gamepad_util.h` (+23 -2) 📝 `OpenPuck/mode_hidgyro.cpp` (+63 -25) 📝 `OpenPuck/mode_ps5.cpp` (+12 -15) 📝 `README.md` (+25 -0) 📝 `docs/index.html` (+5 -2) </details> ### 📄 Description Fixes #223, fixes #118, and most of #202. All three issues turned out to be separate PlayStation-mode bugs. ## DS4 mode was dead on Windows/macOS #202 ("DS4 does not work whatsoever"), #118 ("as if the thing was bricked"), and @ming1455's comment. The DS4 report descriptor declared the four stick usages (X/Y/Z/Rz) with the **hat's** item — `Logical Max 7, Report Size 4, Report Count 1` — so the whole stick block collapsed into a single 4-bit field. Walking the descriptor, input report 0x01 declared **60 bytes** while `hidGyroBuild()` sends **64**. Two consequences, both fatal: * Hosts that parse the descriptor (Windows HIDClass, macOS IOHIDManager) size every read from the *declared* length, so all field offsets shift. * SDL's PS4 driver drops any USB state packet under 64 bytes outright (`HIDAPI_DriverPS4_IsPacketValid`, `SDL_hidapi_ps4.c`: `if (size >= 64 && !(data[31] & 0x04))`) — every report thrown away. Linux hidraw hands back the full 64 bytes the device actually wrote, which is why the mode worked there and nowhere else. Replaced with the genuine DualShock 4 descriptor (verified: 63 payload + id = 64, output 0x05 = 31 B, features 0x04/0x02 = 36 B). ## "Create" pressed Options, "Options" pressed nothing #223. The config panel offers remap code 9 = *Create* and 10 = *Options* (and Back/Start, Minus/Plus for the other types). But `tritonFromCode`/`psOrBackCode` mapped 9 → `TB_VIEW`, which `psShouldersByte` emits as **Options**, and 10 → `TB_QAM`, which no mode turns into a host button at all. `TB_VIEW`/`TB_MENU` are named backwards with respect to the physical buttons (see the note in `triton.h`). Now 9 → `TB_MENU` (Create / Back / Minus) and 10 → `TB_VIEW` (Options / Start / Plus). This also fixes the same inversion for a QAM remap in Xbox mode, where code 9 ("Back") was landing on Start. ## DS5/DS4 motion axes and sensitivity #118, and the reversed Cemu gyro reported in #202. Ground truth is SDL's own SC2 driver (`SDL_hidapi_steam_triton.c`), which maps **both** gyro and accel as `X ← +x, Y ← +z, Z ← −y`. The gyro used exactly that permutation; the accel was passed through **unpermuted**. That put gravity on PS Z instead of PS Y *and* gave the accel the opposite handedness to the gyro — so anything that fuses the two (Cemu, rpcs3, console motion) latched into a rotated solution, while Steam and Switch modes read correctly. Same class of bug as the Switch IMU handedness fix. Both modes now share `psImuPack()`, which applies the one permutation to gyro and accel alike and halves the accel into the PS pads' 8192-counts/g scale (the SC2 is ±2g over the full int16, ~16384 counts/g). The calibration feature report was wrong too: the old `2844/2844` gyro pair makes `hid-playstation`/`hid-sony` — and rpcs3, which parses the same report — compute a sensitivity **16× too high**. SDL escaped it only by rejecting the calibration as "bad" and falling back to raw. `4096` / `256` lands the correct `raw/16` deg/s on every stack, so the "super sensitive G" @Surge4315 attributed to rpcs3 should be gone as well. Windows/Steam sensitivity is unchanged (it was already using the correct fallback); Linux/SteamOS and rpcs3 are the ones that change. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
roman 2026-10-22 05:08:21 +00:00
Sign in to join this conversation.
No labels
pull-request
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
safijari/openpuck#259
No description provided.