Skip to content

Vibration handles before a controller's haptics are routed (a game that asks once at startup lost every value) - #246

Closed
parsifal295 wants to merge 2 commits into
seedds:mainfrom
parsifal295:rumble-handles
Closed

parsifal295 wants to merge 2 commits into
seedds:mainfrom
parsifal295:rumble-handles

Conversation

@parsifal295

@parsifal295 parsifal295 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

hid::GetVibrationDeviceHandles answered 0 handles until a controller's haptics were routed (vib_targets → dm_haptics_available). A game that asks once at startup, before GameController reports the pad, keeps that empty answer and sends every vibration value to handle 0, which reaches no output for the whole session: a game that rumbles would stay silent.

Found in the log of Unicorn Overlord on the Mac with a DualSense (DM_RUMBLE_LOG=1, below). Unicorn Overlord itself has no rumble (on the Switch it does not vibrate either: it sends amplitude 0 throughout), so the bug changed nothing in its play; the fix is not yet checked on a game that rumbles.

On Horizon the handles are computed from the npad id and style alone (libnx _hidGetVibrationDeviceHandles), and vib_send already checks for an output at each send. The handles now need only rumble on with an output sink installed (new dm_haptics_enabled) and the npad's connected style. No sink, rumble off or a disconnected npad still get none, and IsVibrationPermitted still follows the routed outputs: t_hid's existing checks for both are unchanged, plus one new check (handles before routing). DM_RUMBLE_LOG=1 logs the handle requests and, once a second, the values sent, those that reached no output and the peak amplitude.

Docs: docs/reference/services.md "Vibration handles before a controller is reported" (symptom index regenerated), the rumble switches in docs/development.md, and Unicorn Overlord's note (Input: its two vibration paths and that it has no rumble; Found on this game).

Related PRs

Checked

  • dm/host/tests: t_hid (61 checks), t_haptics and t_haptics_apple pass.
  • The tool tests (111, 14 skipped) and the docs check pass; dmhost builds for Unicorn Overlord (010069401ADB8000).
  • On the Mac with a DualSense, Unicorn Overlord (Asian release, 1.05), DM_RUMBLE_LOG=1: before, the startup request was answered with none and every value reached no output; after, the handles are 0x3 / 0x10003 and no value is dropped.
  • Not checked: a game that actually rumbles. Unicorn Overlord and 13 Sentinels: Aegis Rim (the two games tried) have no rumble. The iPhone was not tested.

…verlord asks for its handles once at startup, before GameController reports the pad, and kept an empty answer for the whole session

