mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
812465df58
A title calls psx_mod_set_rewind_blocked(1) while it is in a mode that must not be rewound, such as local split-screen multiplayer, and 0 when it ends. While blocked, opening Rewind is refused with an OSD note, no history is captured (the ring keeps what it has; a capture already due is dropped and an open panel closes unloaded), and a title-allowed direct Rewind shortcut is not in force: its button is not claimed and reaches the guest pad / title transform as if Rewind were off. Netplay already refuses Rewind on its own. The block clears at every mod/session start, so a title that never calls it is unchanged. The direct-allowance decision (allowed, and for Rewind: enabled and not blocked) is now one pure helper, psx_hotkey_direct_active, used for both the claim and the shortcut press, so an unclaimed Rewind button is never a one-button shortcut (with Rewind off it falls back to Select + button rather than popping the "Rewind is off" note on every press). Tests: psx_hotkey_pad_test covers the allowance and a block taking effect mid-press; rewind_toggle_combo_test guards the capture/open gates and reset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
89 lines
4.1 KiB
C
89 lines
4.1 KiB
C
/* Host shortcut binding semantics: legacy Select chords, multi-button combos,
|
|
* one-button combos that are direct only when the title allows it, and the
|
|
* claim-through-release mask for direct shortcut buttons. */
|
|
#include <stdio.h>
|
|
#include "psx_hotkey_pad.h"
|
|
|
|
#define CHECK(expr) do { if (!(expr)) { \
|
|
fprintf(stderr, "FAIL line %d: %s\n", __LINE__, #expr); return 1; } } while (0)
|
|
|
|
enum { A = 0, B = 1, BACK = 4, Y = 3, RS = 8, LEFTX = 0 };
|
|
static uint32_t held;
|
|
static int axis;
|
|
static int down(void *c, int code) { (void)c; return (held >> code) & 1u; }
|
|
static int axis_value(void *c, int a) { (void)c; return a == LEFTX ? axis : 0; }
|
|
static int combo(uint32_t mask) { return PSX_HOTKEY_PAD_COMBO_BASE + (int)mask; }
|
|
static int pressed(int binding, int direct) {
|
|
return psx_hotkey_pad_down(binding, direct, BACK, down, axis_value, NULL);
|
|
}
|
|
|
|
int main(void) {
|
|
CHECK(psx_hotkey_pad_single_button(combo(1u << Y)) == Y);
|
|
CHECK(psx_hotkey_pad_single_button(combo((1u << BACK) | (1u << RS))) == -1);
|
|
CHECK(psx_hotkey_pad_single_button(1 + Y) == -1); /* legacy encoding */
|
|
CHECK(psx_hotkey_pad_single_button(combo(0)) == -1);
|
|
CHECK(psx_hotkey_pad_single_button(0) == -1);
|
|
|
|
/* One-button combination: Select + Y unless direct is allowed. */
|
|
held = 1u << Y;
|
|
CHECK(!pressed(combo(1u << Y), 0));
|
|
CHECK(pressed(combo(1u << Y), 1));
|
|
held = (1u << Y) | (1u << BACK);
|
|
CHECK(pressed(combo(1u << Y), 0));
|
|
|
|
/* Multi-button combination: all held, direct flag irrelevant. */
|
|
held = (1u << BACK) | (1u << RS);
|
|
CHECK(pressed(combo((1u << BACK) | (1u << RS)), 0));
|
|
held = 1u << RS;
|
|
CHECK(!pressed(combo((1u << BACK) | (1u << RS)), 1));
|
|
|
|
/* Legacy one-button and axis encodings always chord with Select. */
|
|
held = 1u << Y;
|
|
CHECK(!pressed(1 + Y, 1));
|
|
held |= 1u << BACK;
|
|
CHECK(pressed(1 + Y, 0));
|
|
axis = -20000;
|
|
CHECK(pressed(100 + LEFTX * 2 + 0, 0));
|
|
CHECK(!pressed(100 + LEFTX * 2 + 1, 0));
|
|
held = 0;
|
|
CHECK(!pressed(100 + LEFTX * 2 + 0, 1));
|
|
CHECK(!pressed(0, 1));
|
|
|
|
/* Claims: a claimed button is suppressed; once claimed while held it
|
|
* stays suppressed through release even after the claim ends. */
|
|
{
|
|
uint32_t latched = 0;
|
|
CHECK(psx_hotkey_claim_update(&latched, 1u << Y, 0) == (1u << Y));
|
|
CHECK(psx_hotkey_claim_update(&latched, 1u << Y, 1u << Y) == (1u << Y));
|
|
CHECK(psx_hotkey_claim_update(&latched, 0, 1u << Y) == (1u << Y));
|
|
CHECK(psx_hotkey_claim_update(&latched, 0, 1u << Y) == (1u << Y));
|
|
CHECK(psx_hotkey_claim_update(&latched, 0, 0) == 0);
|
|
CHECK(psx_hotkey_claim_update(&latched, 0, 1u << Y) == 0); /* fresh press */
|
|
CHECK(psx_hotkey_claim_update(&latched, 0, 0) == 0 && latched == 0);
|
|
}
|
|
/* Direct allowance in force: title-allowed, and for Rewind only while
|
|
* Rewind is enabled and the title has not blocked it. */
|
|
{
|
|
const uint32_t allowed = 1u << 0; /* shortcut 0 (Rewind) */
|
|
CHECK(psx_hotkey_direct_active(allowed, 0, 1, 1, 0));
|
|
CHECK(!psx_hotkey_direct_active(allowed, 0, 1, 0, 0)); /* disabled */
|
|
CHECK(!psx_hotkey_direct_active(allowed, 0, 1, 1, 1)); /* blocked */
|
|
CHECK(!psx_hotkey_direct_active(0, 0, 1, 1, 0)); /* not allowed */
|
|
CHECK(psx_hotkey_direct_active(1u << 2, 2, 0, 0, 1)); /* not Rewind */
|
|
CHECK(!psx_hotkey_direct_active(~0u, -1, 0, 1, 0));
|
|
CHECK(!psx_hotkey_direct_active(~0u, 32, 0, 1, 0));
|
|
/* Blocked mid-press: the claim stops but the held button stays
|
|
* suppressed until release, then reaches the guest. */
|
|
uint32_t latched = 0;
|
|
CHECK(psx_hotkey_claim_update(&latched, 1u << Y, 1u << Y) == (1u << Y));
|
|
CHECK(psx_hotkey_claim_update(&latched, 0, 1u << Y) == (1u << Y));
|
|
CHECK(psx_hotkey_claim_update(&latched, 0, 0) == 0);
|
|
CHECK(psx_hotkey_claim_update(&latched, 0, 1u << Y) == 0);
|
|
/* Not in force: a one-button binding needs Select, like legacy. */
|
|
held = 1u << Y;
|
|
CHECK(!pressed(combo(1u << Y), psx_hotkey_direct_active(allowed, 0, 1, 1, 1)));
|
|
}
|
|
fprintf(stderr, "psx_hotkey_pad: passed\n");
|
|
return 0;
|
|
}
|