mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
host_keymap: a present-but-empty / "None" [KeyMap] line is an explicit unbind
host_keymap_load zeroed an action's binds when its line was present and then apply_defaults() put the built-in key straight back, so "Turbo = None" (or an empty value) silently re-armed Tab. Track explicit_unbound per action: set when the line is present but yields no binds, and honoured by apply_defaults through want_default(). A missing line still receives the default, so existing config.ini files are unaffected. Pairs with the launcher's Backspace-to-clear (recomp-ui feat/additional-ui-functionality), which writes "None" for that reason. README documents the rule; test_rewind_toggle_combo.py guards it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -746,6 +746,10 @@ acceleration is **opt-in**, per game, so the accurate path is never compromised:
|
||||
speed until pressed again. Controller host shortcuts bound to a single
|
||||
button or trigger are chords with Select — the launcher shows them as
|
||||
`select + …`; only a two-button capture replaces the implicit Select.
|
||||
Backspace while the launcher is listening clears a shortcut; in the files
|
||||
that is `0` for a `[hotkeys]` pad value and `None` for a `[KeyMap]` key (a
|
||||
present-but-empty or `None` line is an explicit unbind, a missing line
|
||||
keeps the built-in default).
|
||||
- **The "Fast Loading (host pacing)" and "CD Speed" mods** — automatic
|
||||
acceleration during load waits, shipped with every title and **off by
|
||||
default**, with `turbo_audio_sink` keeping the SPU timeline coherent through
|
||||
|
||||
+23
-11
@@ -25,10 +25,19 @@ typedef struct HostKeyBind {
|
||||
typedef struct HostKeyAction {
|
||||
HostKeyBind binds[HOST_KEYMAP_MAX_BINDS];
|
||||
int count;
|
||||
/* 1 when [KeyMap] names this action with an empty / "None" / "(unbound)"
|
||||
* value: the user cleared it, so apply_defaults must NOT put the built-in
|
||||
* key back. A MISSING line still gets the default. */
|
||||
int explicit_unbound;
|
||||
} HostKeyAction;
|
||||
|
||||
|
||||
static HostKeyAction s_actions[HOST_KEYMAP_ACTION_COUNT];
|
||||
|
||||
static int want_default(HostKeymapAction action) {
|
||||
return s_actions[action].count == 0 && !s_actions[action].explicit_unbound;
|
||||
}
|
||||
|
||||
static int ieq(const char *a, const char *b) {
|
||||
if (!a || !b) return 0;
|
||||
while (*a && *b) {
|
||||
@@ -79,27 +88,27 @@ static void add_bind(HostKeymapAction action, int keycode, int scancode, int mod
|
||||
}
|
||||
|
||||
static void apply_defaults(void) {
|
||||
if (s_actions[HOST_KEYMAP_FULLSCREEN].count == 0) {
|
||||
if (want_default(HOST_KEYMAP_FULLSCREEN)) {
|
||||
add_bind(HOST_KEYMAP_FULLSCREEN, (int)SDLK_RETURN, (int)SDL_SCANCODE_RETURN, KMOD_ALT);
|
||||
add_bind(HOST_KEYMAP_FULLSCREEN, (int)SDLK_f, (int)SDL_SCANCODE_F, KMOD_CTRL);
|
||||
}
|
||||
if (s_actions[HOST_KEYMAP_TURBO].count == 0)
|
||||
if (want_default(HOST_KEYMAP_TURBO))
|
||||
add_bind(HOST_KEYMAP_TURBO, (int)SDLK_TAB, (int)SDL_SCANCODE_TAB, 0);
|
||||
if (s_actions[HOST_KEYMAP_VOLUME_UP].count == 0)
|
||||
if (want_default(HOST_KEYMAP_VOLUME_UP))
|
||||
add_bind(HOST_KEYMAP_VOLUME_UP, (int)SDLK_KP_PLUS, (int)SDL_SCANCODE_KP_PLUS, 0);
|
||||
if (s_actions[HOST_KEYMAP_VOLUME_DOWN].count == 0)
|
||||
if (want_default(HOST_KEYMAP_VOLUME_DOWN))
|
||||
add_bind(HOST_KEYMAP_VOLUME_DOWN, (int)SDLK_KP_MINUS, (int)SDL_SCANCODE_KP_MINUS, 0);
|
||||
if (s_actions[HOST_KEYMAP_DISPLAY_PERF].count == 0)
|
||||
if (want_default(HOST_KEYMAP_DISPLAY_PERF))
|
||||
add_bind(HOST_KEYMAP_DISPLAY_PERF, (int)SDLK_f, (int)SDL_SCANCODE_F, 0);
|
||||
#if defined(PSX_HAS_RBENGINE_SNAP)
|
||||
if (s_actions[HOST_KEYMAP_REWIND].count == 0)
|
||||
if (want_default(HOST_KEYMAP_REWIND))
|
||||
add_bind(HOST_KEYMAP_REWIND, (int)SDLK_F8, (int)SDL_SCANCODE_F8, 0);
|
||||
#endif
|
||||
if (s_actions[HOST_KEYMAP_SAVE_STATE_MENU].count == 0)
|
||||
if (want_default(HOST_KEYMAP_SAVE_STATE_MENU))
|
||||
add_bind(HOST_KEYMAP_SAVE_STATE_MENU, (int)SDLK_F7, (int)SDL_SCANCODE_F7, 0);
|
||||
if (s_actions[HOST_KEYMAP_SCANLINES].count == 0)
|
||||
if (want_default(HOST_KEYMAP_SCANLINES))
|
||||
add_bind(HOST_KEYMAP_SCANLINES, (int)SDLK_F6, (int)SDL_SCANCODE_F6, 0);
|
||||
if (s_actions[HOST_KEYMAP_TURBO_TOGGLE].count == 0)
|
||||
if (want_default(HOST_KEYMAP_TURBO_TOGGLE))
|
||||
add_bind(HOST_KEYMAP_TURBO_TOGGLE, (int)SDLK_F9, (int)SDL_SCANCODE_F9, 0);
|
||||
}
|
||||
|
||||
@@ -202,10 +211,13 @@ void host_keymap_load(const char *config_ini_path) {
|
||||
trim_inplace(val);
|
||||
act = action_for_key(key);
|
||||
if (act == HOST_KEYMAP_ACTION_COUNT) continue;
|
||||
/* Explicit empty unbinds (no keypad fallback for that action until
|
||||
* apply_defaults — empty means user cleared it; still fall back). */
|
||||
/* Explicit empty / "None" unbinds: the user cleared it, so no
|
||||
* default fallback for that action (explicit_unbound). */
|
||||
s_actions[act].count = 0;
|
||||
s_actions[act].explicit_unbound = 0;
|
||||
parse_value(act, val);
|
||||
if (s_actions[act].count == 0)
|
||||
s_actions[act].explicit_unbound = 1;
|
||||
}
|
||||
fclose(f);
|
||||
apply_defaults();
|
||||
|
||||
@@ -75,5 +75,11 @@ KEYMAP_C = (ROOT / "runtime" / "src" / "host_keymap.c").read_text(encoding="utf-
|
||||
assert "HOST_KEYMAP_TURBO_TOGGLE," in KEYMAP_H
|
||||
assert 'ieq(name, "TurboToggle")' in KEYMAP_C
|
||||
assert "add_bind(HOST_KEYMAP_TURBO_TOGGLE, (int)SDLK_F9" in KEYMAP_C
|
||||
# A present-but-empty / "None" [KeyMap] line is an explicit unbind: no
|
||||
# built-in default is re-applied for that action (launcher Backspace-to-clear).
|
||||
assert "int explicit_unbound;" in KEYMAP_C
|
||||
assert "static int want_default(HostKeymapAction action)" in KEYMAP_C
|
||||
assert "s_actions[HOST_KEYMAP_TURBO].count == 0" not in KEYMAP_C
|
||||
assert "if (want_default(HOST_KEYMAP_TURBO))" in KEYMAP_C
|
||||
|
||||
print("host shortcut guard passed")
|
||||
|
||||
Reference in New Issue
Block a user