diff --git a/recompiler/src/config_loader.cpp b/recompiler/src/config_loader.cpp index 2f220785..c7862e45 100644 --- a/recompiler/src/config_loader.cpp +++ b/recompiler/src/config_loader.cpp @@ -329,10 +329,10 @@ static RuntimeConfig parse_runtime_block(const toml::value& cfg, const fs::path& } } } - if (!cfg.contains("runtime")) return rt; - const toml::value& runtime = toml::find(cfg, "runtime"); - if (runtime.contains("language")) // [runtime].language convenience alias - rt.language = toml::find(runtime, "language"); + if (cfg.contains("runtime")) { + const toml::value& runtime = toml::find(cfg, "runtime"); + if (runtime.contains("language")) // [runtime].language convenience alias + rt.language = toml::find(runtime, "language"); if (runtime.contains("debug_port")) { const auto port = toml::find(runtime, "debug_port"); @@ -504,9 +504,10 @@ static RuntimeConfig parse_runtime_block(const toml::value& cfg, const fs::path& if (runtime.contains("overlay_backend")) { rt.overlay_backend = toml::find(runtime, "overlay_backend"); } - if (runtime.contains("overlay_native_block")) { - for (const auto& a : toml::find>(runtime, "overlay_native_block")) { - rt.overlay_native_block.push_back(parse_hex(a, "runtime.overlay_native_block")); + if (runtime.contains("overlay_native_block")) { + for (const auto& a : toml::find>(runtime, "overlay_native_block")) { + rt.overlay_native_block.push_back(parse_hex(a, "runtime.overlay_native_block")); + } } } @@ -704,6 +705,16 @@ static RuntimeConfig parse_runtime_block(const toml::value& cfg, const fs::path& toml::find(ct, "p2_mode"), PAD_MODE_ANALOG); rt.has_default_mode = true; } + if (ct.contains("p1_device")) { + rt.default_p1_device = toml::find(ct, "p1_device"); + if (!rt.default_p1_device.empty()) + rt.has_default_p1_device = true; + } + if (ct.contains("p2_device")) { + rt.default_p2_device = toml::find(ct, "p2_device"); + if (!rt.default_p2_device.empty()) + rt.has_default_p2_device = true; + } if (ct.contains("lock_mode")) { rt.controller_lock_mode = toml::find(ct, "lock_mode"); } diff --git a/recompiler/src/config_loader.h b/recompiler/src/config_loader.h index 2486ec19..871b9d0d 100644 --- a/recompiler/src/config_loader.h +++ b/recompiler/src/config_loader.h @@ -497,6 +497,15 @@ struct RuntimeConfig { int default_p1_mode = PAD_MODE_ANALOG; int default_p2_mode = PAD_MODE_ANALOG; + // p1_device / p2_device: optional per-game default input sources for + // fresh settings and launcher-less boots. Same vocabulary as settings.toml: + // "none", "keyboard", "auto"/"gamepad"/"controller", or an SDL GUID. + // Per-install settings.toml still overrides these defaults. + bool has_default_p1_device = false; + bool has_default_p2_device = false; + std::string default_p1_device; + std::string default_p2_device; + // lock_mode: when true the launcher HIDES the whole pad-mode selector // (Hybrid | Analog | D-Pad) and forces every port to default_p1_mode. For a // game that supports exactly one pad type — e.g. Tomba 2, whose driver only diff --git a/recompiler/tests/recompiler_patch_test.cpp b/recompiler/tests/recompiler_patch_test.cpp index 212f7c93..43cebaf1 100644 --- a/recompiler/tests/recompiler_patch_test.cpp +++ b/recompiler/tests/recompiler_patch_test.cpp @@ -142,6 +142,22 @@ buffer_ms = 60 check(audio_config.runtime.audio_buffer_ms == 60, "parser preserves per-game audio buffer target"); + const auto controller_defaults = write_config(root, "controller-defaults", R"toml( +[controller] +p1_device = "keyboard" +p2_device = "gamepad" +p2_mode = "digital" +)toml"); + const auto controller_defaults_config = + PSXRecompV4::load_game_config(controller_defaults); + check(controller_defaults_config.runtime.has_default_p1_device && + controller_defaults_config.runtime.default_p1_device == "keyboard" && + controller_defaults_config.runtime.has_default_p2_device && + controller_defaults_config.runtime.default_p2_device == "gamepad" && + controller_defaults_config.runtime.default_p2_mode == + PSXRecompV4::PAD_MODE_DIGITAL, + "parser preserves per-game controller device defaults"); + const auto bad_audio_buffer = write_config(root, "bad-audio-buffer", R"toml( [runtime] diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index 65de1371..3a8d2de4 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -10504,6 +10504,10 @@ int main(int argc, char** argv) { if (i >= 2) player_mode[i] = gc.runtime.default_p1_mode; } } + if (gc.runtime.has_default_p1_device) + player_device[0] = gc.runtime.default_p1_device; + if (PSX_MAX_PLAYERS >= 2 && gc.runtime.has_default_p2_device) + player_device[1] = gc.runtime.default_p2_device; for (int i = 0; i < PSX_MAX_PLAYERS; ++i) ctrl_locked_mode[i] = player_mode[i]; ctrl_lock_mode = gc.runtime.controller_lock_mode;