Skip to content

host/haptics: drive Pro Controllers through their rumble report - #2607

Open
victormlourenco wants to merge 1 commit into
seedds:mainfrom
victormlourenco:host/pro-controller-rumble
Open

victormlourenco wants to merge 1 commit into
seedds:mainfrom
victormlourenco:host/pro-controller-rumble

Conversation

@victormlourenco

Copy link
Copy Markdown

What

On the Mac, a controller that GameController reports as a Switch Pro Controller now rumbles through the controller's own rumble report 0x10, as SDL's hidapi driver does, instead of through Core Haptics.

Why

An 8BitDo pad in Switch mode (HID 057E / 2009, productCategory "Switch Pro Controller") never rumbled through Core Haptics on macOS 27.2. The log showed no error: the handle engines had no advanced players (NSCocoaErrorDomain 4097), so both motors were merged onto one Handles engine, and its plain players started and played. The pad still didn't vibrate. A small probe that wrote report 0x10 straight to the same pad made it vibrate, with or without first sending subcommand 0x48 (enable vibration). Why gamecontrollerd's output doesn't reach the pad is still open.

How

  • pro_route (dm/host/haptics_apple.m) takes a free 057E / 2009 HID device that accepts a neutral report. The neutral report test skips the dead second entry IOKit can keep after a long Bluetooth disconnect (Mac: one Bluetooth Pro Controller comes back as two HID players after it reconnects, and Ocarina of Time reopens the controller applet in a loop (1,671 times), no input #2237). Log line: rumble through the Pro Controller rumble report (<transport>).
  • The registry lookup the DualShock 4 route used is now hid_take, shared by both routes. The DualShock 4 route behaves the same; t_haptics_apple still covers it.
  • Each of the game's two actuators keeps its own high and low band at the game's frequencies, encoded as HD rumble (pad_pro_rumble_side / pad_pro_rumble in dm/host/pad_pro.h, per dekuNukem's rumble_data_table.md). Rumble strength and Rumble cutoff apply as on the other routes.
  • A rumble that is playing is sent again every 30 ms, as SDL does. A stop or a loss of focus sends the neutral side.
  • Docs: a new entry, "Pro Controller rumble through its rumble report", in docs/reference/services.md; the symptom index regenerated; a line under "Found on this game" in the Ocarina of Time note.

Checked

  • In game: The Legend of Zelda: Ocarina of Time (v131072, Mac app) rumbles with an 8BitDo pad in Switch mode over Bluetooth, over USB and through 8BitDo's 2.4 GHz receiver, on macOS 27.2.
  • Host unit tests: make -C dm/host/tests GAME=0400486024DEC000 run passes. t_pad_pro gained encoder checks: the neutral side, the strongest full-amplitude side 00 C9 40 72, the frequency clamps, NaN input, the amplitude thresholds and their monotonicity, and the report layout. t_haptics_apple and t_haptics pass.
  • Docs: dm/tools/tests/test_docs.py passes.
  • C lint: dm/tools/lint_c.py compdb and tidy report no findings in the changed files. The 8 findings above the baseline are in files this PR doesn't touch (dm/gfx/tests/t_upload_src.m, t_vk_swapchain_life.m, t_wline.m, t_zero_depth.m, and dm/gfx/vk/hle_vk.m asking for a baseline shrink).
  • regress.py: not run. The change only touches Mac controller rumble, which the boot, shader and frame checks don't exercise.

Not checked

  • A genuine Nintendo Pro Controller, which rumbled through Core Haptics before and now takes this route too.
  • Two Pro Controllers at once. GameController doesn't name a controller's HID device, so two that connect together may swap their rumble, as with the DualShock 4.

On the Mac, a controller GameController calls a Switch Pro Controller is
now driven through its own rumble report 0x10, as SDL's hidapi driver
does, instead of Core Haptics. An 8BitDo pad in Switch mode (057E / 2009)
never rumbled through Core Haptics on macOS 27.2: the handle engines were
refused advanced players, the merged Handles engine started and its plain
players played without an error, and the pad stayed still. A probe that
wrote report 0x10 to the same pad made it vibrate, with or without first
sending subcommand 0x48. Why gamecontrollerd's output does not reach the
pad is open.

pro_route takes a free 057E / 2009 HID device that accepts a neutral
report; that skips the dead second entry IOKit can keep after a long
Bluetooth disconnect (issue seedds#2237). The registry lookup is now hid_take,
shared with the DualShock 4 route. Each of the game's two actuators keeps
its own high and low band at the game's frequencies, encoded as HD rumble
(pad_pro_rumble_side in pad_pro.h, covered by t_pad_pro), with Rumble
strength and Rumble cutoff applied. A rumble that is playing is sent
again every 30 ms, as SDL does, and a stop or loss of focus sends the
neutral side.

Checked: Ocarina of Time (v131072) rumbles with the 8BitDo pad over
Bluetooth, over USB and through 8BitDo's 2.4 GHz receiver; the host unit
tests pass. Not checked: a genuine Pro Controller, which rumbled through
Core Haptics before, and two Pro Controllers at once.
@github-actions github-actions Bot added host The Horizon host: SVCs, services, threads, memory (dm/host) docs Documentation game: 0400486024DEC000 A game labels Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation game: 0400486024DEC000 A game host The Horizon host: SVCs, services, threads, memory (dm/host)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants