From 33612fead3b98fa1ab416110a01a03701fe1cd85 Mon Sep 17 00:00:00 2001 From: drako <98249188+drakolordx7@users.noreply.github.com> Date: Wed, 30 Sep 2026 18:10:12 -0500 Subject: [PATCH] Fix DualShock 2 pressure byte order for R1 and L2 scePadRead filled the shoulder pressure bytes 16..19 as L1, L2, R1, R2. A DualShock 2 reports them as L1, R1, L2, R2 (bytes 8..19: right, left, up, down, triangle, circle, cross, square, L1, R1, L2, R2). Games that read buttons through the pressure bytes therefore saw R1 and L2 swapped. Found in Killzone (SCUS-97402), which reads every button as an analog value from the pressure bytes: with the old order, R1 (fire in its default controller map) triggered crouch and L2 fired. The existing pad test only pressed L1 and R2, which sit at the same index in both orders; it now also presses R1 alone and L2 alone. Made by drakolord and assisted with Claude Code. --- ps2xRuntime/src/lib/Kernel/Stubs/Pad.cpp | 5 +++-- ps2xTest/src/pad_input_tests.cpp | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/ps2xRuntime/src/lib/Kernel/Stubs/Pad.cpp b/ps2xRuntime/src/lib/Kernel/Stubs/Pad.cpp index b50a4cf6a..38666d3d4 100644 --- a/ps2xRuntime/src/lib/Kernel/Stubs/Pad.cpp +++ b/ps2xRuntime/src/lib/Kernel/Stubs/Pad.cpp @@ -260,9 +260,10 @@ namespace ps2_stubs data[13] = pressureValue(state, portState, kPadBtnCircle); data[14] = pressureValue(state, portState, kPadBtnCross); data[15] = pressureValue(state, portState, kPadBtnSquare); + // DualShock 2 pressure order: right, left, up, down, triangle, circle, cross, square, L1, R1, L2, R2. data[16] = pressureValue(state, portState, kPadBtnL1); - data[17] = pressureValue(state, portState, kPadBtnL2); - data[18] = pressureValue(state, portState, kPadBtnR1); + data[17] = pressureValue(state, portState, kPadBtnR1); + data[18] = pressureValue(state, portState, kPadBtnL2); data[19] = pressureValue(state, portState, kPadBtnR2); } diff --git a/ps2xTest/src/pad_input_tests.cpp b/ps2xTest/src/pad_input_tests.cpp index 07f9b7a29..45f22013a 100644 --- a/ps2xTest/src/pad_input_tests.cpp +++ b/ps2xTest/src/pad_input_tests.cpp @@ -456,10 +456,23 @@ void register_pad_input_tests() t.Equals(data[14], static_cast(0xFF), "cross pressure should be populated when pressed"); t.Equals(data[15], static_cast(0x00), "square pressure should be clear when not pressed"); t.Equals(data[16], static_cast(0xFF), "L1 pressure should be populated when pressed"); - t.Equals(data[17], static_cast(0x00), "L2 pressure should be clear when not pressed"); - t.Equals(data[18], static_cast(0x00), "R1 pressure should be clear when not pressed"); + t.Equals(data[17], static_cast(0x00), "R1 pressure should be clear when not pressed"); + t.Equals(data[18], static_cast(0x00), "L2 pressure should be clear when not pressed"); t.Equals(data[19], static_cast(0xFF), "R2 pressure should be populated when pressed"); + // Shoulder pressure bytes follow the DualShock 2 order L1, R1, L2, R2. + ps2_stubs::setPadOverrideState(static_cast(0xFFFFu & ~kPadBtnR1), 0x80, 0x80, 0x80, 0x80); + runPadRead(ctx, rdram); + t.Equals(data[16], static_cast(0x00), "L1 pressure should be clear when only R1 is pressed"); + t.Equals(data[17], static_cast(0xFF), "R1 pressure is byte 17"); + t.Equals(data[18], static_cast(0x00), "L2 pressure should be clear when only R1 is pressed"); + t.Equals(data[19], static_cast(0x00), "R2 pressure should be clear when only R1 is pressed"); + ps2_stubs::setPadOverrideState(static_cast(0xFFFFu & ~kPadBtnL2), 0x80, 0x80, 0x80, 0x80); + runPadRead(ctx, rdram); + t.Equals(data[17], static_cast(0x00), "R1 pressure should be clear when only L2 is pressed"); + t.Equals(data[18], static_cast(0xFF), "L2 pressure is byte 18"); + ps2_stubs::setPadOverrideState(pressedButtons, 0x80, 0x80, 0x80, 0x80); + setRegU32(ctx, 4, 0u); setRegU32(ctx, 5, 0u); setRegU32(ctx, 6, static_cast(kPadBtnL1 | kPadBtnR2));