Skip to content

Support the NSO GameCube controller - #30

Open
thisishuey wants to merge 1 commit into
JoeGeC:mainfrom
thisishuey:add-gamecube-controller-support
Open

thisishuey wants to merge 1 commit into
JoeGeC:mainfrom
thisishuey:add-gamecube-controller-support

Conversation

@thisishuey

Copy link
Copy Markdown

The NSO GameCube controller advertises product ID 0x2073, which the scanner didn't know. It connected as an unknown side, and a lone unknown controller is treated as a sideways Joy-Con. So its stick and D-pad were turned 90 degrees, its C-stick was never decoded, L + R didn't assign it, and it played as whichever Joy-Con the first button pressed suggested.

The scanner now names a ControllerModel from the product ID. The GameCube controller reports in the Pro Controller's layout, so it's parsed and assigned as one: one body, both sticks.

It shares nothing else with the Pro. For button mapping it's a body of its own, beside a pair and a lone Joy-Con, with its own layouts and saved bindings. Its default puts Z on its Z button (reported as ZR) and the triggers on L/R. The mapping editor offers only the buttons it has, with ZR shown as Z. Dolphin setup configures a GameCube player and still skips Pro players, as before. Joy-Con pairs and Pro Controllers keep their layouts exactly as they were.

Each controller card now has a Controller type menu: Auto, Pro Controller, Left or Right Joy-Con. This covers any controller whose advertisement names no type or the wrong one. The choice is stored per BLE address, which captures show is a fixed public address, so it applies again on reconnect. On a connected controller it takes effect at once: the parser reads the new side's sticks, and stick calibration starts over. A controller assigned to a player is unassigned first, since its slot was checked against the old type.

Analog L/R now reach Dolphin. The controller reports trigger travel at 0x3C/0x3D. TriggerCalibrator maps it from the factory zero (SPI 0x013140) to the first stop, where analog travel ends, and drives the virtual gamepad's trigger bytes with it. Dolphin setup binds L-Analog and R-Analog to those axes and keeps the click at the second stop on L/R. Every other controller keeps ZL/ZR on the trigger bytes.

On this controller ZL and Z also move off BUTTON_L2/R2 and onto the stick clicks, which it doesn't have. On a Retroid Pocket Nova those keys followed the trigger axes, so pulling R pressed Z and Z itself did nothing. With the move, both work.

At connect it also reads its factory stick calibration (0x0130A8 for the main stick, 0x0130E8 for the C-stick, decoded as the Linux and SDL Switch 2 drivers do), so its sticks start centred with their full range. Learning still applies on top, and takes over when the flash is unset or implausible. Only the GameCube controller's values have been checked against its sticks, so Joy-Con 2 and Pro Controllers aren't read and keep learning theirs.

Tested on a Retroid Pocket Nova (Android 13), with three GameCube controllers connected at once as players 1–3 in Dolphin. Recognition, L + R assign, both sticks, the D-pad, every button, analog L/R with a separate click, and the type menu all behave. Packet captures from the three controllers back the offsets and calibration values in protocol.md. Four controllers and Android 14+ are untested.

Rumble is left out: the app has no rumble path yet.

Closes #27

The NSO GameCube controller advertises product ID 0x2073, which the
scanner didn't know. It connected as an unknown side, and a lone unknown
controller is treated as a sideways Joy-Con. So its stick and D-pad were
turned 90 degrees, its C-stick was never decoded, L + R didn't assign
it, and it played as whichever Joy-Con the first button pressed
suggested.

The scanner now names a ControllerModel from the product ID. The
GameCube controller reports in the Pro Controller's layout, so it's
parsed and assigned as one: one body, both sticks.

It shares nothing else with the Pro. For button mapping it's a body of
its own, beside a pair and a lone Joy-Con, with its own layouts and
saved bindings. Its default puts Z on its Z button (reported as ZR) and
the triggers on L/R. The mapping editor offers only the buttons it has,
with ZR shown as Z. Dolphin setup configures a GameCube player and still
skips Pro players, as before. Joy-Con pairs and Pro Controllers keep
their layouts exactly as they were.

Each controller card now has a Controller type menu: Auto, Pro
Controller, Left or Right Joy-Con. This covers any controller whose
advertisement names no type or the wrong one. The choice is stored per
BLE address, which captures show is a fixed public address, so it
applies again on reconnect. On a connected controller it takes effect at
once: the parser reads the new side's sticks, and stick calibration
starts over. A controller assigned to a player is unassigned first,
since its slot was checked against the old type.

Analog L/R now reach Dolphin. The controller reports trigger travel at
0x3C/0x3D. TriggerCalibrator maps it from the factory zero (SPI
0x013140) to the first stop, where analog travel ends, and drives the
virtual gamepad's trigger bytes with it. Dolphin setup binds L-Analog
and R-Analog to those axes and keeps the click at the second stop on
L/R. Every other controller keeps ZL/ZR on the trigger bytes.

On this controller ZL and Z also move off BUTTON_L2/R2 and onto the
stick clicks, which it doesn't have. On a Retroid Pocket Nova those keys
followed the trigger axes, so pulling R pressed Z and Z itself did
nothing. With the move, both work.

At connect it also reads its factory stick calibration (0x0130A8 for the
main stick, 0x0130E8 for the C-stick, decoded as the Linux and SDL
Switch 2 drivers do), so its sticks start centred with their full range.
Learning still applies on top, and takes over when the flash is unset or
implausible. Only the GameCube controller's values have been checked
against its sticks, so Joy-Con 2 and Pro Controllers aren't read and
keep learning theirs.

Tested on a Retroid Pocket Nova (Android 13), with three GameCube
controllers connected at once as players 1–3 in Dolphin. Recognition,
L + R assign, both sticks, the D-pad, every button, analog L/R with a
separate click, and the type menu all behave. Packet captures from the
three controllers back the offsets and calibration values in
protocol.md. Four controllers and Android 14+ are untested.

Rumble is left out: the app has no rumble path yet.

Closes JoeGeC#27

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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.

Ability to manually assign NSO Gamecube Controller as Pro Controller via touch menu

1 participant