fix(input): apply Switch-measured controller fallback

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Andrew Quenehen
2026-08-01 03:53:27 -03:00
parent 361d4b81df
commit 560ebc5997
3 changed files with 61 additions and 4 deletions
+23
View File
@@ -211,3 +211,26 @@ scripts/build_switch.sh --loose
shasum -a 256 .bazinga/work/game.love
```
## Controller input mapping (NX)
Measured on Switch OLED (`feat/switch-nx`, love-nx `11.5-nx1`, 1280×720). Both `joystickpressed` and `gamepadpressed` fire for Joy-Con; prefer the gamepad path when `joystick:isGamepad()` is true.
| Path | Control | Mapping |
| ---- | ------- | ------- |
| `gamepadpressed` | D-pad / left stick | move (via `GamepadMap.DEFAULT_GAMEPAD_BINDINGS`) |
| `gamepadpressed` | `a` / `b` | GB A / B |
| `gamepadpressed` | `start` / `back` | Start / Select |
| `joystickpressed` (raw) | `#1` Nintendo B | GB A |
| `joystickpressed` (raw) | `#2` Nintendo A | GB B |
| `joystickpressed` (raw) | `#3` Y | GB B (measured) |
| `joystickpressed` (raw) | `#4` X | GB A (measured) |
| `joystickpressed` (raw) | `#9` / `#10` | Select / Start ( / +) |
Implementation: `src/core/GamepadMap.lua` (`NX_RAW_*` tables). Launcher (`RomImporter`) and gameplay (`Input`) share the same converter.
**Opt-in diagnostics:** create an empty `switch-debug.txt` in the save directory; events flush to `switch.log` at ≤1 Hz with build identity (no ROM/save bytes).
**Hardware re-test:** P0-07/08 Joy-Con launcher + naming screen — pending operator after T15 software (T16).
**Suspend/resume audio:** after resume, chip music is stopped to avoid duplicate streams; confirm on hardware during P0-09/10 (T19).
+16 -4
View File
@@ -16,16 +16,28 @@ GamepadMap.RAW_BUTTON_BINDINGS = {
[7] = "select", [8] = "start", [9] = "select", [10] = "start",
}
-- Switch OLED probe 2026-08-01: love.joystickpressed indices (1-based).
-- Gamepad path still preferred when isGamepad(); raw covers the rest.
GamepadMap.NX_RAW_BUTTON_BINDINGS = {
[1] = "a", [2] = "b",
[3] = "b", [4] = "a",
[9] = "select", [10] = "start",
}
-- Raw index -> gamepad button name for RomImporter routing.
GamepadMap.RAW_TO_GAMEPAD_BUTTON = {
[1] = "a", [2] = "b",
[7] = "back", [8] = "start", [9] = "back", [10] = "start",
}
GamepadMap.NX_RAW_TO_GAMEPAD_BUTTON = {
[1] = "a", [2] = "b",
[3] = "y", [4] = "x",
[9] = "back", [10] = "start",
}
-- Test hook: force NX raw tables without stubbing love.
GamepadMap._forceNXForTests = false
GamepadMap.NX_RAW_BUTTON_BINDINGS = nil
GamepadMap.NX_RAW_TO_GAMEPAD_BUTTON = nil
function GamepadMap._setForceNXForTests(v)
GamepadMap._forceNXForTests = not not v
@@ -43,7 +55,7 @@ function GamepadMap.mapGamepadButton(button)
end
function GamepadMap.mapRawButton(index)
if nxActive() and GamepadMap.NX_RAW_BUTTON_BINDINGS then
if nxActive() then
local nx = GamepadMap.NX_RAW_BUTTON_BINDINGS[index]
if nx then return nx end
end
@@ -51,7 +63,7 @@ function GamepadMap.mapRawButton(index)
end
function GamepadMap.mapRawToGamepadButton(index)
if nxActive() and GamepadMap.NX_RAW_TO_GAMEPAD_BUTTON then
if nxActive() then
local nx = GamepadMap.NX_RAW_TO_GAMEPAD_BUTTON[index]
if nx then return nx end
end
+22
View File
@@ -0,0 +1,22 @@
-- NX raw fallback indices measured on OLED hardware (SWNX-11).
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local T = require("tests.harness")
local eq = T.eq
local GamepadMap = require("src.core.GamepadMap")
GamepadMap._setForceNXForTests(true)
-- Phase 0 probe: Y→#3, X→#4; Nintendo B/A at #1/#2.
eq(GamepadMap.mapRawButton(3), "b", "NX raw Y (#3) maps to GB B")
eq(GamepadMap.mapRawButton(4), "a", "NX raw X (#4) maps to GB A")
eq(GamepadMap.mapRawToGamepadButton(3), "y", "NX raw #3 routes to gamepad y")
eq(GamepadMap.mapRawToGamepadButton(4), "x", "NX raw #4 routes to gamepad x")
eq(GamepadMap.mapRawButton(9), "select", "NX minus (#9) -> select")
eq(GamepadMap.mapRawButton(10), "start", "NX plus (#10) -> start")
GamepadMap._setForceNXForTests(false)
T.finish()