mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
refactor(input): share gamepad map between launcher and gameplay
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
-- Shared gamepad + raw joystick button tables for launcher and gameplay.
|
||||
-- Hardware-measured NX overrides live in NX_* tables (see docs/switch-development.md).
|
||||
|
||||
local GamepadMap = {}
|
||||
|
||||
-- LÖVE SDL game-controller mapping (D-pad / face / menu).
|
||||
GamepadMap.DEFAULT_GAMEPAD_BINDINGS = {
|
||||
dpup = "up", dpdown = "down", dpleft = "left", dpright = "right",
|
||||
a = "a", b = "b",
|
||||
start = "start", back = "select",
|
||||
}
|
||||
|
||||
-- Generic SDL joysticks without a game-controller DB entry (Linux handhelds).
|
||||
GamepadMap.RAW_BUTTON_BINDINGS = {
|
||||
[1] = "a", [2] = "b",
|
||||
[7] = "select", [8] = "start", [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",
|
||||
}
|
||||
|
||||
-- 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
|
||||
end
|
||||
|
||||
local function nxActive()
|
||||
if GamepadMap._forceNXForTests then return true end
|
||||
if love and love._os == "NX" then return true end
|
||||
if love and love.system and love.system.getOS() == "NX" then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function GamepadMap.mapGamepadButton(button)
|
||||
return GamepadMap.DEFAULT_GAMEPAD_BINDINGS[button]
|
||||
end
|
||||
|
||||
function GamepadMap.mapRawButton(index)
|
||||
if nxActive() and GamepadMap.NX_RAW_BUTTON_BINDINGS then
|
||||
local nx = GamepadMap.NX_RAW_BUTTON_BINDINGS[index]
|
||||
if nx then return nx end
|
||||
end
|
||||
return GamepadMap.RAW_BUTTON_BINDINGS[index]
|
||||
end
|
||||
|
||||
function GamepadMap.mapRawToGamepadButton(index)
|
||||
if nxActive() and GamepadMap.NX_RAW_TO_GAMEPAD_BUTTON then
|
||||
local nx = GamepadMap.NX_RAW_TO_GAMEPAD_BUTTON[index]
|
||||
if nx then return nx end
|
||||
end
|
||||
return GamepadMap.RAW_TO_GAMEPAD_BUTTON[index]
|
||||
end
|
||||
|
||||
return GamepadMap
|
||||
+7
-22
@@ -1,6 +1,8 @@
|
||||
-- Input abstraction: maps keyboard to Game Boy buttons.
|
||||
-- `down` = held this frame; `pressed` = edge, consumed per fixed step.
|
||||
|
||||
local GamepadMap = require("src.core.GamepadMap")
|
||||
|
||||
local Input = {}
|
||||
|
||||
local DEFAULT_BINDINGS = {
|
||||
@@ -22,31 +24,12 @@ local DEFAULT_BINDINGS = {
|
||||
-- keys that map to "start" but also to "a" would conflict; keep Enter = a,
|
||||
-- Escape = start for desktop friendliness.
|
||||
|
||||
-- LÖVE's standard gamepad mapping (SDL game controller DB), consistent
|
||||
-- across Xbox/PlayStation/generic controllers on desktop and mobile. Some
|
||||
-- third-party pads report their own SDL mapping for a given physical
|
||||
-- button (e.g. Select/Back/View on off-brand XInput pads), which is what
|
||||
-- src/ui/BindingsMenu.lua's rebinding is for -- see applyBindings below.
|
||||
local DEFAULT_GAMEPAD_BINDINGS = {
|
||||
dpup = "up", dpdown = "down", dpleft = "left", dpright = "right",
|
||||
a = "a", b = "b",
|
||||
start = "start", back = "select",
|
||||
}
|
||||
|
||||
-- left-stick deadzones: press past STICK_ON, release once back under
|
||||
-- STICK_OFF. The gap (hysteresis) stops the direction from flickering
|
||||
-- while the stick sits near the threshold.
|
||||
local STICK_ON = 0.5
|
||||
local STICK_OFF = 0.3
|
||||
|
||||
-- Generic SDL joysticks expose the left stick as the first two numbered
|
||||
-- axes and the D-pad as a hat. This is common on Linux handhelds whose
|
||||
-- controller has no game-controller database entry.
|
||||
local RAW_BUTTON_BINDINGS = {
|
||||
[1] = "a", [2] = "b",
|
||||
[7] = "select", [8] = "start", [9] = "select", [10] = "start",
|
||||
}
|
||||
|
||||
local HAT_DIRECTIONS = {
|
||||
u = { "up" }, d = { "down" }, l = { "left" }, r = { "right" },
|
||||
lu = { "left", "up" }, ru = { "right", "up" },
|
||||
@@ -68,7 +51,9 @@ end
|
||||
function Input:applyBindings(overlay)
|
||||
local keys, pads = {}, {}
|
||||
for key, action in pairs(DEFAULT_BINDINGS) do keys[key] = action end
|
||||
for button, action in pairs(DEFAULT_GAMEPAD_BINDINGS) do pads[button] = action end
|
||||
for button, action in pairs(GamepadMap.DEFAULT_GAMEPAD_BINDINGS) do
|
||||
pads[button] = action
|
||||
end
|
||||
for actionId, binding in pairs(overlay or {}) do
|
||||
if type(binding) == "table" then
|
||||
if binding.key then keys[binding.key] = actionId end
|
||||
@@ -195,12 +180,12 @@ function Input:gamepadreleased(joystick, button)
|
||||
end
|
||||
|
||||
function Input:joystickpressed(joystick, button)
|
||||
local btn = RAW_BUTTON_BINDINGS[button]
|
||||
local btn = GamepadMap.mapRawButton(button)
|
||||
if btn then press(self, btn, "joy:" .. button) end
|
||||
end
|
||||
|
||||
function Input:joystickreleased(joystick, button)
|
||||
local btn = RAW_BUTTON_BINDINGS[button]
|
||||
local btn = GamepadMap.mapRawButton(button)
|
||||
if btn then release(self, btn, "joy:" .. button) end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
local GameVersion = require("src.core.GameVersion")
|
||||
local GamepadMap = require("src.core.GamepadMap")
|
||||
local Strings = require("src.core.Strings")
|
||||
local HostShell = require("src.core.HostShell")
|
||||
local Platform = require("src.core.Platform")
|
||||
@@ -1547,11 +1548,13 @@ function RomImporter:gamepadaxis(_, axis, value)
|
||||
end
|
||||
|
||||
function RomImporter:joystickpressed(joystick, button)
|
||||
if button == 1 then self:gamepadpressed(joystick, "a") end
|
||||
local padButton = GamepadMap.mapRawToGamepadButton(button)
|
||||
if padButton then self:gamepadpressed(joystick, padButton) end
|
||||
end
|
||||
|
||||
function RomImporter:joystickreleased(joystick, button)
|
||||
if button == 1 then self:gamepadreleased(joystick, "a") end
|
||||
local padButton = GamepadMap.mapRawToGamepadButton(button)
|
||||
if padButton then self:gamepadreleased(joystick, padButton) end
|
||||
end
|
||||
|
||||
function RomImporter:joystickaxis(joystick, axis, value)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
-- Shared gamepad/raw map: launcher and gameplay use identical converters (SWNX-10/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 check = T.check
|
||||
local eq = T.eq
|
||||
|
||||
local GamepadMap = require("src.core.GamepadMap")
|
||||
local Input = require("src.core.Input")
|
||||
local RomImporter = require("src.import.RomImporter")
|
||||
|
||||
-- Gamepad names map to GB actions.
|
||||
eq(GamepadMap.mapGamepadButton("a"), "a", "gamepad A -> GB A")
|
||||
eq(GamepadMap.mapGamepadButton("back"), "select", "gamepad back -> select")
|
||||
eq(GamepadMap.mapGamepadButton("dpup"), "up", "gamepad d-pad up")
|
||||
|
||||
-- Generic raw indices (Linux handheld fallback).
|
||||
eq(GamepadMap.mapRawButton(1), "a", "raw #1 -> A")
|
||||
eq(GamepadMap.mapRawButton(8), "start", "raw #8 -> start")
|
||||
eq(GamepadMap.mapRawToGamepadButton(2), "b", "raw #2 routes to gamepad b")
|
||||
|
||||
-- Input and RomImporter agree on the same GB action for a raw press.
|
||||
Input:init()
|
||||
Input:joystickpressed(nil, 1)
|
||||
Input:step()
|
||||
check(Input:isDown("a"), "Input raw #1 holds A")
|
||||
|
||||
local importer = setmetatable({
|
||||
_padCursor = { x = 0, y = 0 }, _padCursorActive = false,
|
||||
_padAxis = { leftx = 0, lefty = 0, righty = 0 },
|
||||
_padDir = {}, _rawHatDirs = {}, _padInited = true,
|
||||
}, RomImporter)
|
||||
local clicked = false
|
||||
function importer:mousepressed(_, _, button)
|
||||
clicked = button == 1
|
||||
end
|
||||
importer:joystickpressed(nil, 1)
|
||||
check(clicked, "RomImporter raw #1 clicks via shared map (not hardcoded-only)")
|
||||
|
||||
importer:joystickpressed(nil, 2)
|
||||
check(importer._padDir.dpright == nil,
|
||||
"raw #2 maps to B, not spurious d-pad")
|
||||
|
||||
T.finish()
|
||||
Reference in New Issue
Block a user