hid::GetVibrationDeviceHandles answered 0 handles until a controller's haptics were routed (vib_targets: dm_haptics_available). Unicorn Overlord calls it once at startup; on the Mac the DualSense is reported a moment later, so the game kept no handles and sent every value (two hid::SendVibrationValue a frame per player) to handle 0, which reached no output: no rumble for the whole session. On Horizon the handles are computed from the npad id and style alone (libnx _hidGetVibrationDeviceHandles), and vib_send already checks for an output at each send. The handles now need only rumble on with an output sink installed (new dm_haptics_enabled) and the npad's connected style; no sink, rumble off or a disconnected npad still get none, and IsVibrationPermitted still follows the routed outputs (t_hid's checks for both are unchanged). DM_RUMBLE_LOG=1 logs the handle requests and, once a second, the values sent, those that reached no output and the peak amplitude.

Docs: services.md "Vibration handles before a controller is reported" (symptom index regenerated), the rumble switches in development.md, and Unicorn Overlord's note (Input: what its two vibration paths do; Found on this game). Checked: t_hid (61 checks, one new: handles before routing), t_haptics and t_haptics_apple pass; the tool tests and the docs check pass; dmhost builds for Unicorn Overlord. On the Mac with a DualSense (Unicorn Overlord, Asian release): before, the request was answered with none and every value reached no output; after, the handles are 0x3 / 0x10003 and none is dropped
…een in the log only

The reference entry and the game note said the game lost its rumble. It has none (on the Switch it does not vibrate either): it sends amplitude 0 throughout, so nothing could be felt before or after the fix. The symptom is now the log's (handles answered with none, every value reaching no output), what a rumbling game would lose is said as such, and the Found on line says the fix is not yet checked on a game that rumbles. Symptom index regenerated; the docs check passes
@parsifal295 parsifal295 changed the title Vibration handles before a controller's haptics are routed (no rumble all session in Unicorn Overlord) Vibration handles before a controller's haptics are routed (a game that asks once at startup lost every value) Oct 26, 2026
seedds added a commit that referenced this pull request Oct 26, 2026
GetVibrationDeviceHandles used routed haptics availability to decide whether
handles existed. Games that cache this answer at startup could retain an empty
answer after a controller connected. Return handles for a connected npad style
when rumble is enabled and an output sink is installed; check routed outputs
when values are sent, keeping the existing permission and lifecycle behavior.

Include the PR's rumble diagnostics, count unroutable values individually in
mixed batches, and protect aggregate counters across game threads. Correct the
code comment to describe Unicorn Overlord's observed empty handles and zero
values without claiming restored physical rumble.

Add regressions for cached startup handles delivering a nonzero value after
routing, diagnostic totals and concurrent sends. Include HID in the existing
ThreadSanitizer target and record the mechanism in the service reference.

Checked with GAME=010069401ADB8000: full host suite, 73 HID checks, audio and HID
ThreadSanitizer checks, docs checks, Mac host build, and iOS compilation
(133 files). Physical rumble and iOS runtime remain untested. Broader tool
validation is incomplete because Capstone is missing and iconutil failed.

Co-authored-by: parsifal295 <130349765+parsifal295@users.noreply.github.com>
@seedds

seedds commented Oct 26, 2026

Copy link
Copy Markdown
Owner

Thanks @parsifal295. I confirmed the startup handle bug with a regression that fails on the original code: handles requested before haptics routing must remain usable when an output is routed later. The fixed test delivers a nonzero value through those cached handles.

Landed on main in 2db12f7, with you credited as co-author. This includes your handle fix, diagnostics and documentation, plus two corrections to the logger: count each unroutable value in mixed batches, and synchronize shared counters. ThreadSanitizer reproduced the counter race before correction and passes afterward. The comment now describes the observed empty handles without claiming restored physical rumble in Unicorn Overlord.

Validation passed: full host suite, 73 HID checks, audio/HID ThreadSanitizer checks, docs checks, Mac host build and iOS source compilation (133 files). Physical controller rumble and iOS runtime remain untested; broader tool validation was incomplete due to missing Capstone and an iconutil failure.

Closing this PR because the corrected implementation is now on main. Thanks for the investigation and contribution.

@seedds seedds closed this Oct 26, 2026
Know-It-All-Brother pushed a commit to Know-It-All-Brother/nxnative that referenced this pull request Nov 9, 2026
GetVibrationDeviceHandles used routed haptics availability to decide whether
handles existed. Games that cache this answer at startup could retain an empty
answer after a controller connected. Return handles for a connected npad style
when rumble is enabled and an output sink is installed; check routed outputs
when values are sent, keeping the existing permission and lifecycle behavior.

Include the PR's rumble diagnostics, count unroutable values individually in
mixed batches, and protect aggregate counters across game threads. Correct the
code comment to describe Unicorn Overlord's observed empty handles and zero
values without claiming restored physical rumble.

Add regressions for cached startup handles delivering a nonzero value after
routing, diagnostic totals and concurrent sends. Include HID in the existing
ThreadSanitizer target and record the mechanism in the service reference.

Checked with GAME=010069401ADB8000: full host suite, 73 HID checks, audio and HID
ThreadSanitizer checks, docs checks, Mac host build, and iOS compilation
(133 files). Physical rumble and iOS runtime remain untested. Broader tool
validation is incomplete because Capstone is missing and iconutil failed.

Co-authored-by: parsifal295 <130349765+parsifal295@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants