Skip to content

Detect Switch 2 Pro Controller and support GL/GR paddles - #1

Merged
JoeGeC merged 1 commit into
mainfrom
fix/pro-controller-mapping
Sep 2, 2026
Merged

Detect Switch 2 Pro Controller and support GL/GR paddles#1
JoeGeC merged 1 commit into
mainfrom
fix/pro-controller-mapping

Conversation

@JoeGeC

@JoeGeC JoeGeC commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Problem

A Switch 2 Pro Controller was reported as behaving like a sideways Left Joy-Con:

  • D-Pad rotated: up→left, left→down, down→right, right→up
  • Left stick rotated the same way
  • Right stick not mapped at all
  • Back paddles (GL/GR) not mapped to anything
  • Everything else (XYAB, L/ZL/R/ZR, ±, Home, Capture, C, stick clicks) fine

Root cause

BleScanner only recognised the Joy-Con product bytes (0x67 Left / 0x66 Right), so a Pro Controller fell through to Side.UNKNOWN. PlayerStateResolver then placed it in the single-Left-Joy-Con slot (left set, right null), and GamepadState.from() takes its sideways branch for that shape — applying SidewaysMapper's 90° rotation to the stick + D-Pad and pinning the right stick to centre. Every symptom follows from that one misclassification (the untouched buttons pass straight through, which is why they worked).

Fix

Detection (the core fix):

  • Map product byte 0x69 (Pro Controller 2, PID 0x2069) → Side.PRO. The advertisement carries the little-endian USB/BLE product ID at manufacturer-data bytes [5..6], the same scheme as the hardware-confirmed Joy-Con values. Once tagged Side.PRO, the existing pipeline fills both player slots (hasFullController) → no rotation, and PacketParser decodes the right stick from offset 0x0D. This resolves the D-Pad, left stick, and right stick.

GL/GR back paddles:

  • Parse report byte 0x07 (GR = bit 0, GL = bit 1) in PacketParser.
  • Add GL/GR to JoyconButton — this also makes them selectable remap sources for a Pro (the mapping screen enumerates JoyconButton.entries for DUAL).
  • Expose them as HID buttons 15/16 (ReportMapper + the UhidRelay report descriptor, reusing the two former padding bits).
  • Show them in the Pro controller UI so their presses are visible.

Delivery / tests:

  • CI now uploads the debug APK as an artifact (app-debug) — it was being built but never published.
  • Adds PacketParserTest covering the PRO stick offsets and the paddle decode.

Testing notes for the reporter (I don't have a Pro Controller)

  1. 0x69 is cross-validated from RE sources but not hardware-confirmed by us. This build's test is the confirmation. If the Pro still isn't detected, a logcat filtered on Joycon2 during pairing will show the real advertisement byte (Adv … mfg=… is already logged) — please capture and share it.
  2. GL vs GR assignment (which physical paddle is which) is per the reference dissector — worth confirming; it's a trivial swap if reversed.
  3. GL/GR in Eden specifically are parsed, visible in-app, delivered over HID, and remappable — but the in-game Eden binding needs the Android keycode that HID buttons 15/16 land on, which is kernel/device-dependent and not yet captured. Deferred as a follow-up.

The debug APK is downloadable from this PR's CI run → Artifacts → app-debug.

🤖 Generated with Claude Code

The Pro Controller was never identified as Side.PRO: BleScanner only
recognised the Joy-Con product bytes (0x67/0x66), so a Pro fell through
to Side.UNKNOWN. That routed it into the single-Left-Joy-Con slot, where
GamepadState.from applies the sideways 90 degree rotation and pins the
right stick to centre — matching the reported symptoms (rotated D-Pad
and left stick, dead right stick, working face/shoulder/system buttons).

Detection:
- Map product byte 0x69 (PID 0x2069) to Side.PRO. Once tagged PRO the
  existing pipeline fills both player slots (hasFullController), so no
  rotation is applied and the right stick decodes from offset 0x0D.

GL/GR back paddles:
- Parse report byte 0x07 (GR = bit 0, GL = bit 1) in PacketParser.
- Add GL/GR to JoyconButton, which also makes them selectable remap
  sources for a Pro (ControllerMappingScreen enumerates the entries).
- Expose them as HID buttons 15/16 (ReportMapper + UhidRelay descriptor,
  reusing the two former padding bits).
- Show them in the Pro controller UI.

Eden in-game binding for GL/GR is deferred: the Android keycode that HID
buttons 15/16 land on is kernel/device-dependent and not yet captured.

CI now uploads the debug APK as an artifact (it was built but never
published). Adds PacketParserTest covering the PRO stick offsets and the
paddle decode.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JoeGeC
JoeGeC merged commit fc1b981 into main Sep 2, 2026
1 check passed
@JoeGeC
JoeGeC deleted the fix/pro-controller-mapping branch September 2, 2026 16:25
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.

1 participant