Fix PSX launcher hotkeys and audio persistence

This commit is contained in:
Matthew Stanley
2026-08-14 15:22:29 -07:00
parent 7ac2733896
commit cab7d00f9a
11 changed files with 285 additions and 36 deletions
+13
View File
@@ -2103,6 +2103,10 @@ GameOptions load_game_options(const fs::path& path) {
// ---- UserSettings (settings.toml) — launcher-written override layer ----
static bool valid_user_audio_freq(int n) {
return n == 32040 || n == 32000 || n == 44100 || n == 48000;
}
UserSettings load_user_settings(const fs::path& path) {
UserSettings s;
std::error_code ec;
@@ -2245,6 +2249,13 @@ UserSettings load_user_settings(const fs::path& path) {
}
if (doc.contains("audio")) {
const toml::value& a = toml::find(doc, "audio");
if (a.contains("frequency")) try_get([&]{
const auto n = toml::find<int64_t>(a, "frequency");
if (valid_user_audio_freq((int)n)) {
s.audio_freq = (int)n;
s.has_audio_freq = true;
}
});
if (a.contains("spu_hq")) try_get([&]{
s.spu_hq = toml::find<bool>(a, "spu_hq"); s.has_spu_hq = true;
});
@@ -2487,6 +2498,8 @@ bool save_user_settings(const fs::path& path, const UserSettings& s) {
if (s.has_rewind_interval)
f << "rewind_interval = " << s.rewind_interval << "\n";
f << "\n[audio]\n";
if (s.has_audio_freq)
f << "frequency = " << s.audio_freq << "\n";
if (s.has_spu_hq)
f << "spu_hq = " << (s.spu_hq ? "true" : "false") << "\n";
if (s.has_hotkey_pad_rewind || s.has_hotkey_pad_save_state_menu) {
+1
View File
@@ -1115,6 +1115,7 @@ struct UserSettings {
bool has_hotkey_pad_save_state_menu = false; int hotkey_pad_save_state_menu = 2040; /* select+r1 */
// [audio]
bool has_spu_hq = false; bool spu_hq = false;
bool has_audio_freq = false; int audio_freq = 44100;
// [bios] / [disc] / [memcard]
bool has_bios_path = false; std::filesystem::path bios_path;
bool has_disc_path = false; std::filesystem::path disc_path;
@@ -122,13 +122,17 @@ static void test_user_settings_read() {
fs::path p = write_temp("psxrecomp_pgxp_settings.toml",
"[video]\n"
"geometry_correction = true\n"
"perspective_texturing = false\n");
"perspective_texturing = false\n"
"[audio]\n"
"frequency = 48000\n");
auto us = PSXRecompV4::load_user_settings(p);
check(!us.parse_error, "settings.toml parses");
check(us.has_geometry_correction && us.geometry_correction,
"settings.toml geometry_correction = true read");
check(us.has_perspective_texturing && !us.perspective_texturing,
"settings.toml perspective_texturing = false read (explicit off)");
check(us.has_audio_freq && us.audio_freq == 48000,
"settings.toml audio frequency read");
fs::remove(p);
}
@@ -150,6 +154,7 @@ static void test_user_settings_round_trip() {
PSXRecompV4::UserSettings out;
out.geometry_correction = true; out.has_geometry_correction = true;
out.perspective_texturing = true; out.has_perspective_texturing = true;
out.audio_freq = 48000; out.has_audio_freq = true;
fs::path p = fs::temp_directory_path() / "psxrecomp_pgxp_roundtrip.toml";
check(PSXRecompV4::save_user_settings(p, out), "save_user_settings writes");
@@ -160,6 +165,8 @@ static void test_user_settings_round_trip() {
"geometry_correction survives a save/load round trip");
check(back.has_perspective_texturing && back.perspective_texturing,
"perspective_texturing survives a save/load round trip");
check(back.has_audio_freq && back.audio_freq == 48000,
"audio frequency survives a save/load round trip");
fs::remove(p);
}
+11
View File
@@ -52,6 +52,17 @@ if(BUILD_TESTING)
PSX_OVERLAY_DLL_BUILD=1)
add_test(NAME psx_icache_fastpath_test COMMAND psx_icache_fastpath_test)
add_executable(host_keymap_test
tests/test_host_keymap.c
src/host_keymap.c)
target_include_directories(host_keymap_test PRIVATE
include ${PSX_SDL_INCLUDE_DIRS})
target_compile_definitions(host_keymap_test PRIVATE
SDL_MAIN_HANDLED
$<$<BOOL:${PSX_SDL3}>:PSX_SDL3=1>)
target_link_libraries(host_keymap_test PRIVATE ${PSX_SDL_LIBRARIES})
add_test(NAME host_keymap_test COMMAND host_keymap_test)
# Registered since before this change, but it did NOT LINK on origin/master:
# sio.c had grown psx_read_word / psx_get_cycle_count / i_mask /
# g_debug_last_store_pc references that this test's stub block never gained,
+8 -3
View File
@@ -10,13 +10,15 @@ extern "C" {
/*
* Host hotkeys from recomp-ui config.ini [KeyMap] (SDL key names + Ctrl+/Alt+/
* Shift+ prefixes). VolumeUp / VolumeDown are honored by the runtime; missing
* lines keep the historic keypad +/- defaults.
* Shift+ prefixes). Missing lines keep the historic runtime defaults.
*/
typedef enum HostKeymapAction {
HOST_KEYMAP_VOLUME_UP = 0,
HOST_KEYMAP_FULLSCREEN = 0,
HOST_KEYMAP_TURBO,
HOST_KEYMAP_VOLUME_UP,
HOST_KEYMAP_VOLUME_DOWN,
HOST_KEYMAP_DISPLAY_PERF,
HOST_KEYMAP_REWIND, /* default F8 */
HOST_KEYMAP_SAVE_STATE_MENU, /* default F7 */
HOST_KEYMAP_ACTION_COUNT
@@ -28,6 +30,9 @@ void host_keymap_load(const char *config_ini_path);
/* 1 if (keycode, mod) matches a binding for `action`. */
int host_keymap_match(HostKeymapAction action, int keycode, int mod);
/* 1 if any configured bind for `action` is currently held. */
int host_keymap_down(HostKeymapAction action, const uint8_t *keys, int mod);
/* Format the primary bind for `action` into out (e.g. "F8", "Ctrl+R",
* "GRAVE"). Punctuation key names are tokenized for the rewind overlay font.
* Returns out, or "F8" / "" on empty action. Always NUL-terminates. */
+3
View File
@@ -19,6 +19,9 @@ extern "C" {
/* Top-left text toast. duration_ms <= 0 uses 2000. */
void host_osd_push(const char *msg, int duration_ms);
/* Persistent top-left status text. Passing NULL/empty clears it. */
void host_osd_set_status(const char *msg);
/* Right-side vertical volume bar (percent clamped 0..100). */
void host_osd_show_volume(int percent, int duration_ms);
+28 -10
View File
@@ -441,18 +441,34 @@ endif()
# Local rewind: full rbengine when netplay is on; otherwise compile snap_ring.c
# only (no recomp-net / sched / hash_confirm). Never both — duplicate symbols.
# Defaults ON because local rewind is useful for every PSX title. If a title
# deliberately opts out with -DPSX_REWIND=OFF, recomp-ui hides the Rewind
# controls instead of exposing dead hotkeys.
option(PSX_REWIND "Build and expose local rewind support" ON)
set(PSXRECOMP_HAS_RBENGINE_SNAP FALSE)
set(PSXRECOMP_RBENGINE_SNAP_INCLUDE "")
if(PSXRECOMP_HAS_RBENGINE)
set(PSXRECOMP_HAS_RBENGINE_SNAP TRUE)
elseif(RECOMP_RBENGINE_ROOT
AND EXISTS "${RECOMP_RBENGINE_ROOT}/src/snap/rbe_snap_ring.c"
AND EXISTS "${RECOMP_RBENGINE_ROOT}/include/retcomm_rbengine/snap_ring.h")
list(APPEND PSXRECOMP_RUNTIME_SOURCES
${RECOMP_RBENGINE_ROOT}/src/snap/rbe_snap_ring.c)
set(PSXRECOMP_HAS_RBENGINE_SNAP TRUE)
set(PSXRECOMP_RBENGINE_SNAP_INCLUDE "${RECOMP_RBENGINE_ROOT}/include")
message(STATUS "psxrecomp: rewind snap_ring (${RECOMP_RBENGINE_ROOT})")
if(PSX_REWIND)
if(PSXRECOMP_HAS_RBENGINE)
set(PSXRECOMP_HAS_RBENGINE_SNAP TRUE)
elseif(RECOMP_RBENGINE_ROOT
AND EXISTS "${RECOMP_RBENGINE_ROOT}/src/snap/rbe_snap_ring.c"
AND EXISTS "${RECOMP_RBENGINE_ROOT}/include/retcomm_rbengine/snap_ring.h")
list(APPEND PSXRECOMP_RUNTIME_SOURCES
${RECOMP_RBENGINE_ROOT}/src/snap/rbe_snap_ring.c)
set(PSXRECOMP_HAS_RBENGINE_SNAP TRUE)
set(PSXRECOMP_RBENGINE_SNAP_INCLUDE "${RECOMP_RBENGINE_ROOT}/include")
message(STATUS "psxrecomp: rewind snap_ring (${RECOMP_RBENGINE_ROOT})")
endif()
if(NOT PSXRECOMP_HAS_RBENGINE_SNAP)
message(FATAL_ERROR
"psxrecomp: PSX_REWIND=ON exposes the Rewind launcher controls "
"but no retcomm-rbengine snap-ring backend was found.\n"
" git submodule update --init lib/retcomm-rbengine\n"
" or -DRECOMP_RBENGINE_ROOT=/path/to/retcomm-rbengine\n"
" or configure with -DPSX_REWIND=OFF to hide Rewind.")
endif()
else()
message(STATUS "psxrecomp: local rewind disabled (PSX_REWIND=OFF)")
endif()
# Lobby WebSocket client helpers are vendored under runtime/src/lobby_ws/
@@ -1358,6 +1374,8 @@ function(psxrecomp_add_runtime_target target)
list(APPEND _psx_recomp_ui_args BRAND "${PSXRT_LAUNCHER_BRAND}")
endif()
recomp_target_launcher_ui(${target} ${_psx_recomp_ui_args})
target_compile_definitions(${target} PRIVATE
RECOMP_UI_PSX_HAS_REWIND=$<BOOL:${PSXRECOMP_HAS_RBENGINE_SNAP}>)
endif()
if(WIN32 OR MINGW)
+42 -7
View File
@@ -18,6 +18,7 @@
typedef struct HostKeyBind {
int keycode;
int scancode;
int mods; /* KMOD_CTRL | KMOD_ALT | KMOD_SHIFT subset */
} HostKeyBind;
@@ -65,32 +66,44 @@ static void clear_all(void) {
memset(s_actions, 0, sizeof(s_actions));
}
static void add_bind(HostKeymapAction action, int keycode, int mods) {
static void add_bind(HostKeymapAction action, int keycode, int scancode, int mods) {
HostKeyAction *a;
if (action < 0 || action >= HOST_KEYMAP_ACTION_COUNT) return;
if (keycode == 0 || keycode == SDLK_UNKNOWN) return;
a = &s_actions[action];
if (a->count >= HOST_KEYMAP_MAX_BINDS) return;
a->binds[a->count].keycode = keycode;
a->binds[a->count].scancode = scancode;
a->binds[a->count].mods = mods;
a->count++;
}
static void apply_defaults(void) {
if (s_actions[HOST_KEYMAP_FULLSCREEN].count == 0) {
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)
add_bind(HOST_KEYMAP_TURBO, (int)SDLK_TAB, (int)SDL_SCANCODE_TAB, 0);
if (s_actions[HOST_KEYMAP_VOLUME_UP].count == 0)
add_bind(HOST_KEYMAP_VOLUME_UP, (int)SDLK_KP_PLUS, 0);
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)
add_bind(HOST_KEYMAP_VOLUME_DOWN, (int)SDLK_KP_MINUS, 0);
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)
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)
add_bind(HOST_KEYMAP_REWIND, (int)SDLK_F8, 0);
add_bind(HOST_KEYMAP_REWIND, (int)SDLK_F8, (int)SDL_SCANCODE_F8, 0);
#endif
if (s_actions[HOST_KEYMAP_SAVE_STATE_MENU].count == 0)
add_bind(HOST_KEYMAP_SAVE_STATE_MENU, (int)SDLK_F7, 0);
add_bind(HOST_KEYMAP_SAVE_STATE_MENU, (int)SDLK_F7, (int)SDL_SCANCODE_F7, 0);
}
/* Parse one "Ctrl+Alt+PageUp" token into key+mods. */
static void parse_one_token(HostKeymapAction action, char *tok) {
int mods = 0;
SDL_Keycode key;
SDL_Scancode sc;
trim_inplace(tok);
if (!tok[0] || ieq(tok, "(unbound)") || ieq(tok, "None")) return;
for (;;) {
@@ -114,7 +127,8 @@ static void parse_one_token(HostKeymapAction action, char *tok) {
fprintf(stderr, "host_keymap: unknown key '%s'\n", tok);
return;
}
add_bind(action, (int)key, mods);
sc = SDL_GetScancodeFromName(tok);
add_bind(action, (int)key, (int)sc, mods);
}
static void parse_value(HostKeymapAction action, const char *value) {
@@ -133,8 +147,11 @@ static void parse_value(HostKeymapAction action, const char *value) {
}
static HostKeymapAction action_for_key(const char *name) {
if (ieq(name, "Fullscreen")) return HOST_KEYMAP_FULLSCREEN;
if (ieq(name, "Turbo")) return HOST_KEYMAP_TURBO;
if (ieq(name, "VolumeUp")) return HOST_KEYMAP_VOLUME_UP;
if (ieq(name, "VolumeDown")) return HOST_KEYMAP_VOLUME_DOWN;
if (ieq(name, "DisplayPerf")) return HOST_KEYMAP_DISPLAY_PERF;
if (ieq(name, "Rewind")) return HOST_KEYMAP_REWIND;
if (ieq(name, "SaveStateMenu")) return HOST_KEYMAP_SAVE_STATE_MENU;
return HOST_KEYMAP_ACTION_COUNT;
@@ -201,6 +218,21 @@ int host_keymap_match(HostKeymapAction action, int keycode, int mod) {
return 0;
}
int host_keymap_down(HostKeymapAction action, const uint8_t *keys, int mod) {
const HostKeyAction *a;
const int relevant = (int)(KMOD_CTRL | KMOD_ALT | KMOD_SHIFT);
int i;
if (!keys || action < 0 || action >= HOST_KEYMAP_ACTION_COUNT) return 0;
a = &s_actions[action];
for (i = 0; i < a->count; i++) {
const int sc = a->binds[i].scancode;
if (sc <= 0 || sc >= SDL_NUM_SCANCODES) continue;
if (!keys[sc]) continue;
if ((mod & relevant) == a->binds[i].mods) return 1;
}
return 0;
}
/* Rewind overlay FONT8 only draws ASCII 32..90 (space..Z); lowercase is
* uppercased by the drawer. Map punctuation / odd SDL single-glyph names to
* short tokens so binds like backtick don't render as "?". */
@@ -257,9 +289,12 @@ const char *host_keymap_label(HostKeymapAction action, char *out, size_t cap) {
if (action < 0 || action >= HOST_KEYMAP_ACTION_COUNT) return out;
a = &s_actions[action];
if (a->count <= 0) {
#if defined(PSX_HAS_RBENGINE_SNAP)
if (action == HOST_KEYMAP_REWIND)
snprintf(out, cap, "F8");
else if (action == HOST_KEYMAP_SAVE_STATE_MENU)
else
#endif
if (action == HOST_KEYMAP_SAVE_STATE_MENU)
snprintf(out, cap, "F7");
return out;
}
+38 -7
View File
@@ -130,6 +130,10 @@ static Uint32 s_expire_ms;
static int s_active;
static int s_img_dirty = 1;
static char s_status_msg[OSD_MAX_CHARS];
static int s_status_active;
static int s_status_dirty = 1;
static int s_volume = 100; /* host master 0..100 */
static int s_vol_pct = 100; /* last shown bar fill */
static Uint32 s_vol_expire_ms;
@@ -197,8 +201,8 @@ static int vol_visible(void) {
return 1;
}
static void rasterize_text(void) {
int n = (int)strlen(s_msg);
static void rasterize_text(const char *msg) {
int n = (int)strlen(msg);
if (n > OSD_MAX_CHARS) n = OSD_MAX_CHARS;
s_img_w = (OSD_PAD_X * 2 + n * OSD_GLYPH_W) * OSD_SCALE;
s_img_h = (OSD_PAD_Y * 2 + OSD_GLYPH_H) * OSD_SCALE;
@@ -211,7 +215,7 @@ static void rasterize_text(void) {
s_img[i] = 0xFF202020u;
for (int ci = 0; ci < n; ci++) {
unsigned char ch = (unsigned char)s_msg[ci];
unsigned char ch = (unsigned char)msg[ci];
if (ch < 32 || ch > 126) ch = '?';
const uint8_t *g = FONT8X8[ch - 32];
for (int row = 0; row < OSD_GLYPH_H; row++) {
@@ -338,6 +342,25 @@ void host_osd_push(const char *msg, int duration_ms) {
#endif
}
void host_osd_set_status(const char *msg) {
#if !HOST_OSD_VISUAL
(void)msg;
return;
#else
if (!msg || !msg[0]) {
if (s_status_active) s_needs_clear = 1;
s_status_msg[0] = '\0';
s_status_active = 0;
s_status_dirty = 1;
return;
}
snprintf(s_status_msg, sizeof(s_status_msg), "%s", msg);
s_status_active = 1;
s_status_dirty = 1;
s_needs_clear = 0;
#endif
}
void host_osd_show_volume(int percent, int duration_ms) {
#if !HOST_OSD_VISUAL
(void)percent;
@@ -375,7 +398,7 @@ int host_osd_needs_present(void) {
#if !HOST_OSD_VISUAL
return 0;
#else
if (msg_visible() || vol_visible()) return 1;
if (msg_visible() || s_status_active || vol_visible()) return 1;
return s_needs_clear;
#endif
}
@@ -387,13 +410,21 @@ int host_osd_image(const uint32_t **pixels, int *w, int *h) {
if (h) *h = 0;
return 0;
#else
if (!msg_visible()) {
const int show_msg = msg_visible();
if (!show_msg && !s_status_active) {
if (pixels) *pixels = NULL;
if (w) *w = 0;
if (h) *h = 0;
return 0;
}
if (s_img_dirty) rasterize_text();
if (show_msg) {
if (s_img_dirty) rasterize_text(s_msg);
} else {
if (s_status_dirty || s_img_dirty) {
rasterize_text(s_status_msg);
s_status_dirty = 0;
}
}
if (pixels) *pixels = s_img;
if (w) *w = s_img_w;
if (h) *h = s_img_h;
@@ -426,7 +457,7 @@ void host_osd_present_done(void) {
#if !HOST_OSD_VISUAL
return;
#else
if (!s_active && !s_vol_active) s_needs_clear = 0;
if (!s_active && !s_status_active && !s_vol_active) s_needs_clear = 0;
#endif
}
+49 -8
View File
@@ -465,6 +465,7 @@ static int post_load_probe_env_on(void) {
static Uint64 s_fps_last_time = 0;
static uint64_t s_fps_last_frame = 0;
static std::string s_fps_base_title;
static int s_fps_telemetry_enabled = -1; /* -1 = unread env */
static FramePacer s_frame_pacer = { 0 };
static int s_turbo_present_skip = 0;
static int s_fmv_skip_present_skip = 0;
@@ -517,6 +518,27 @@ static void present_session_reset(void) {
smooth_60_reset();
}
static int fps_telemetry_enabled(void) {
if (s_fps_telemetry_enabled < 0) {
const char *e = std::getenv("PSX_FPS_TELEMETRY");
s_fps_telemetry_enabled = (e && e[0] && e[0] != '0') ? 1 : 0;
}
return s_fps_telemetry_enabled;
}
static void fps_telemetry_toggle(void) {
const int enabled = fps_telemetry_enabled() ? 0 : 1;
s_fps_telemetry_enabled = enabled;
s_fps_last_time = 0;
s_fps_last_frame = 0;
if (!enabled && sdl_window && !s_fps_base_title.empty())
SDL_SetWindowTitle(sdl_window, s_fps_base_title.c_str());
if (!enabled)
host_osd_set_status(NULL);
s_fps_base_title.clear();
host_osd_push(enabled ? "FPS readout on" : "FPS readout off", 1500);
}
static void post_load_probe_stall_pc_note(uint32_t pc) {
if (!pc) return;
for (int i = 0; i < s_stall_pc_used; i++) {
@@ -1065,6 +1087,7 @@ static int g_fullscreen = 0; /* tri-state: 0 windowed, 1 borderle
static int g_video_screen = 0; /* 0=raw,1=crt,2=composite,3=trinitron */
static int g_video_win_w = 1280; /* window width (height follows aspect) */
static bool g_audio_spu_hq = false; /* SPU float-shadow (env overrides) */
static int g_audio_freq = 44100; /* host device request */
static int g_auto_skip_fmv = 0; /* skip FMVs the instant they're detected */
static int g_rewind_depth = 50; /* local rewind snap count (50/100/150/200) */
static int g_rewind_interval = 15; /* frames between snaps (1/4/8/12/15) */
@@ -5635,14 +5658,14 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
* than presents so turbo and skipped-frame modes still report game speed.
* Skip during netplay post-load barrier — admit is stalled and the window
* is not updating, so a climbing FPS line is misleading. */
if (!psx_netplay_in_load_barrier()) {
if (fps_telemetry_enabled() && !psx_netplay_in_load_barrier()) {
extern uint64_t s_frame_count;
const Uint64 now = SDL_GetPerformanceCounter();
const Uint64 frequency = SDL_GetPerformanceFrequency();
if (!s_fps_last_time) {
s_fps_last_time = now;
s_fps_last_frame = s_frame_count;
if (sdl_window) {
if (sdl_window && s_fps_base_title.empty()) {
const char *title = SDL_GetWindowTitle(sdl_window);
if (title) s_fps_base_title = title;
}
@@ -5656,6 +5679,11 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
s_fps_base_title.c_str(), fps, speed);
SDL_SetWindowTitle(sdl_window, title);
}
if (!g_headless) {
char osd[64];
snprintf(osd, sizeof(osd), "FPS %.0f %.2fx", fps, speed);
host_osd_set_status(osd);
}
if (netplay_timing_on() && s_np_timing_frames > 0) {
const double invf = 1000.0 / (double)frequency;
const double admit_ms =
@@ -5773,6 +5801,11 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
debug_force_cd_reinsert();
host_osd_push("CD reinsert", 1500);
}
else if (!key_repeat &&
host_keymap_match(HOST_KEYMAP_DISPLAY_PERF, (int)key,
(int)mod)) {
fps_telemetry_toggle();
}
/* Host volume: config.ini [KeyMap] VolumeUp/VolumeDown
* (defaults: keypad +/-). 5% steps; shows right-side bar. */
else if (host_keymap_match(HOST_KEYMAP_VOLUME_UP, (int)key,
@@ -5790,8 +5823,9 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
* set in both SDL_WINDOW_FULLSCREEN and
* SDL_WINDOW_FULLSCREEN_DESKTOP, so testing just that bit
* detects "currently fullscreen, either mode". */
else if ((key == SDLK_RETURN && (mod & KMOD_ALT)) ||
(key == SDLK_f && (mod & (KMOD_GUI | KMOD_CTRL)))) {
else if (!key_repeat &&
host_keymap_match(HOST_KEYMAP_FULLSCREEN, (int)key,
(int)mod)) {
Uint32 is_fs = SDL_GetWindowFlags(sdl_window) &
SDL_WINDOW_FULLSCREEN;
if (is_fs) {
@@ -6004,7 +6038,7 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
const Uint8* keys = SDL_GetKeyboardState(NULL);
static int turbo_skip = 0;
const int TURBO_PRESENT_EVERY = 30;
if (keys[SDL_SCANCODE_TAB]) {
if (host_keymap_down(HOST_KEYMAP_TURBO, keys, (int)SDL_GetModState())) {
turbo_skip = (turbo_skip + 1) % TURBO_PRESENT_EVERY;
if (turbo_skip != 0) {
ep.skip_pace = 1;
@@ -10657,6 +10691,7 @@ int main(int argc, char** argv) {
g_video_aspect_num = us.aspect_num;
g_video_aspect_den = us.aspect_den;
}
if (us.has_audio_freq) g_audio_freq = us.audio_freq;
if (us.has_spu_hq) g_audio_spu_hq = us.spu_hq;
if (us.has_rewind_depth) g_rewind_depth = us.rewind_depth;
if (us.has_rewind_interval) g_rewind_interval = us.rewind_interval;
@@ -11073,6 +11108,7 @@ int main(int argc, char** argv) {
seed.has_frame_interpolation_fps = true;
seed.aspect_num = g_video_aspect_num;
seed.aspect_den = g_video_aspect_den; seed.has_aspect_ratio = true;
seed.audio_freq = g_audio_freq; seed.has_audio_freq = true;
seed.spu_hq = g_audio_spu_hq; seed.has_spu_hq = true;
seed.rewind_depth = g_rewind_depth; seed.has_rewind_depth = true;
seed.rewind_interval = g_rewind_interval; seed.has_rewind_interval = true;
@@ -11178,7 +11214,7 @@ int main(int argc, char** argv) {
ls.widescreen = (seed.aspect_num == 16 && seed.aspect_den == 9) ? 1 : 0;
ls.widescreen_hud = ls.widescreen;
ls.enable_audio = 1;
ls.audio_freq = 44100;
ls.audio_freq = seed.audio_freq;
ls.volume = host_volume_get();
{
const int n = std::min(PSX_MAX_PLAYERS, RECOMP_LAUNCHER_MAX_PLAYERS);
@@ -11466,6 +11502,7 @@ int main(int argc, char** argv) {
seed.screen_kind = ls.screen_kind; seed.has_screen_kind = true;
seed.frame_interpolation = ls.frame_interp != 0; seed.has_frame_interpolation = true;
seed.frame_interpolation_fps = ls.frame_interp_fps; seed.has_frame_interpolation_fps = true;
seed.audio_freq = ls.audio_freq; seed.has_audio_freq = true;
seed.spu_hq = ls.spu_hq != 0; seed.has_spu_hq = true;
seed.rewind_depth = ls.rewind_depth > 0 ? ls.rewind_depth : 50;
seed.has_rewind_depth = true;
@@ -11677,6 +11714,7 @@ int main(int argc, char** argv) {
g_frame_interpolation_fps = seed.frame_interpolation_fps;
g_video_aspect_num = seed.aspect_num;
g_video_aspect_den = seed.aspect_den;
g_audio_freq = seed.audio_freq;
g_audio_spu_hq = seed.spu_hq;
g_rewind_depth = seed.has_rewind_depth && seed.rewind_depth > 0
? seed.rewind_depth : 50;
@@ -12250,7 +12288,7 @@ session_reboot:
if (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) {
PsxSdlAudioSpec want = {};
PsxSdlAudioSpec have = {};
want.freq = 44100;
want.freq = g_audio_freq;
want.format = AUDIO_S16SYS;
want.channels = 2;
want.samples = 1024;
@@ -13008,7 +13046,7 @@ soft_return_lobby:
(g_video_aspect_num == 16 && g_video_aspect_den == 9) ? 1 : 0;
ls.widescreen_hud = ls.widescreen;
ls.enable_audio = 1;
ls.audio_freq = 44100;
ls.audio_freq = g_audio_freq;
ls.volume = host_volume_get();
ls.window_width = g_video_win_w;
ls.renderer = g_video_renderer;
@@ -13279,6 +13317,8 @@ soft_return_lobby:
us.has_frame_interpolation = true;
us.frame_interpolation_fps = ls.frame_interp_fps;
us.has_frame_interpolation_fps = true;
us.audio_freq = ls.audio_freq;
us.has_audio_freq = true;
us.spu_hq = ls.spu_hq != 0;
us.has_spu_hq = true;
us.rewind_depth = ls.rewind_depth > 0 ? ls.rewind_depth : 50;
@@ -13337,6 +13377,7 @@ soft_return_lobby:
g_fullscreen = ls.fullscreen != 0;
g_frame_interpolation = ls.frame_interp ? 1 : 0;
g_frame_interpolation_fps = ls.frame_interp_fps;
g_audio_freq = ls.audio_freq;
g_audio_spu_hq = ls.spu_hq != 0;
if (ls.rewind_depth > 0) {
g_rewind_depth = ls.rewind_depth;
+84
View File
@@ -0,0 +1,84 @@
#include "host_keymap.h"
#include "psx_sdl.h"
#include <stdio.h>
#include <string.h>
static int failures = 0;
static void check(int cond, const char *what) {
if (!cond) {
fprintf(stderr, "FAIL: %s\n", what);
failures++;
}
}
static int mod_ctrl(void) { return (int)KMOD_CTRL; }
static int mod_alt(void) { return (int)KMOD_ALT; }
int main(int argc, char **argv) {
uint8_t keys[SDL_NUM_SCANCODES];
const char *cfg = "host_keymap_test.ini";
FILE *f;
(void)argc;
(void)argv;
memset(keys, 0, sizeof(keys));
host_keymap_load(NULL);
check(host_keymap_match(HOST_KEYMAP_FULLSCREEN, (int)SDLK_RETURN, mod_alt()),
"default fullscreen includes Alt+Return");
check(host_keymap_match(HOST_KEYMAP_FULLSCREEN, (int)SDLK_f, mod_ctrl()),
"default fullscreen includes Ctrl+F");
keys[SDL_SCANCODE_TAB] = 1;
check(host_keymap_down(HOST_KEYMAP_TURBO, keys, 0),
"default turbo is held by Tab");
keys[SDL_SCANCODE_TAB] = 0;
check(host_keymap_match(HOST_KEYMAP_VOLUME_UP, (int)SDLK_KP_PLUS, 0),
"default volume up is keypad plus");
check(host_keymap_match(HOST_KEYMAP_VOLUME_DOWN, (int)SDLK_KP_MINUS, 0),
"default volume down is keypad minus");
check(host_keymap_match(HOST_KEYMAP_DISPLAY_PERF, (int)SDLK_f, 0),
"default display perf is F");
f = fopen(cfg, "wb");
check(f != NULL, "create temporary config.ini");
if (!f) return 1;
fputs("[KeyMap]\n"
"Fullscreen = F11\n"
"Turbo = Q\n"
"VolumeUp = Up\n"
"VolumeDown = Down\n"
"DisplayPerf = F10\n",
f);
fclose(f);
host_keymap_load(cfg);
check(!host_keymap_match(HOST_KEYMAP_FULLSCREEN, (int)SDLK_f, mod_ctrl()),
"fullscreen rebind disables Ctrl+F fallback");
check(host_keymap_match(HOST_KEYMAP_FULLSCREEN, (int)SDLK_F11, 0),
"fullscreen rebind uses F11");
memset(keys, 0, sizeof(keys));
keys[SDL_SCANCODE_TAB] = 1;
check(!host_keymap_down(HOST_KEYMAP_TURBO, keys, 0),
"turbo rebind disables Tab fallback");
keys[SDL_SCANCODE_TAB] = 0;
keys[SDL_SCANCODE_Q] = 1;
check(host_keymap_down(HOST_KEYMAP_TURBO, keys, 0),
"turbo rebind uses Q");
check(host_keymap_match(HOST_KEYMAP_VOLUME_UP, (int)SDLK_UP, 0),
"volume up rebind uses Up");
check(host_keymap_match(HOST_KEYMAP_VOLUME_DOWN, (int)SDLK_DOWN, 0),
"volume down rebind uses Down");
check(!host_keymap_match(HOST_KEYMAP_DISPLAY_PERF, (int)SDLK_f, 0),
"display perf rebind disables F fallback");
check(host_keymap_match(HOST_KEYMAP_DISPLAY_PERF, (int)SDLK_F10, 0),
"display perf rebind uses F10");
remove(cfg);
if (failures) {
fprintf(stderr, "host_keymap_test: %d failure(s)\n", failures);
return 1;
}
printf("PASS: host keymap defaults and rebinds\n");
return 0;
}