Merge feat/l3-r3-stick-binds: first-class L3/R3 stick-click binds

Controller: l3=leftstick / r3=rightstick defaults (map rows were missing
entirely). Keyboard: T/Y defaults. Beetle oracle keyboard: T/Y. Shipped
input.ini templates + README updated. Validated on Ape Escape (user-
confirmed L3/R3 on real pad).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Matthew Stanley
2026-07-10 11:09:50 -07:00
5 changed files with 31 additions and 10 deletions
+2
View File
@@ -187,6 +187,7 @@ generated C is optimized. Game projects generate their own
| Triangle | A |
| L1 / R1 | Q / W |
| L2 / R2 | E / R |
| L3 / R3 (stick clicks) | T / Y |
| Start | Enter |
| Select | Right Shift |
| Turbo | Tab (hold) |
@@ -205,6 +206,7 @@ Xbox-style controller defaults are enabled when a controller is connected:
| Triangle | Y |
| L1 / R1 | LB / RB |
| L2 / R2 | LT / RT |
| L3 / R3 | Left / right stick click |
| Start | Menu |
| Select | View / Back |
+4
View File
@@ -26,6 +26,8 @@ int beetle_debug_server_get_input_override(void);
}
#define PAD_SELECT (1 << 0)
#define PAD_L3 (1 << 1)
#define PAD_R3 (1 << 2)
#define PAD_START (1 << 3)
#define PAD_UP (1 << 4)
#define PAD_RIGHT (1 << 5)
@@ -57,6 +59,8 @@ static uint16_t pad_from_keyboard(void) {
if (keys[SDL_SCANCODE_W]) b &= ~PAD_R1;
if (keys[SDL_SCANCODE_E]) b &= ~PAD_L2;
if (keys[SDL_SCANCODE_R]) b &= ~PAD_R2;
if (keys[SDL_SCANCODE_T]) b &= ~PAD_L3; /* stick clicks: same keys */
if (keys[SDL_SCANCODE_Y]) b &= ~PAD_R3; /* as psx-runtime defaults */
return b;
}
+18 -7
View File
@@ -903,11 +903,15 @@ static void sdl_audio_update(int turbo_active) {
}
/* PS1 digital pad button bits (active-low: 0=pressed, 1=released).
* Bit 0 = SELECT, Bit 3 = START, Bit 4 = UP, Bit 5 = RIGHT,
* Bit 6 = DOWN, Bit 7 = LEFT, Bit 8 = L2, Bit 9 = R2,
* Bit 10 = L1, Bit 11 = R1, Bit 12 = TRIANGLE, Bit 13 = CIRCLE,
* Bit 14 = CROSS, Bit 15 = SQUARE */
* Bit 0 = SELECT, Bit 1 = L3, Bit 2 = R3, Bit 3 = START,
* Bit 4 = UP, Bit 5 = RIGHT, Bit 6 = DOWN, Bit 7 = LEFT,
* Bit 8 = L2, Bit 9 = R2, Bit 10 = L1, Bit 11 = R1,
* Bit 12 = TRIANGLE, Bit 13 = CIRCLE, Bit 14 = CROSS, Bit 15 = SQUARE.
* L3/R3 (stick clicks) exist on a DualShock only; the wire reports them like
* Beetle's dualshock.cpp does — straight from the button word, no mode mask. */
#define PAD_SELECT (1 << 0)
#define PAD_L3 (1 << 1)
#define PAD_R3 (1 << 2)
#define PAD_START (1 << 3)
#define PAD_UP (1 << 4)
#define PAD_RIGHT (1 << 5)
@@ -942,7 +946,7 @@ struct PsxButtonMap {
static int controller_device_index = 0;
static int controller_deadzone = 12000;
static std::array<PsxButtonMap, 14> controller_map = {{
static std::array<PsxButtonMap, 16> controller_map = {{
{ PAD_UP, "up", {} },
{ PAD_DOWN, "down", {} },
{ PAD_LEFT, "left", {} },
@@ -955,6 +959,8 @@ static std::array<PsxButtonMap, 14> controller_map = {{
{ PAD_R1, "r1", {} },
{ PAD_L2, "l2", {} },
{ PAD_R2, "r2", {} },
{ PAD_L3, "l3", {} },
{ PAD_R3, "r3", {} },
{ PAD_START, "start", {} },
{ PAD_SELECT, "select", {} },
}};
@@ -1099,6 +1105,8 @@ static void set_default_controller_mapping(void) {
set_sources("r1", "rightshoulder");
set_sources("l2", "lefttrigger");
set_sources("r2", "righttrigger");
set_sources("l3", "leftstick");
set_sources("r3", "rightstick");
set_sources("start", "start");
set_sources("select", "back");
}
@@ -1107,7 +1115,8 @@ static std::string default_input_ini_text(void) {
return
"; PSXRecomp input mapping. PSX buttons are active when any listed source is pressed.\n"
"; Sources use SDL/Xbox names: a,b,x,y,back,start,leftshoulder,rightshoulder,\n"
"; lefttrigger,righttrigger,dpup,dpdown,dpleft,dpright,leftx-/leftx+/lefty-/lefty+.\n"
"; lefttrigger,righttrigger,leftstick,rightstick (stick clicks -> L3/R3),\n"
"; dpup,dpdown,dpleft,dpright,leftx-/leftx+/lefty-/lefty+.\n"
"\n"
"[controller]\n"
"enabled = true\n"
@@ -1127,6 +1136,8 @@ static std::string default_input_ini_text(void) {
"r1 = rightshoulder\n"
"l2 = lefttrigger\n"
"r2 = righttrigger\n"
"l3 = leftstick\n"
"r3 = rightstick\n"
"start = start\n"
"select = back\n";
}
@@ -1311,7 +1322,7 @@ static bool controller_source_pressed_h(SDL_GameController* h, const ControllerS
/* Keyboard -> PSX button word for `player` (1 or 2), via the configurable
* keybinds.ini map (psx_keybinds). Defaults reproduce the old hardcoded layout
* (arrows=d-pad, X/S/Z/A=Cross/Circle/Square/Triangle, Q/W/E/R=L1/R1/L2/R2,
* Return=Start, RShift=Select), so out-of-the-box behaviour is unchanged. */
* Return=Start, RShift=Select) plus T/Y=L3/R3 stick clicks. */
static uint16_t pad_from_keyboard(int player) {
const Uint8* keys = SDL_GetKeyboardState(NULL);
return psx_keybinds_pad_word(keys, player);
+3 -2
View File
@@ -39,7 +39,8 @@
* with defaults changes nothing until the user edits it:
* D-pad: Arrow keys Start: Return Select: Right Shift
* Cross: X Circle: S Square: Z Triangle: A
* L1: Q R1: W L2: E R2: R L3/R3: unbound
* L1: Q R1: W L2: E R2: R L3: T R3: Y (stick clicks continue the
* shoulder row; DualShock-only games like Ape Escape require L3/R3)
* Left analog stick: Arrow keys (matches the old keyboard analog path)
* Right analog stick: unbound (the keyboard never drove it before)
* Player 2 is fully unbound (add binds to enable a 2nd keyboard player).
@@ -52,7 +53,7 @@
.square = SDL_SCANCODE_Z, .triangle = SDL_SCANCODE_A, \
.l1 = SDL_SCANCODE_Q, .r1 = SDL_SCANCODE_W, \
.l2 = SDL_SCANCODE_E, .r2 = SDL_SCANCODE_R, \
.l3 = SDL_SCANCODE_UNKNOWN, .r3 = SDL_SCANCODE_UNKNOWN, \
.l3 = SDL_SCANCODE_T, .r3 = SDL_SCANCODE_Y, \
.start = SDL_SCANCODE_RETURN, .select = SDL_SCANCODE_RSHIFT, \
.ls_up = SDL_SCANCODE_UP, .ls_down = SDL_SCANCODE_DOWN, \
.ls_left = SDL_SCANCODE_LEFT, .ls_right = SDL_SCANCODE_RIGHT, \
+4 -1
View File
@@ -54,7 +54,8 @@ Write-Host "Verified self-contained: imports only system DLLs ($($imports.Count)
@"
; PSXRecomp input mapping. PSX buttons are active when any listed source is pressed.
; Sources use SDL/Xbox names: a,b,x,y,back,start,leftshoulder,rightshoulder,
; lefttrigger,righttrigger,dpup,dpdown,dpleft,dpright,leftx-/leftx+/lefty-/lefty+.
; lefttrigger,righttrigger,leftstick,rightstick (stick clicks -> L3/R3),
; dpup,dpdown,dpleft,dpright,leftx-/leftx+/lefty-/lefty+.
[controller]
enabled = true
@@ -74,6 +75,8 @@ l1 = leftshoulder
r1 = rightshoulder
l2 = lefttrigger
r2 = righttrigger
l3 = leftstick
r3 = rightstick
start = start
select = back
"@ | Set-Content -Encoding ASCII (Join-Path $Stage "input.ini")