config: Unify config handling under frontend_common
Replaces every way of handling config for each frontend with SimpleIni. frontend_common's Config class is at the center where it saves and loads all of the cross-platform settings and provides a set of pure virtual functions for platform specific settings. As a result of making config handling platform specific, several parts had to be moved to each platform's own config class or to other parts. Default keys were put in platform specific config classes and translatable strings for Qt were moved to shared_translation. Default hotkeys, default_theme, window geometry, and qt metatypes were moved to uisettings. Additionally, to reduce dependence on Qt, QStrings were converted to std::strings where applicable.master
parent
8da5bd27e9
commit
da14c7b8e4
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 382ddbb4b92c0b26aa1b32cefba2002119a5b1f2
|
@ -0,0 +1,70 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "android_config.h"
|
||||||
|
#include "android_settings.h"
|
||||||
|
#include "common/settings_setting.h"
|
||||||
|
|
||||||
|
AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_type)
|
||||||
|
: Config(config_type) {
|
||||||
|
Initialize(config_name);
|
||||||
|
if (config_type != ConfigType::InputProfile) {
|
||||||
|
ReadAndroidValues();
|
||||||
|
SaveAndroidValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidConfig::~AndroidConfig() {
|
||||||
|
if (global) {
|
||||||
|
AndroidConfig::SaveAllValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::ReloadAllValues() {
|
||||||
|
Reload();
|
||||||
|
ReadAndroidValues();
|
||||||
|
SaveAndroidValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::SaveAllValues() {
|
||||||
|
Save();
|
||||||
|
SaveAndroidValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::ReadAndroidValues() {
|
||||||
|
if (global) {
|
||||||
|
ReadAndroidUIValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::ReadAndroidUIValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Android));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Android);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::SaveAndroidValues() {
|
||||||
|
if (global) {
|
||||||
|
SaveAndroidUIValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteToIni();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::SaveAndroidUIValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Android));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Android);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) {
|
||||||
|
auto& map = Settings::values.linkage.by_category;
|
||||||
|
if (map.contains(category)) {
|
||||||
|
return Settings::values.linkage.by_category[category];
|
||||||
|
}
|
||||||
|
return AndroidSettings::values.linkage.by_category[category];
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "frontend_common/config.h"
|
||||||
|
|
||||||
|
class AndroidConfig final : public Config {
|
||||||
|
public:
|
||||||
|
explicit AndroidConfig(const std::string& config_name = "config",
|
||||||
|
ConfigType config_type = ConfigType::GlobalConfig);
|
||||||
|
~AndroidConfig() override;
|
||||||
|
|
||||||
|
void ReloadAllValues() override;
|
||||||
|
void SaveAllValues() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ReadAndroidValues();
|
||||||
|
void ReadAndroidUIValues();
|
||||||
|
void ReadHidbusValues() override {}
|
||||||
|
void ReadDebugControlValues() override {}
|
||||||
|
void ReadPathValues() override {}
|
||||||
|
void ReadShortcutValues() override {}
|
||||||
|
void ReadUIValues() override {}
|
||||||
|
void ReadUIGamelistValues() override {}
|
||||||
|
void ReadUILayoutValues() override {}
|
||||||
|
void ReadMultiplayerValues() override {}
|
||||||
|
|
||||||
|
void SaveAndroidValues();
|
||||||
|
void SaveAndroidUIValues();
|
||||||
|
void SaveHidbusValues() override {}
|
||||||
|
void SaveDebugControlValues() override {}
|
||||||
|
void SavePathValues() override {}
|
||||||
|
void SaveShortcutValues() override {}
|
||||||
|
void SaveUIValues() override {}
|
||||||
|
void SaveUIGamelistValues() override {}
|
||||||
|
void SaveUILayoutValues() override {}
|
||||||
|
void SaveMultiplayerValues() override {}
|
||||||
|
|
||||||
|
std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "uisettings.h"
|
#include "android_settings.h"
|
||||||
|
|
||||||
namespace AndroidSettings {
|
namespace AndroidSettings {
|
||||||
|
|
@ -1,330 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <INIReader.h>
|
|
||||||
#include "common/fs/file.h"
|
|
||||||
#include "common/fs/fs.h"
|
|
||||||
#include "common/fs/path_util.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "common/settings_enums.h"
|
|
||||||
#include "core/hle/service/acc/profile_manager.h"
|
|
||||||
#include "input_common/main.h"
|
|
||||||
#include "jni/config.h"
|
|
||||||
#include "jni/default_ini.h"
|
|
||||||
#include "uisettings.h"
|
|
||||||
|
|
||||||
namespace FS = Common::FS;
|
|
||||||
|
|
||||||
Config::Config(const std::string& config_name, ConfigType config_type)
|
|
||||||
: type(config_type), global{config_type == ConfigType::GlobalConfig} {
|
|
||||||
Initialize(config_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Config::~Config() = default;
|
|
||||||
|
|
||||||
bool Config::LoadINI(const std::string& default_contents, bool retry) {
|
|
||||||
void(FS::CreateParentDir(config_loc));
|
|
||||||
config = std::make_unique<INIReader>(FS::PathToUTF8String(config_loc));
|
|
||||||
const auto config_loc_str = FS::PathToUTF8String(config_loc);
|
|
||||||
if (config->ParseError() < 0) {
|
|
||||||
if (retry) {
|
|
||||||
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...",
|
|
||||||
config_loc_str);
|
|
||||||
|
|
||||||
void(FS::CreateParentDir(config_loc));
|
|
||||||
void(FS::WriteStringToFile(config_loc, FS::FileType::TextFile, default_contents));
|
|
||||||
|
|
||||||
config = std::make_unique<INIReader>(config_loc_str);
|
|
||||||
|
|
||||||
return LoadINI(default_contents, false);
|
|
||||||
}
|
|
||||||
LOG_ERROR(Config, "Failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LOG_INFO(Config, "Successfully loaded {}", config_loc_str);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
|
|
||||||
std::string setting_value = config->Get(group, setting.GetLabel(), setting.GetDefault());
|
|
||||||
if (setting_value.empty()) {
|
|
||||||
setting_value = setting.GetDefault();
|
|
||||||
}
|
|
||||||
setting = std::move(setting_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
|
|
||||||
setting = config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Type, bool ranged>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
|
|
||||||
setting = static_cast<Type>(
|
|
||||||
config->GetInteger(group, setting.GetLabel(), static_cast<long>(setting.GetDefault())));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::ReadValues() {
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.touch_device);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
|
|
||||||
Settings::values.touchscreen.enabled =
|
|
||||||
config->GetBoolean("ControlsGeneral", "touch_enabled", true);
|
|
||||||
Settings::values.touchscreen.rotation_angle =
|
|
||||||
config->GetInteger("ControlsGeneral", "touch_angle", 0);
|
|
||||||
Settings::values.touchscreen.diameter_x =
|
|
||||||
config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
|
|
||||||
Settings::values.touchscreen.diameter_y =
|
|
||||||
config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
|
|
||||||
|
|
||||||
int num_touch_from_button_maps =
|
|
||||||
config->GetInteger("ControlsGeneral", "touch_from_button_map", 0);
|
|
||||||
if (num_touch_from_button_maps > 0) {
|
|
||||||
for (int i = 0; i < num_touch_from_button_maps; ++i) {
|
|
||||||
Settings::TouchFromButtonMap map;
|
|
||||||
map.name = config->Get("ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) +
|
|
||||||
std::string("_name"),
|
|
||||||
"default");
|
|
||||||
const int num_touch_maps = config->GetInteger(
|
|
||||||
"ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"),
|
|
||||||
0);
|
|
||||||
map.buttons.reserve(num_touch_maps);
|
|
||||||
|
|
||||||
for (int j = 0; j < num_touch_maps; ++j) {
|
|
||||||
std::string touch_mapping =
|
|
||||||
config->Get("ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) +
|
|
||||||
std::string("_bind_") + std::to_string(j),
|
|
||||||
"");
|
|
||||||
map.buttons.emplace_back(std::move(touch_mapping));
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.touch_from_button_maps.emplace_back(std::move(map));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Settings::values.touch_from_button_maps.emplace_back(
|
|
||||||
Settings::TouchFromButtonMap{"default", {}});
|
|
||||||
num_touch_from_button_maps = 1;
|
|
||||||
}
|
|
||||||
Settings::values.touch_from_button_map_index = std::clamp(
|
|
||||||
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
|
|
||||||
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
|
|
||||||
|
|
||||||
// Data Storage
|
|
||||||
ReadSetting("Data Storage", Settings::values.use_virtual_sd);
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::NANDDir,
|
|
||||||
config->Get("Data Storage", "nand_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::SDMCDir,
|
|
||||||
config->Get("Data Storage", "sdmc_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::LoadDir,
|
|
||||||
config->Get("Data Storage", "load_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::DumpDir,
|
|
||||||
config->Get("Data Storage", "dump_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
|
|
||||||
ReadSetting("Data Storage", Settings::values.gamecard_inserted);
|
|
||||||
ReadSetting("Data Storage", Settings::values.gamecard_current_game);
|
|
||||||
ReadSetting("Data Storage", Settings::values.gamecard_path);
|
|
||||||
|
|
||||||
// System
|
|
||||||
ReadSetting("System", Settings::values.current_user);
|
|
||||||
Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
|
|
||||||
Service::Account::MAX_USERS - 1);
|
|
||||||
|
|
||||||
// Disable docked mode by default on Android
|
|
||||||
Settings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false)
|
|
||||||
? Settings::ConsoleMode::Docked
|
|
||||||
: Settings::ConsoleMode::Handheld);
|
|
||||||
|
|
||||||
const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false);
|
|
||||||
if (rng_seed_enabled) {
|
|
||||||
Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0));
|
|
||||||
} else {
|
|
||||||
Settings::values.rng_seed.SetValue(0);
|
|
||||||
}
|
|
||||||
Settings::values.rng_seed_enabled.SetValue(rng_seed_enabled);
|
|
||||||
|
|
||||||
const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false);
|
|
||||||
if (custom_rtc_enabled) {
|
|
||||||
Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0);
|
|
||||||
} else {
|
|
||||||
Settings::values.custom_rtc = 0;
|
|
||||||
}
|
|
||||||
Settings::values.custom_rtc_enabled = custom_rtc_enabled;
|
|
||||||
|
|
||||||
ReadSetting("System", Settings::values.language_index);
|
|
||||||
ReadSetting("System", Settings::values.region_index);
|
|
||||||
ReadSetting("System", Settings::values.time_zone_index);
|
|
||||||
ReadSetting("System", Settings::values.sound_index);
|
|
||||||
|
|
||||||
// Core
|
|
||||||
ReadSetting("Core", Settings::values.use_multi_core);
|
|
||||||
ReadSetting("Core", Settings::values.memory_layout_mode);
|
|
||||||
|
|
||||||
// Cpu
|
|
||||||
ReadSetting("Cpu", Settings::values.cpu_accuracy);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpu_debug_mode);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_page_tables);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_block_linking);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_return_stack_buffer);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_fast_dispatcher);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_context_elimination);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_const_prop);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_misc_ir);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_ignore_memory_aborts);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor);
|
|
||||||
|
|
||||||
// Renderer
|
|
||||||
ReadSetting("Renderer", Settings::values.renderer_backend);
|
|
||||||
ReadSetting("Renderer", Settings::values.renderer_debug);
|
|
||||||
ReadSetting("Renderer", Settings::values.renderer_shader_feedback);
|
|
||||||
ReadSetting("Renderer", Settings::values.enable_nsight_aftermath);
|
|
||||||
ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks);
|
|
||||||
ReadSetting("Renderer", Settings::values.vulkan_device);
|
|
||||||
|
|
||||||
ReadSetting("Renderer", Settings::values.resolution_setup);
|
|
||||||
ReadSetting("Renderer", Settings::values.scaling_filter);
|
|
||||||
ReadSetting("Renderer", Settings::values.fsr_sharpening_slider);
|
|
||||||
ReadSetting("Renderer", Settings::values.anti_aliasing);
|
|
||||||
ReadSetting("Renderer", Settings::values.fullscreen_mode);
|
|
||||||
ReadSetting("Renderer", Settings::values.aspect_ratio);
|
|
||||||
ReadSetting("Renderer", Settings::values.max_anisotropy);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_speed_limit);
|
|
||||||
ReadSetting("Renderer", Settings::values.speed_limit);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
|
|
||||||
ReadSetting("Renderer", Settings::values.vsync_mode);
|
|
||||||
ReadSetting("Renderer", Settings::values.shader_backend);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
|
|
||||||
ReadSetting("Renderer", Settings::values.nvdec_emulation);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache);
|
|
||||||
|
|
||||||
ReadSetting("Renderer", Settings::values.bg_red);
|
|
||||||
ReadSetting("Renderer", Settings::values.bg_green);
|
|
||||||
ReadSetting("Renderer", Settings::values.bg_blue);
|
|
||||||
|
|
||||||
// Use GPU accuracy normal by default on Android
|
|
||||||
Settings::values.gpu_accuracy = static_cast<Settings::GpuAccuracy>(config->GetInteger(
|
|
||||||
"Renderer", "gpu_accuracy", static_cast<u32>(Settings::GpuAccuracy::Normal)));
|
|
||||||
|
|
||||||
// Use GPU default anisotropic filtering on Android
|
|
||||||
Settings::values.max_anisotropy =
|
|
||||||
static_cast<Settings::AnisotropyMode>(config->GetInteger("Renderer", "max_anisotropy", 1));
|
|
||||||
|
|
||||||
// Disable ASTC compute by default on Android
|
|
||||||
Settings::values.accelerate_astc.SetValue(
|
|
||||||
config->GetBoolean("Renderer", "accelerate_astc", false) ? Settings::AstcDecodeMode::Gpu
|
|
||||||
: Settings::AstcDecodeMode::Cpu);
|
|
||||||
|
|
||||||
// Enable asynchronous presentation by default on Android
|
|
||||||
Settings::values.async_presentation =
|
|
||||||
config->GetBoolean("Renderer", "async_presentation", true);
|
|
||||||
|
|
||||||
// Disable force_max_clock by default on Android
|
|
||||||
Settings::values.renderer_force_max_clock =
|
|
||||||
config->GetBoolean("Renderer", "force_max_clock", false);
|
|
||||||
|
|
||||||
// Disable use_reactive_flushing by default on Android
|
|
||||||
Settings::values.use_reactive_flushing =
|
|
||||||
config->GetBoolean("Renderer", "use_reactive_flushing", false);
|
|
||||||
|
|
||||||
// Audio
|
|
||||||
ReadSetting("Audio", Settings::values.sink_id);
|
|
||||||
ReadSetting("Audio", Settings::values.audio_output_device_id);
|
|
||||||
ReadSetting("Audio", Settings::values.volume);
|
|
||||||
|
|
||||||
// Miscellaneous
|
|
||||||
// log_filter has a different default here than from common
|
|
||||||
Settings::values.log_filter = "*:Info";
|
|
||||||
ReadSetting("Miscellaneous", Settings::values.use_dev_keys);
|
|
||||||
|
|
||||||
// Debugging
|
|
||||||
Settings::values.record_frame_times =
|
|
||||||
config->GetBoolean("Debugging", "record_frame_times", false);
|
|
||||||
ReadSetting("Debugging", Settings::values.dump_exefs);
|
|
||||||
ReadSetting("Debugging", Settings::values.dump_nso);
|
|
||||||
ReadSetting("Debugging", Settings::values.enable_fs_access_log);
|
|
||||||
ReadSetting("Debugging", Settings::values.reporting_services);
|
|
||||||
ReadSetting("Debugging", Settings::values.quest_flag);
|
|
||||||
ReadSetting("Debugging", Settings::values.use_debug_asserts);
|
|
||||||
ReadSetting("Debugging", Settings::values.use_auto_stub);
|
|
||||||
ReadSetting("Debugging", Settings::values.disable_macro_jit);
|
|
||||||
ReadSetting("Debugging", Settings::values.disable_macro_hle);
|
|
||||||
ReadSetting("Debugging", Settings::values.use_gdbstub);
|
|
||||||
ReadSetting("Debugging", Settings::values.gdbstub_port);
|
|
||||||
|
|
||||||
const auto title_list = config->Get("AddOns", "title_ids", "");
|
|
||||||
std::stringstream ss(title_list);
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(ss, line, '|')) {
|
|
||||||
const auto title_id = std::strtoul(line.c_str(), nullptr, 16);
|
|
||||||
const auto disabled_list = config->Get("AddOns", "disabled_" + line, "");
|
|
||||||
|
|
||||||
std::stringstream inner_ss(disabled_list);
|
|
||||||
std::string inner_line;
|
|
||||||
std::vector<std::string> out;
|
|
||||||
while (std::getline(inner_ss, inner_line, '|')) {
|
|
||||||
out.push_back(inner_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.disabled_addons.insert_or_assign(title_id, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Web Service
|
|
||||||
ReadSetting("WebService", Settings::values.enable_telemetry);
|
|
||||||
ReadSetting("WebService", Settings::values.web_api_url);
|
|
||||||
ReadSetting("WebService", Settings::values.yuzu_username);
|
|
||||||
ReadSetting("WebService", Settings::values.yuzu_token);
|
|
||||||
|
|
||||||
// Network
|
|
||||||
ReadSetting("Network", Settings::values.network_interface);
|
|
||||||
|
|
||||||
// Android
|
|
||||||
ReadSetting("Android", AndroidSettings::values.picture_in_picture);
|
|
||||||
ReadSetting("Android", AndroidSettings::values.screen_layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::Initialize(const std::string& config_name) {
|
|
||||||
const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir);
|
|
||||||
const auto config_file = fmt::format("{}.ini", config_name);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case ConfigType::GlobalConfig:
|
|
||||||
config_loc = FS::PathToUTF8String(fs_config_loc / config_file);
|
|
||||||
break;
|
|
||||||
case ConfigType::PerGameConfig:
|
|
||||||
config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file));
|
|
||||||
break;
|
|
||||||
case ConfigType::InputProfile:
|
|
||||||
config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file);
|
|
||||||
LoadINI(DefaultINI::android_config_file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoadINI(DefaultINI::android_config_file);
|
|
||||||
ReadValues();
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
|
|
||||||
class INIReader;
|
|
||||||
|
|
||||||
class Config {
|
|
||||||
bool LoadINI(const std::string& default_contents = "", bool retry = true);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum class ConfigType {
|
|
||||||
GlobalConfig,
|
|
||||||
PerGameConfig,
|
|
||||||
InputProfile,
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit Config(const std::string& config_name = "config",
|
|
||||||
ConfigType config_type = ConfigType::GlobalConfig);
|
|
||||||
~Config();
|
|
||||||
|
|
||||||
void Initialize(const std::string& config_name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Applies a value read from the config to a Setting.
|
|
||||||
*
|
|
||||||
* @param group The name of the INI group
|
|
||||||
* @param setting The yuzu setting to modify
|
|
||||||
*/
|
|
||||||
template <typename Type, bool ranged>
|
|
||||||
void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
|
|
||||||
|
|
||||||
void ReadValues();
|
|
||||||
|
|
||||||
const ConfigType type;
|
|
||||||
std::unique_ptr<INIReader> config;
|
|
||||||
std::string config_loc;
|
|
||||||
const bool global;
|
|
||||||
};
|
|
@ -0,0 +1,10 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
add_library(frontend_common STATIC
|
||||||
|
config.cpp
|
||||||
|
config.h
|
||||||
|
)
|
||||||
|
|
||||||
|
create_target_directory_groups(frontend_common)
|
||||||
|
target_link_libraries(frontend_common PUBLIC core SimpleIni PRIVATE common Boost::headers)
|
@ -0,0 +1,931 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include "common/fs/fs.h"
|
||||||
|
#include "common/fs/path_util.h"
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "common/settings_common.h"
|
||||||
|
#include "common/settings_enums.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/service/acc/profile_manager.h"
|
||||||
|
#include "core/hle/service/hid/controllers/npad.h"
|
||||||
|
#include "network/network.h"
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
|
namespace FS = Common::FS;
|
||||||
|
|
||||||
|
Config::Config(const ConfigType config_type)
|
||||||
|
: type(config_type), global{config_type == ConfigType::GlobalConfig} {}
|
||||||
|
|
||||||
|
void Config::Initialize(const std::string& config_name) {
|
||||||
|
const std::filesystem::path fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir);
|
||||||
|
const auto config_file = fmt::format("{}.ini", config_name);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ConfigType::GlobalConfig:
|
||||||
|
config_loc = FS::PathToUTF8String(fs_config_loc / config_file);
|
||||||
|
void(FS::CreateParentDir(config_loc));
|
||||||
|
SetUpIni();
|
||||||
|
Reload();
|
||||||
|
break;
|
||||||
|
case ConfigType::PerGameConfig:
|
||||||
|
config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file));
|
||||||
|
void(FS::CreateParentDir(config_loc));
|
||||||
|
SetUpIni();
|
||||||
|
Reload();
|
||||||
|
break;
|
||||||
|
case ConfigType::InputProfile:
|
||||||
|
config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file);
|
||||||
|
void(FS::CreateParentDir(config_loc));
|
||||||
|
SetUpIni();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::Initialize(const std::optional<std::string> config_path) {
|
||||||
|
const std::filesystem::path default_sdl_config_path =
|
||||||
|
FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini";
|
||||||
|
config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path));
|
||||||
|
void(FS::CreateParentDir(config_loc));
|
||||||
|
SetUpIni();
|
||||||
|
Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::WriteToIni() const {
|
||||||
|
if (const SI_Error rc = config->SaveFile(config_loc.c_str()); rc < 0) {
|
||||||
|
LOG_ERROR(Frontend, "Config file could not be saved!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SetUpIni() {
|
||||||
|
config = std::make_unique<CSimpleIniA>();
|
||||||
|
config->SetUnicode(true);
|
||||||
|
config->SetSpaces(false);
|
||||||
|
config->LoadFile(config_loc.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::IsCustomConfig() const {
|
||||||
|
return type == ConfigType::PerGameConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadPlayerValues(const std::size_t player_index) {
|
||||||
|
std::string player_prefix;
|
||||||
|
if (type != ConfigType::InputProfile) {
|
||||||
|
player_prefix.append("player_").append(ToString(player_index)).append("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
const auto profile_name =
|
||||||
|
ReadStringSetting(std::string(player_prefix).append("profile_name"));
|
||||||
|
if (profile_name.empty()) {
|
||||||
|
// Use the global input config
|
||||||
|
player = Settings::values.players.GetValue(true)[player_index];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.profile_name = profile_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player_prefix.empty() && Settings::IsConfiguringGlobal()) {
|
||||||
|
const auto controller = static_cast<Settings::ControllerType>(
|
||||||
|
ReadIntegerSetting(std::string(player_prefix).append("type"),
|
||||||
|
static_cast<u8>(Settings::ControllerType::ProController)));
|
||||||
|
|
||||||
|
if (controller == Settings::ControllerType::LeftJoycon ||
|
||||||
|
controller == Settings::ControllerType::RightJoycon) {
|
||||||
|
player.controller_type = controller;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::string connected_key = player_prefix;
|
||||||
|
player.connected = ReadBooleanSetting(connected_key.append("connected"),
|
||||||
|
std::make_optional(player_index == 0));
|
||||||
|
|
||||||
|
player.controller_type = static_cast<Settings::ControllerType>(
|
||||||
|
ReadIntegerSetting(std::string(player_prefix).append("type"),
|
||||||
|
static_cast<u8>(Settings::ControllerType::ProController)));
|
||||||
|
|
||||||
|
player.vibration_enabled = ReadBooleanSetting(
|
||||||
|
std::string(player_prefix).append("vibration_enabled"), std::make_optional(true));
|
||||||
|
|
||||||
|
player.vibration_strength = static_cast<int>(
|
||||||
|
ReadIntegerSetting(std::string(player_prefix).append("vibration_strength"), 100));
|
||||||
|
|
||||||
|
player.body_color_left = static_cast<u32>(ReadIntegerSetting(
|
||||||
|
std::string(player_prefix).append("body_color_left"), Settings::JOYCON_BODY_NEON_BLUE));
|
||||||
|
player.body_color_right = static_cast<u32>(ReadIntegerSetting(
|
||||||
|
std::string(player_prefix).append("body_color_right"), Settings::JOYCON_BODY_NEON_RED));
|
||||||
|
player.button_color_left = static_cast<u32>(
|
||||||
|
ReadIntegerSetting(std::string(player_prefix).append("button_color_left"),
|
||||||
|
Settings::JOYCON_BUTTONS_NEON_BLUE));
|
||||||
|
player.button_color_right = static_cast<u32>(
|
||||||
|
ReadIntegerSetting(std::string(player_prefix).append("button_color_right"),
|
||||||
|
Settings::JOYCON_BUTTONS_NEON_RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadTouchscreenValues() {
|
||||||
|
Settings::values.touchscreen.enabled =
|
||||||
|
ReadBooleanSetting(std::string("touchscreen_enabled"), std::make_optional(true));
|
||||||
|
Settings::values.touchscreen.rotation_angle =
|
||||||
|
static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_angle"), 0));
|
||||||
|
Settings::values.touchscreen.diameter_x =
|
||||||
|
static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_x"), 15));
|
||||||
|
Settings::values.touchscreen.diameter_y =
|
||||||
|
static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_y"), 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadAudioValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Audio));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Audio);
|
||||||
|
ReadCategory(Settings::Category::UiAudio);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadControlValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Controls);
|
||||||
|
|
||||||
|
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||||
|
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||||
|
ReadPlayerValues(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable docked mode if handheld is selected
|
||||||
|
const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
|
||||||
|
if (controller_type == Settings::ControllerType::Handheld) {
|
||||||
|
Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig());
|
||||||
|
Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
EndGroup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ReadTouchscreenValues();
|
||||||
|
ReadMotionTouchValues();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadMotionTouchValues() {
|
||||||
|
int num_touch_from_button_maps = BeginArray(std::string("touch_from_button_maps"));
|
||||||
|
|
||||||
|
if (num_touch_from_button_maps > 0) {
|
||||||
|
for (int i = 0; i < num_touch_from_button_maps; ++i) {
|
||||||
|
SetArrayIndex(i);
|
||||||
|
|
||||||
|
Settings::TouchFromButtonMap map;
|
||||||
|
map.name = ReadStringSetting(std::string("name"), std::string("default"));
|
||||||
|
|
||||||
|
const int num_touch_maps = BeginArray(std::string("entries"));
|
||||||
|
map.buttons.reserve(num_touch_maps);
|
||||||
|
for (int j = 0; j < num_touch_maps; j++) {
|
||||||
|
SetArrayIndex(j);
|
||||||
|
std::string touch_mapping = ReadStringSetting(std::string("bind"));
|
||||||
|
map.buttons.emplace_back(std::move(touch_mapping));
|
||||||
|
}
|
||||||
|
EndArray(); // entries
|
||||||
|
Settings::values.touch_from_button_maps.emplace_back(std::move(map));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Settings::values.touch_from_button_maps.emplace_back(
|
||||||
|
Settings::TouchFromButtonMap{"default", {}});
|
||||||
|
num_touch_from_button_maps = 1;
|
||||||
|
}
|
||||||
|
EndArray(); // touch_from_button_maps
|
||||||
|
|
||||||
|
Settings::values.touch_from_button_map_index = std::clamp(
|
||||||
|
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadCoreValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Core));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Core);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadDataStorageValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage));
|
||||||
|
|
||||||
|
FS::SetYuzuPath(FS::YuzuPath::NANDDir, ReadStringSetting(std::string("nand_directory")));
|
||||||
|
FS::SetYuzuPath(FS::YuzuPath::SDMCDir, ReadStringSetting(std::string("sdmc_directory")));
|
||||||
|
FS::SetYuzuPath(FS::YuzuPath::LoadDir, ReadStringSetting(std::string("load_directory")));
|
||||||
|
FS::SetYuzuPath(FS::YuzuPath::DumpDir, ReadStringSetting(std::string("dump_directory")));
|
||||||
|
FS::SetYuzuPath(FS::YuzuPath::TASDir, ReadStringSetting(std::string("tas_directory")));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::DataStorage);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadDebuggingValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging));
|
||||||
|
|
||||||
|
// Intentionally not using the QT default setting as this is intended to be changed in the ini
|
||||||
|
Settings::values.record_frame_times =
|
||||||
|
ReadBooleanSetting(std::string("record_frame_times"), std::make_optional(false));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Debugging);
|
||||||
|
ReadCategory(Settings::Category::DebuggingGraphics);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadServiceValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Services));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Services);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadDisabledAddOnValues() {
|
||||||
|
// Custom config section
|
||||||
|
BeginGroup(std::string("DisabledAddOns"));
|
||||||
|
|
||||||
|
const int size = BeginArray(std::string(""));
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
SetArrayIndex(i);
|
||||||
|
const auto title_id = ReadIntegerSetting(std::string("title_id"), 0);
|
||||||
|
std::vector<std::string> out;
|
||||||
|
const int d_size = BeginArray("disabled");
|
||||||
|
for (int j = 0; j < d_size; ++j) {
|
||||||
|
SetArrayIndex(j);
|
||||||
|
out.push_back(ReadStringSetting(std::string("d"), std::string("")));
|
||||||
|
}
|
||||||
|
EndArray(); // d
|
||||||
|
Settings::values.disabled_addons.insert_or_assign(title_id, out);
|
||||||
|
}
|
||||||
|
EndArray(); // Base disabled addons array - Has no base key
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadMiscellaneousValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Miscellaneous));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Miscellaneous);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadCpuValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Cpu));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Cpu);
|
||||||
|
ReadCategory(Settings::Category::CpuDebug);
|
||||||
|
ReadCategory(Settings::Category::CpuUnsafe);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadRendererValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Renderer));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Renderer);
|
||||||
|
ReadCategory(Settings::Category::RendererAdvanced);
|
||||||
|
ReadCategory(Settings::Category::RendererDebug);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadScreenshotValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Screenshots);
|
||||||
|
FS::SetYuzuPath(FS::YuzuPath::ScreenshotsDir,
|
||||||
|
ReadStringSetting(std::string("screenshot_path"),
|
||||||
|
FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)));
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadSystemValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::System));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::System);
|
||||||
|
ReadCategory(Settings::Category::SystemAudio);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadWebServiceValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::WebService));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::WebService);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadNetworkValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Services));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Network);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadValues() {
|
||||||
|
if (global) {
|
||||||
|
ReadDataStorageValues();
|
||||||
|
ReadDebuggingValues();
|
||||||
|
ReadDisabledAddOnValues();
|
||||||
|
ReadNetworkValues();
|
||||||
|
ReadServiceValues();
|
||||||
|
ReadWebServiceValues();
|
||||||
|
ReadMiscellaneousValues();
|
||||||
|
}
|
||||||
|
ReadControlValues();
|
||||||
|
ReadCoreValues();
|
||||||
|
ReadCpuValues();
|
||||||
|
ReadRendererValues();
|
||||||
|
ReadAudioValues();
|
||||||
|
ReadSystemValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SavePlayerValues(const std::size_t player_index) {
|
||||||
|
std::string player_prefix;
|
||||||
|
if (type != ConfigType::InputProfile) {
|
||||||
|
player_prefix = std::string("player_").append(ToString(player_index)).append("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
if (player.profile_name.empty()) {
|
||||||
|
// No custom profile selected
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WriteSetting(std::string(player_prefix).append("profile_name"), player.profile_name,
|
||||||
|
std::make_optional(std::string("")));
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteSetting(std::string(player_prefix).append("type"), static_cast<u8>(player.controller_type),
|
||||||
|
std::make_optional(static_cast<u8>(Settings::ControllerType::ProController)));
|
||||||
|
|
||||||
|
if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) {
|
||||||
|
WriteSetting(std::string(player_prefix).append("connected"), player.connected,
|
||||||
|
std::make_optional(player_index == 0));
|
||||||
|
WriteSetting(std::string(player_prefix).append("vibration_enabled"),
|
||||||
|
player.vibration_enabled, std::make_optional(true));
|
||||||
|
WriteSetting(std::string(player_prefix).append("vibration_strength"),
|
||||||
|
player.vibration_strength, std::make_optional(100));
|
||||||
|
WriteSetting(std::string(player_prefix).append("body_color_left"), player.body_color_left,
|
||||||
|
std::make_optional(Settings::JOYCON_BODY_NEON_BLUE));
|
||||||
|
WriteSetting(std::string(player_prefix).append("body_color_right"), player.body_color_right,
|
||||||
|
std::make_optional(Settings::JOYCON_BODY_NEON_RED));
|
||||||
|
WriteSetting(std::string(player_prefix).append("button_color_left"),
|
||||||
|
player.button_color_left,
|
||||||
|
std::make_optional(Settings::JOYCON_BUTTONS_NEON_BLUE));
|
||||||
|
WriteSetting(std::string(player_prefix).append("button_color_right"),
|
||||||
|
player.button_color_right,
|
||||||
|
std::make_optional(Settings::JOYCON_BUTTONS_NEON_RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveTouchscreenValues() {
|
||||||
|
const auto& touchscreen = Settings::values.touchscreen;
|
||||||
|
|
||||||
|
WriteSetting(std::string("touchscreen_enabled"), touchscreen.enabled, std::make_optional(true));
|
||||||
|
|
||||||
|
WriteSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle,
|
||||||
|
std::make_optional(static_cast<u32>(0)));
|
||||||
|
WriteSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x,
|
||||||
|
std::make_optional(static_cast<u32>(15)));
|
||||||
|
WriteSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y,
|
||||||
|
std::make_optional(static_cast<u32>(15)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveMotionTouchValues() {
|
||||||
|
BeginArray(std::string("touch_from_button_maps"));
|
||||||
|
for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
|
||||||
|
SetArrayIndex(static_cast<int>(p));
|
||||||
|
WriteSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name,
|
||||||
|
std::make_optional(std::string("default")));
|
||||||
|
|
||||||
|
BeginArray(std::string("entries"));
|
||||||
|
for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size();
|
||||||
|
++q) {
|
||||||
|
SetArrayIndex(static_cast<int>(q));
|
||||||
|
WriteSetting(std::string("bind"),
|
||||||
|
Settings::values.touch_from_button_maps[p].buttons[q]);
|
||||||
|
}
|
||||||
|
EndArray(); // entries
|
||||||
|
}
|
||||||
|
EndArray(); // touch_from_button_maps
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveValues() {
|
||||||
|
if (global) {
|
||||||
|
SaveDataStorageValues();
|
||||||
|
SaveDebuggingValues();
|
||||||
|
SaveDisabledAddOnValues();
|
||||||
|
SaveNetworkValues();
|
||||||
|
SaveWebServiceValues();
|
||||||
|
SaveMiscellaneousValues();
|
||||||
|
}
|
||||||
|
SaveControlValues();
|
||||||
|
SaveCoreValues();
|
||||||
|
SaveCpuValues();
|
||||||
|
SaveRendererValues();
|
||||||
|
SaveAudioValues();
|
||||||
|
SaveSystemValues();
|
||||||
|
|
||||||
|
WriteToIni();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveAudioValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Audio));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Audio);
|
||||||
|
WriteCategory(Settings::Category::UiAudio);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveControlValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Controls);
|
||||||
|
|
||||||
|
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||||
|
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||||
|
SavePlayerValues(p);
|
||||||
|
}
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
EndGroup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SaveTouchscreenValues();
|
||||||
|
SaveMotionTouchValues();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveCoreValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Core));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Core);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveDataStorageValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage));
|
||||||
|
|
||||||
|
WriteSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir),
|
||||||
|
std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
|
||||||
|
WriteSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir),
|
||||||
|
std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
|
||||||
|
WriteSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir),
|
||||||
|
std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
|
||||||
|
WriteSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir),
|
||||||
|
std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
|
||||||
|
WriteSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir),
|
||||||
|
std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir)));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::DataStorage);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveDebuggingValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging));
|
||||||
|
|
||||||
|
// Intentionally not using the QT default setting as this is intended to be changed in the ini
|
||||||
|
WriteSetting(std::string("record_frame_times"), Settings::values.record_frame_times);
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Debugging);
|
||||||
|
WriteCategory(Settings::Category::DebuggingGraphics);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveNetworkValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Services));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Network);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveDisabledAddOnValues() {
|
||||||
|
// Custom config section
|
||||||
|
BeginGroup(std::string("DisabledAddOns"));
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
BeginArray(std::string(""));
|
||||||
|
for (const auto& elem : Settings::values.disabled_addons) {
|
||||||
|
SetArrayIndex(i);
|
||||||
|
WriteSetting(std::string("title_id"), elem.first, std::make_optional(static_cast<u64>(0)));
|
||||||
|
BeginArray(std::string("disabled"));
|
||||||
|
for (std::size_t j = 0; j < elem.second.size(); ++j) {
|
||||||
|
SetArrayIndex(static_cast<int>(j));
|
||||||
|
WriteSetting(std::string("d"), elem.second[j], std::make_optional(std::string("")));
|
||||||
|
}
|
||||||
|
EndArray(); // disabled
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
EndArray(); // Base disabled addons array - Has no base key
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveMiscellaneousValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Miscellaneous));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Miscellaneous);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveCpuValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Cpu));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Cpu);
|
||||||
|
WriteCategory(Settings::Category::CpuDebug);
|
||||||
|
WriteCategory(Settings::Category::CpuUnsafe);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveRendererValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Renderer));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Renderer);
|
||||||
|
WriteCategory(Settings::Category::RendererAdvanced);
|
||||||
|
WriteCategory(Settings::Category::RendererDebug);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveScreenshotValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots));
|
||||||
|
|
||||||
|
WriteSetting(std::string("screenshot_path"),
|
||||||
|
FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir));
|
||||||
|
WriteCategory(Settings::Category::Screenshots);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveSystemValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::System));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::System);
|
||||||
|
WriteCategory(Settings::Category::SystemAudio);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SaveWebServiceValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::WebService));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::WebService);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::ReadBooleanSetting(const std::string& key, const std::optional<bool> default_value) {
|
||||||
|
std::string full_key = GetFullKey(key, false);
|
||||||
|
if (!default_value.has_value()) {
|
||||||
|
return config->GetBoolValue(GetSection().c_str(), full_key.c_str(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->GetBoolValue(GetSection().c_str(),
|
||||||
|
std::string(full_key).append("\\default").c_str(), false)) {
|
||||||
|
return static_cast<bool>(default_value.value());
|
||||||
|
} else {
|
||||||
|
return config->GetBoolValue(GetSection().c_str(), full_key.c_str(),
|
||||||
|
static_cast<bool>(default_value.value()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Config::ReadIntegerSetting(const std::string& key, const std::optional<s64> default_value) {
|
||||||
|
std::string full_key = GetFullKey(key, false);
|
||||||
|
if (!default_value.has_value()) {
|
||||||
|
try {
|
||||||
|
return std::stoll(
|
||||||
|
std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0")));
|
||||||
|
} catch (...) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 result = 0;
|
||||||
|
if (config->GetBoolValue(GetSection().c_str(),
|
||||||
|
std::string(full_key).append("\\default").c_str(), true)) {
|
||||||
|
result = default_value.value();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
result = std::stoll(std::string(config->GetValue(
|
||||||
|
GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str())));
|
||||||
|
} catch (...) {
|
||||||
|
result = default_value.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Config::ReadDoubleSetting(const std::string& key,
|
||||||
|
const std::optional<double> default_value) {
|
||||||
|
std::string full_key = GetFullKey(key, false);
|
||||||
|
if (!default_value.has_value()) {
|
||||||
|
return config->GetDoubleValue(GetSection().c_str(), full_key.c_str(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double result;
|
||||||
|
if (config->GetBoolValue(GetSection().c_str(),
|
||||||
|
std::string(full_key).append("\\default").c_str(), true)) {
|
||||||
|
result = default_value.value();
|
||||||
|
} else {
|
||||||
|
result =
|
||||||
|
config->GetDoubleValue(GetSection().c_str(), full_key.c_str(), default_value.value());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::ReadStringSetting(const std::string& key,
|
||||||
|
const std::optional<std::string> default_value) {
|
||||||
|
std::string result;
|
||||||
|
std::string full_key = GetFullKey(key, false);
|
||||||
|
if (!default_value.has_value()) {
|
||||||
|
result = config->GetValue(GetSection().c_str(), full_key.c_str(), "");
|
||||||
|
boost::replace_all(result, "\"", "");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->GetBoolValue(GetSection().c_str(),
|
||||||
|
std::string(full_key).append("\\default").c_str(), true)) {
|
||||||
|
result = default_value.value();
|
||||||
|
} else {
|
||||||
|
result =
|
||||||
|
config->GetValue(GetSection().c_str(), full_key.c_str(), default_value.value().c_str());
|
||||||
|
}
|
||||||
|
boost::replace_all(result, "\"", "");
|
||||||
|
boost::replace_all(result, "//", "/");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::Exists(const std::string& section, const std::string& key) const {
|
||||||
|
const std::string value = config->GetValue(section.c_str(), key.c_str(), "");
|
||||||
|
return !value.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
void Config::WriteSetting(const std::string& key, const Type& value,
|
||||||
|
const std::optional<Type>& default_value,
|
||||||
|
const std::optional<bool>& use_global) {
|
||||||
|
std::string full_key = GetFullKey(key, false);
|
||||||
|
|
||||||
|
std::string saved_value;
|
||||||
|
std::string string_default;
|
||||||
|
if constexpr (std::is_same_v<Type, std::string>) {
|
||||||
|
saved_value.append(AdjustOutputString(value));
|
||||||
|
if (default_value.has_value()) {
|
||||||
|
string_default.append(AdjustOutputString(default_value.value()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
saved_value.append(AdjustOutputString(ToString(value)));
|
||||||
|
if (default_value.has_value()) {
|
||||||
|
string_default.append(ToString(default_value.value()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_value.has_value() && use_global.has_value()) {
|
||||||
|
if (!global) {
|
||||||
|
WriteSettingInternal(std::string(full_key).append("\\global"),
|
||||||
|
ToString(use_global.value()));
|
||||||
|
}
|
||||||
|
if (global || use_global.value() == false) {
|
||||||
|
WriteSettingInternal(std::string(full_key).append("\\default"),
|
||||||
|
ToString(string_default == saved_value));
|
||||||
|
WriteSettingInternal(full_key, saved_value);
|
||||||
|
}
|
||||||
|
} else if (default_value.has_value() && !use_global.has_value()) {
|
||||||
|
WriteSettingInternal(std::string(full_key).append("\\default"),
|
||||||
|
ToString(string_default == saved_value));
|
||||||
|
WriteSettingInternal(full_key, saved_value);
|
||||||
|
} else {
|
||||||
|
WriteSettingInternal(full_key, saved_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::WriteSettingInternal(const std::string& key, const std::string& value) {
|
||||||
|
config->SetValue(GetSection().c_str(), key.c_str(), value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::Reload() {
|
||||||
|
ReadValues();
|
||||||
|
// To apply default value changes
|
||||||
|
SaveValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::Save() {
|
||||||
|
SaveValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ClearControlPlayerValues() const {
|
||||||
|
// If key is an empty string, all keys in the current group() are removed.
|
||||||
|
const char* section = Settings::TranslateCategory(Settings::Category::Controls);
|
||||||
|
CSimpleIniA::TNamesDepend keys;
|
||||||
|
config->GetAllKeys(section, keys);
|
||||||
|
for (const auto& key : keys) {
|
||||||
|
if (std::string(config->GetValue(section, key.pItem)).empty()) {
|
||||||
|
config->Delete(section, key.pItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Config::GetConfigFilePath() const {
|
||||||
|
return config_loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadCategory(const Settings::Category category) {
|
||||||
|
const auto& settings = FindRelevantList(category);
|
||||||
|
std::ranges::for_each(settings, [&](const auto& setting) { ReadSettingGeneric(setting); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::WriteCategory(const Settings::Category category) {
|
||||||
|
const auto& settings = FindRelevantList(category);
|
||||||
|
std::ranges::for_each(settings, [&](const auto& setting) { WriteSettingGeneric(setting); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) {
|
||||||
|
if (!setting->Save() || (!setting->Switchable() && !global)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string key = AdjustKey(setting->GetLabel());
|
||||||
|
const std::string default_value(setting->DefaultToString());
|
||||||
|
|
||||||
|
bool use_global = true;
|
||||||
|
if (setting->Switchable() && !global) {
|
||||||
|
use_global =
|
||||||
|
ReadBooleanSetting(std::string(key).append("\\use_global"), std::make_optional(true));
|
||||||
|
setting->SetGlobal(use_global);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global || !use_global) {
|
||||||
|
const bool is_default =
|
||||||
|
ReadBooleanSetting(std::string(key).append("\\default"), std::make_optional(true));
|
||||||
|
if (!is_default) {
|
||||||
|
const std::string setting_string = ReadStringSetting(key, default_value);
|
||||||
|
setting->LoadString(setting_string);
|
||||||
|
} else {
|
||||||
|
// Empty string resets the Setting to default
|
||||||
|
setting->LoadString("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::WriteSettingGeneric(const Settings::BasicSetting* const setting) {
|
||||||
|
if (!setting->Save()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key = AdjustKey(setting->GetLabel());
|
||||||
|
if (setting->Switchable()) {
|
||||||
|
if (!global) {
|
||||||
|
WriteSetting(std::string(key).append("\\use_global"), setting->UsingGlobal());
|
||||||
|
}
|
||||||
|
if (global || !setting->UsingGlobal()) {
|
||||||
|
WriteSetting(std::string(key).append("\\default"),
|
||||||
|
setting->ToString() == setting->DefaultToString());
|
||||||
|
WriteSetting(key, setting->ToString());
|
||||||
|
}
|
||||||
|
} else if (global) {
|
||||||
|
WriteSetting(std::string(key).append("\\default"),
|
||||||
|
setting->ToString() == setting->DefaultToString());
|
||||||
|
WriteSetting(key, setting->ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::BeginGroup(const std::string& group) {
|
||||||
|
// You can't begin a group while reading/writing from a config array
|
||||||
|
ASSERT(array_stack.empty());
|
||||||
|
|
||||||
|
key_stack.push_back(AdjustKey(group));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::EndGroup() {
|
||||||
|
// You can't end a group if you haven't started one yet
|
||||||
|
ASSERT(!key_stack.empty());
|
||||||
|
|
||||||
|
// You can't end a group when reading/writing from a config array
|
||||||
|
ASSERT(array_stack.empty());
|
||||||
|
|
||||||
|
key_stack.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::GetSection() {
|
||||||
|
if (key_stack.empty()) {
|
||||||
|
return std::string{""};
|
||||||
|
}
|
||||||
|
|
||||||
|
return key_stack.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::GetGroup() const {
|
||||||
|
if (key_stack.size() <= 1) {
|
||||||
|
return std::string{""};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key;
|
||||||
|
for (size_t i = 1; i < key_stack.size(); ++i) {
|
||||||
|
key.append(key_stack[i]).append("\\");
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::AdjustKey(const std::string& key) {
|
||||||
|
std::string adjusted_key(key);
|
||||||
|
boost::replace_all(adjusted_key, "/", "\\");
|
||||||
|
boost::replace_all(adjusted_key, " ", "%20");
|
||||||
|
return adjusted_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::AdjustOutputString(const std::string& string) {
|
||||||
|
std::string adjusted_string(string);
|
||||||
|
boost::replace_all(adjusted_string, "\\", "/");
|
||||||
|
boost::replace_all(adjusted_string, "//", "/");
|
||||||
|
|
||||||
|
// Needed for backwards compatibility with QSettings deserialization
|
||||||
|
for (const auto& special_character : special_characters) {
|
||||||
|
if (adjusted_string.find(special_character) != std::string::npos) {
|
||||||
|
adjusted_string.insert(0, "\"");
|
||||||
|
adjusted_string.append("\"");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return adjusted_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::GetFullKey(const std::string& key, bool skipArrayIndex) {
|
||||||
|
if (array_stack.empty()) {
|
||||||
|
return std::string(GetGroup()).append(AdjustKey(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string array_key;
|
||||||
|
for (size_t i = 0; i < array_stack.size(); ++i) {
|
||||||
|
if (!array_stack[i].name.empty()) {
|
||||||
|
array_key.append(array_stack[i].name).append("\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skipArrayIndex || (array_stack.size() - 1 != i && array_stack.size() > 1)) {
|
||||||
|
array_key.append(ToString(array_stack[i].index)).append("\\");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string final_key = std::string(GetGroup()).append(array_key).append(AdjustKey(key));
|
||||||
|
return final_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Config::BeginArray(const std::string& array) {
|
||||||
|
array_stack.push_back(ConfigArray{AdjustKey(array), 0, 0});
|
||||||
|
const int size = config->GetLongValue(GetSection().c_str(),
|
||||||
|
GetFullKey(std::string("size"), true).c_str(), 0);
|
||||||
|
array_stack.back().size = size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::EndArray() {
|
||||||
|
// You can't end a config array before starting one
|
||||||
|
ASSERT(!array_stack.empty());
|
||||||
|
|
||||||
|
// Write out the size to config
|
||||||
|
if (key_stack.size() == 1 && array_stack.back().name.empty()) {
|
||||||
|
// Edge-case where the first array created doesn't have a name
|
||||||
|
config->SetValue(GetSection().c_str(), std::string("size").c_str(),
|
||||||
|
ToString(array_stack.back().size).c_str());
|
||||||
|
} else {
|
||||||
|
const auto key = GetFullKey(std::string("size"), true);
|
||||||
|
config->SetValue(GetSection().c_str(), key.c_str(),
|
||||||
|
ToString(array_stack.back().size).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
array_stack.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::SetArrayIndex(const int index) {
|
||||||
|
// You can't set the array index if you haven't started one yet
|
||||||
|
ASSERT(!array_stack.empty());
|
||||||
|
|
||||||
|
const int array_index = index + 1;
|
||||||
|
|
||||||
|
// You can't exceed the known max size of the array by more than 1
|
||||||
|
ASSERT(array_stack.front().size + 1 >= array_index);
|
||||||
|
|
||||||
|
// Change the config array size to the current index since you may want
|
||||||
|
// to reduce the number of elements that you read back from the config
|
||||||
|
// in the future.
|
||||||
|
array_stack.back().size = array_index;
|
||||||
|
array_stack.back().index = array_index;
|
||||||
|
}
|
@ -0,0 +1,206 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include "common/settings.h"
|
||||||
|
|
||||||
|
#include <SimpleIni.h>
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
|
// Workaround for conflicting definition in libloaderapi.h caused by SimpleIni
|
||||||
|
#undef LoadString
|
||||||
|
#undef CreateFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#undef CopyFile
|
||||||
|
#undef CreateDirectory
|
||||||
|
#undef MoveFile
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
public:
|
||||||
|
enum class ConfigType {
|
||||||
|
GlobalConfig,
|
||||||
|
PerGameConfig,
|
||||||
|
InputProfile,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~Config() = default;
|
||||||
|
|
||||||
|
void ClearControlPlayerValues() const;
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& GetConfigFilePath() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool Exists(const std::string& section, const std::string& key) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit Config(ConfigType config_type = ConfigType::GlobalConfig);
|
||||||
|
|
||||||
|
void Initialize(const std::string& config_name = "config");
|
||||||
|
void Initialize(std::optional<std::string> config_path);
|
||||||
|
|
||||||
|
void WriteToIni() const;
|
||||||
|
|
||||||
|
void SetUpIni();
|
||||||
|
[[nodiscard]] bool IsCustomConfig() const;
|
||||||
|
|
||||||
|
void Reload();
|
||||||
|
void Save();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derived config classes must implement this so they can reload all platform-specific
|
||||||
|
* values and global ones.
|
||||||
|
*/
|
||||||
|
virtual void ReloadAllValues() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derived config classes must implement this so they can save all platform-specific
|
||||||
|
* and global values.
|
||||||
|
*/
|
||||||
|
virtual void SaveAllValues() = 0;
|
||||||
|
|
||||||
|
void ReadValues();
|
||||||
|
void ReadPlayerValues(std::size_t player_index);
|
||||||
|
|
||||||
|
void ReadTouchscreenValues();
|
||||||
|
void ReadMotionTouchValues();
|
||||||
|
|
||||||
|
// Read functions bases off the respective config section names.
|
||||||
|
void ReadAudioValues();
|
||||||
|
void ReadControlValues();
|
||||||
|
void ReadCoreValues();
|
||||||
|
void ReadDataStorageValues();
|
||||||
|
void ReadDebuggingValues();
|
||||||
|
void ReadServiceValues();
|
||||||
|
void ReadDisabledAddOnValues();
|
||||||
|
void ReadMiscellaneousValues();
|
||||||
|
void ReadCpuValues();
|
||||||
|
void ReadRendererValues();
|
||||||
|
void ReadScreenshotValues();
|
||||||
|
void ReadSystemValues();
|
||||||
|
void ReadWebServiceValues();
|
||||||
|
void ReadNetworkValues();
|
||||||
|
|
||||||
|
// Read platform specific sections
|
||||||
|
virtual void ReadHidbusValues() = 0;
|
||||||
|
virtual void ReadDebugControlValues() = 0;
|
||||||
|
virtual void ReadPathValues() = 0;
|
||||||
|
virtual void ReadShortcutValues() = 0;
|
||||||
|
virtual void ReadUIValues() = 0;
|
||||||
|
virtual void ReadUIGamelistValues() = 0;
|
||||||
|
virtual void ReadUILayoutValues() = 0;
|
||||||
|
virtual void ReadMultiplayerValues() = 0;
|
||||||
|
|
||||||
|
void SaveValues();
|
||||||
|
void SavePlayerValues(std::size_t player_index);
|
||||||
|
void SaveTouchscreenValues();
|
||||||
|
void SaveMotionTouchValues();
|
||||||
|
|
||||||
|
// Save functions based off the respective config section names.
|
||||||
|
void SaveAudioValues();
|
||||||
|
void SaveControlValues();
|
||||||
|
void SaveCoreValues();
|
||||||
|
void SaveDataStorageValues();
|
||||||
|
void SaveDebuggingValues();
|
||||||
|
void SaveNetworkValues();
|
||||||
|
void SaveDisabledAddOnValues();
|
||||||
|
void SaveMiscellaneousValues();
|
||||||
|
void SaveCpuValues();
|
||||||
|
void SaveRendererValues();
|
||||||
|
void SaveScreenshotValues();
|
||||||
|
void SaveSystemValues();
|
||||||
|
void SaveWebServiceValues();
|
||||||
|
|
||||||
|
// Save platform specific sections
|
||||||
|
virtual void SaveHidbusValues() = 0;
|
||||||
|
virtual void SaveDebugControlValues() = 0;
|
||||||
|
virtual void SavePathValues() = 0;
|
||||||
|
virtual void SaveShortcutValues() = 0;
|
||||||
|
virtual void SaveUIValues() = 0;
|
||||||
|
virtual void SaveUIGamelistValues() = 0;
|
||||||
|
virtual void SaveUILayoutValues() = 0;
|
||||||
|
virtual void SaveMultiplayerValues() = 0;
|
||||||
|
|
||||||
|
virtual std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a setting from the qt_config.
|
||||||
|
*
|
||||||
|
* @param key The setting's identifier
|
||||||
|
* @param default_value The value to use when the setting is not already present in the config
|
||||||
|
*/
|
||||||
|
bool ReadBooleanSetting(const std::string& key,
|
||||||
|
std::optional<bool> default_value = std::nullopt);
|
||||||
|
s64 ReadIntegerSetting(const std::string& key, std::optional<s64> default_value = std::nullopt);
|
||||||
|
double ReadDoubleSetting(const std::string& key,
|
||||||
|
std::optional<double> default_value = std::nullopt);
|
||||||
|
std::string ReadStringSetting(const std::string& key,
|
||||||
|
std::optional<std::string> default_value = std::nullopt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a setting to the qt_config.
|
||||||
|
*
|
||||||
|
* @param key The setting's idetentifier
|
||||||
|
* @param value Value of the setting
|
||||||
|
* @param default_value Default of the setting if not present in config
|
||||||
|
* @param use_global Specifies if the custom or global config should be in use, for custom
|
||||||
|
* configs
|
||||||
|
*/
|
||||||
|
template <typename Type = int>
|
||||||
|
void WriteSetting(const std::string& key, const Type& value,
|
||||||
|
const std::optional<Type>& default_value = std::nullopt,
|
||||||
|
const std::optional<bool>& use_global = std::nullopt);
|
||||||
|
void WriteSettingInternal(const std::string& key, const std::string& value);
|
||||||
|
|
||||||
|
void ReadCategory(Settings::Category category);
|
||||||
|
void WriteCategory(Settings::Category category);
|
||||||
|
void ReadSettingGeneric(Settings::BasicSetting* setting);
|
||||||
|
void WriteSettingGeneric(const Settings::BasicSetting* setting);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
[[nodiscard]] std::string ToString(const T& value_) {
|
||||||
|
if constexpr (std::is_same_v<T, std::string>) {
|
||||||
|
return value_;
|
||||||
|
} else if constexpr (std::is_same_v<T, std::optional<u32>>) {
|
||||||
|
return value_.has_value() ? std::to_string(*value_) : "none";
|
||||||
|
} else if constexpr (std::is_same_v<T, bool>) {
|
||||||
|
return value_ ? "true" : "false";
|
||||||
|
} else {
|
||||||
|
return std::to_string(static_cast<s64>(value_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginGroup(const std::string& group);
|
||||||
|
void EndGroup();
|
||||||
|
std::string GetSection();
|
||||||
|
[[nodiscard]] std::string GetGroup() const;
|
||||||
|
static std::string AdjustKey(const std::string& key);
|
||||||
|
static std::string AdjustOutputString(const std::string& string);
|
||||||
|
std::string GetFullKey(const std::string& key, bool skipArrayIndex);
|
||||||
|
int BeginArray(const std::string& array);
|
||||||
|
void EndArray();
|
||||||
|
void SetArrayIndex(int index);
|
||||||
|
|
||||||
|
const ConfigType type;
|
||||||
|
std::unique_ptr<CSimpleIniA> config;
|
||||||
|
std::string config_loc;
|
||||||
|
const bool global;
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline static std::array<char, 19> special_characters = {'!', '#', '$', '%', '^', '&', '*',
|
||||||
|
'|', ';', '\'', '\"', ',', '<', '.',
|
||||||
|
'>', '?', '`', '~', '='};
|
||||||
|
|
||||||
|
struct ConfigArray {
|
||||||
|
std::string name;
|
||||||
|
int size;
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
std::vector<ConfigArray> array_stack;
|
||||||
|
std::vector<std::string> key_stack;
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
@ -1,179 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <QMetaType>
|
|
||||||
#include <QVariant>
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "common/settings_enums.h"
|
|
||||||
#include "yuzu/uisettings.h"
|
|
||||||
|
|
||||||
class QSettings;
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
class System;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Config {
|
|
||||||
public:
|
|
||||||
enum class ConfigType {
|
|
||||||
GlobalConfig,
|
|
||||||
PerGameConfig,
|
|
||||||
InputProfile,
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit Config(const std::string& config_name = "qt-config",
|
|
||||||
ConfigType config_type = ConfigType::GlobalConfig);
|
|
||||||
~Config();
|
|
||||||
|
|
||||||
void Reload();
|
|
||||||
void Save();
|
|
||||||
|
|
||||||
void ReadControlPlayerValue(std::size_t player_index);
|
|
||||||
void SaveControlPlayerValue(std::size_t player_index);
|
|
||||||
void ClearControlPlayerValues();
|
|
||||||
|
|
||||||
const std::string& GetConfigFilePath() const;
|
|
||||||
|
|
||||||
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
|
||||||
static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
|
|
||||||
static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
|
||||||
static const std::array<int, 2> default_stick_mod;
|
|
||||||
static const std::array<int, 2> default_ringcon_analogs;
|
|
||||||
static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>
|
|
||||||
default_mouse_buttons;
|
|
||||||
static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
|
|
||||||
static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
|
|
||||||
static const std::array<UISettings::Shortcut, 23> default_hotkeys;
|
|
||||||
|
|
||||||
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map;
|
|
||||||
static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map;
|
|
||||||
static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map;
|
|
||||||
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map;
|
|
||||||
static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map;
|
|
||||||
static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map;
|
|
||||||
|
|
||||||
static constexpr UISettings::Theme default_theme{
|
|
||||||
#ifdef _WIN32
|
|
||||||
UISettings::Theme::DarkColorful
|
|
||||||
#else
|
|
||||||
UISettings::Theme::DefaultColorful
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Initialize(const std::string& config_name);
|
|
||||||
bool IsCustomConfig();
|
|
||||||
|
|
||||||
void ReadValues();
|
|
||||||
void ReadPlayerValue(std::size_t player_index);
|
|
||||||
void ReadDebugValues();
|
|
||||||
void ReadKeyboardValues();
|
|
||||||
void ReadMouseValues();
|
|
||||||
void ReadTouchscreenValues();
|
|
||||||
void ReadMotionTouchValues();
|
|
||||||
void ReadHidbusValues();
|
|
||||||
void ReadIrCameraValues();
|
|
||||||
|
|
||||||
// Read functions bases off the respective config section names.
|
|
||||||
void ReadAudioValues();
|
|
||||||
void ReadControlValues();
|
|
||||||
void ReadCoreValues();
|
|
||||||
void ReadDataStorageValues();
|
|
||||||
void ReadDebuggingValues();
|
|
||||||
void ReadServiceValues();
|
|
||||||
void ReadDisabledAddOnValues();
|
|
||||||
void ReadMiscellaneousValues();
|
|
||||||
void ReadPathValues();
|
|
||||||
void ReadCpuValues();
|
|
||||||
void ReadRendererValues();
|
|
||||||
void ReadScreenshotValues();
|
|
||||||
void ReadShortcutValues();
|
|
||||||
void ReadSystemValues();
|
|
||||||
void ReadUIValues();
|
|
||||||
void ReadUIGamelistValues();
|
|
||||||
void ReadUILayoutValues();
|
|
||||||
void ReadWebServiceValues();
|
|
||||||
void ReadMultiplayerValues();
|
|
||||||
void ReadNetworkValues();
|
|
||||||
|
|
||||||
void SaveValues();
|
|
||||||
void SavePlayerValue(std::size_t player_index);
|
|
||||||
void SaveDebugValues();
|
|
||||||
void SaveMouseValues();
|
|
||||||
void SaveTouchscreenValues();
|
|
||||||
void SaveMotionTouchValues();
|
|
||||||
void SaveHidbusValues();
|
|
||||||
void SaveIrCameraValues();
|
|
||||||
|
|
||||||
// Save functions based off the respective config section names.
|
|
||||||
void SaveAudioValues();
|
|
||||||
void SaveControlValues();
|
|
||||||
void SaveCoreValues();
|
|
||||||
void SaveDataStorageValues();
|
|
||||||
void SaveDebuggingValues();
|
|
||||||
void SaveNetworkValues();
|
|
||||||
void SaveDisabledAddOnValues();
|
|
||||||
void SaveMiscellaneousValues();
|
|
||||||
void SavePathValues();
|
|
||||||
void SaveCpuValues();
|
|
||||||
void SaveRendererValues();
|
|
||||||
void SaveScreenshotValues();
|
|
||||||
void SaveShortcutValues();
|
|
||||||
void SaveSystemValues();
|
|
||||||
void SaveUIValues();
|
|
||||||
void SaveUIGamelistValues();
|
|
||||||
void SaveUILayoutValues();
|
|
||||||
void SaveWebServiceValues();
|
|
||||||
void SaveMultiplayerValues();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a setting from the qt_config.
|
|
||||||
*
|
|
||||||
* @param name The setting's identifier
|
|
||||||
* @param default_value The value to use when the setting is not already present in the config
|
|
||||||
*/
|
|
||||||
QVariant ReadSetting(const QString& name) const;
|
|
||||||
QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a setting to the qt_config.
|
|
||||||
*
|
|
||||||
* @param name The setting's idetentifier
|
|
||||||
* @param value Value of the setting
|
|
||||||
* @param default_value Default of the setting if not present in qt_config
|
|
||||||
* @param use_global Specifies if the custom or global config should be in use, for custom
|
|
||||||
* configs
|
|
||||||
*/
|
|
||||||
void WriteSetting(const QString& name, const QVariant& value);
|
|
||||||
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
|
|
||||||
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
|
|
||||||
bool use_global);
|
|
||||||
|
|
||||||
void ReadCategory(Settings::Category category);
|
|
||||||
void WriteCategory(Settings::Category category);
|
|
||||||
void ReadSettingGeneric(Settings::BasicSetting* const setting);
|
|
||||||
void WriteSettingGeneric(Settings::BasicSetting* const setting) const;
|
|
||||||
|
|
||||||
const ConfigType type;
|
|
||||||
std::unique_ptr<QSettings> qt_config;
|
|
||||||
std::string qt_config_loc;
|
|
||||||
const bool global;
|
|
||||||
};
|
|
||||||
|
|
||||||
// These metatype declarations cannot be in common/settings.h because core is devoid of QT
|
|
||||||
Q_DECLARE_METATYPE(Settings::CpuAccuracy);
|
|
||||||
Q_DECLARE_METATYPE(Settings::GpuAccuracy);
|
|
||||||
Q_DECLARE_METATYPE(Settings::FullscreenMode);
|
|
||||||
Q_DECLARE_METATYPE(Settings::NvdecEmulation);
|
|
||||||
Q_DECLARE_METATYPE(Settings::ResolutionSetup);
|
|
||||||
Q_DECLARE_METATYPE(Settings::ScalingFilter);
|
|
||||||
Q_DECLARE_METATYPE(Settings::AntiAliasing);
|
|
||||||
Q_DECLARE_METATYPE(Settings::RendererBackend);
|
|
||||||
Q_DECLARE_METATYPE(Settings::ShaderBackend);
|
|
||||||
Q_DECLARE_METATYPE(Settings::AstcRecompression);
|
|
||||||
Q_DECLARE_METATYPE(Settings::AstcDecodeMode);
|
|
@ -0,0 +1,548 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "input_common/main.h"
|
||||||
|
#include "qt_config.h"
|
||||||
|
#include "uisettings.h"
|
||||||
|
|
||||||
|
const std::array<int, Settings::NativeButton::NumButtons> QtConfig::default_buttons = {
|
||||||
|
Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F,
|
||||||
|
Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T,
|
||||||
|
Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right,
|
||||||
|
Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0,
|
||||||
|
Qt::Key_Q, Qt::Key_E,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<int, Settings::NativeMotion::NumMotions> QtConfig::default_motions = {
|
||||||
|
Qt::Key_7,
|
||||||
|
Qt::Key_8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{
|
||||||
|
{
|
||||||
|
Qt::Key_W,
|
||||||
|
Qt::Key_S,
|
||||||
|
Qt::Key_A,
|
||||||
|
Qt::Key_D,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Qt::Key_I,
|
||||||
|
Qt::Key_K,
|
||||||
|
Qt::Key_J,
|
||||||
|
Qt::Key_L,
|
||||||
|
},
|
||||||
|
}};
|
||||||
|
|
||||||
|
const std::array<int, 2> QtConfig::default_stick_mod = {
|
||||||
|
Qt::Key_Shift,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<int, 2> QtConfig::default_ringcon_analogs{{
|
||||||
|
Qt::Key_A,
|
||||||
|
Qt::Key_D,
|
||||||
|
}};
|
||||||
|
|
||||||
|
QtConfig::QtConfig(const std::string& config_name, const ConfigType config_type)
|
||||||
|
: Config(config_type) {
|
||||||
|
Initialize(config_name);
|
||||||
|
if (config_type != ConfigType::InputProfile) {
|
||||||
|
ReadQtValues();
|
||||||
|
SaveQtValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtConfig::~QtConfig() {
|
||||||
|
if (global) {
|
||||||
|
QtConfig::SaveAllValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReloadAllValues() {
|
||||||
|
Reload();
|
||||||
|
ReadQtValues();
|
||||||
|
SaveQtValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveAllValues() {
|
||||||
|
Save();
|
||||||
|
SaveQtValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadQtValues() {
|
||||||
|
if (global) {
|
||||||
|
ReadUIValues();
|
||||||
|
}
|
||||||
|
ReadQtControlValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadQtPlayerValues(const std::size_t player_index) {
|
||||||
|
std::string player_prefix;
|
||||||
|
if (type != ConfigType::InputProfile) {
|
||||||
|
player_prefix.append("player_").append(ToString(player_index)).append("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
const auto profile_name =
|
||||||
|
ReadStringSetting(std::string(player_prefix).append("profile_name"));
|
||||||
|
if (profile_name.empty()) {
|
||||||
|
// Use the global input config
|
||||||
|
player = Settings::values.players.GetValue(true)[player_index];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
|
auto& player_buttons = player.buttons[i];
|
||||||
|
|
||||||
|
player_buttons = ReadStringSetting(
|
||||||
|
std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param);
|
||||||
|
if (player_buttons.empty()) {
|
||||||
|
player_buttons = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
|
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||||
|
auto& player_analogs = player.analogs[i];
|
||||||
|
|
||||||
|
player_analogs = ReadStringSetting(
|
||||||
|
std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param);
|
||||||
|
if (player_analogs.empty()) {
|
||||||
|
player_analogs = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||||
|
auto& player_motions = player.motions[i];
|
||||||
|
|
||||||
|
player_motions = ReadStringSetting(
|
||||||
|
std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param);
|
||||||
|
if (player_motions.empty()) {
|
||||||
|
player_motions = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadHidbusValues() {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
|
||||||
|
auto& ringcon_analogs = Settings::values.ringcon_analogs;
|
||||||
|
|
||||||
|
ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param);
|
||||||
|
if (ringcon_analogs.empty()) {
|
||||||
|
ringcon_analogs = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadDebugControlValues() {
|
||||||
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
|
auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i];
|
||||||
|
|
||||||
|
debug_pad_buttons = ReadStringSetting(
|
||||||
|
std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param);
|
||||||
|
if (debug_pad_buttons.empty()) {
|
||||||
|
debug_pad_buttons = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
|
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||||
|
auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
|
||||||
|
|
||||||
|
debug_pad_analogs = ReadStringSetting(
|
||||||
|
std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param);
|
||||||
|
if (debug_pad_analogs.empty()) {
|
||||||
|
debug_pad_analogs = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadQtControlValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||||
|
|
||||||
|
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||||
|
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||||
|
ReadQtPlayerValues(p);
|
||||||
|
}
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
EndGroup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ReadDebugControlValues();
|
||||||
|
ReadHidbusValues();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadPathValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
|
||||||
|
|
||||||
|
UISettings::values.roms_path = ReadStringSetting(std::string("romsPath"));
|
||||||
|
UISettings::values.symbols_path = ReadStringSetting(std::string("symbolsPath"));
|
||||||
|
UISettings::values.game_dir_deprecated =
|
||||||
|
ReadStringSetting(std::string("gameListRootDir"), std::string("."));
|
||||||
|
UISettings::values.game_dir_deprecated_deepscan =
|
||||||
|
ReadBooleanSetting(std::string("gameListDeepScan"), std::make_optional(false));
|
||||||
|
|
||||||
|
const int gamedirs_size = BeginArray(std::string("gamedirs"));
|
||||||
|
for (int i = 0; i < gamedirs_size; ++i) {
|
||||||
|
SetArrayIndex(i);
|
||||||
|
UISettings::GameDir game_dir;
|
||||||
|
game_dir.path = ReadStringSetting(std::string("path"));
|
||||||
|
game_dir.deep_scan =
|
||||||
|
ReadBooleanSetting(std::string("deep_scan"), std::make_optional(false));
|
||||||
|
game_dir.expanded = ReadBooleanSetting(std::string("expanded"), std::make_optional(true));
|
||||||
|
UISettings::values.game_dirs.append(game_dir);
|
||||||
|
}
|
||||||
|
EndArray();
|
||||||
|
|
||||||
|
// Create NAND and SD card directories if empty, these are not removable through the UI,
|
||||||
|
// also carries over old game list settings if present
|
||||||
|
if (UISettings::values.game_dirs.empty()) {
|
||||||
|
UISettings::GameDir game_dir;
|
||||||
|
game_dir.path = std::string("SDMC");
|
||||||
|
game_dir.expanded = true;
|
||||||
|
UISettings::values.game_dirs.append(game_dir);
|
||||||
|
game_dir.path = std::string("UserNAND");
|
||||||
|
UISettings::values.game_dirs.append(game_dir);
|
||||||
|
game_dir.path = std::string("SysNAND");
|
||||||
|
UISettings::values.game_dirs.append(game_dir);
|
||||||
|
if (UISettings::values.game_dir_deprecated != std::string(".")) {
|
||||||
|
game_dir.path = UISettings::values.game_dir_deprecated;
|
||||||
|
game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan;
|
||||||
|
UISettings::values.game_dirs.append(game_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UISettings::values.recent_files =
|
||||||
|
QString::fromStdString(ReadStringSetting(std::string("recentFiles")))
|
||||||
|
.split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive);
|
||||||
|
UISettings::values.language = ReadStringSetting(std::string("language"), std::string(""));
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadShortcutValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts));
|
||||||
|
|
||||||
|
for (const auto& [name, group, shortcut] : UISettings::default_hotkeys) {
|
||||||
|
BeginGroup(group);
|
||||||
|
BeginGroup(name);
|
||||||
|
|
||||||
|
// No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1
|
||||||
|
// for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open
|
||||||
|
// a file dialog in windowed mode
|
||||||
|
UISettings::values.shortcuts.push_back(
|
||||||
|
{name,
|
||||||
|
group,
|
||||||
|
{ReadStringSetting(std::string("KeySeq"), shortcut.keyseq),
|
||||||
|
ReadStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq),
|
||||||
|
shortcut.context,
|
||||||
|
ReadBooleanSetting(std::string("Repeat"), std::optional(shortcut.repeat))}});
|
||||||
|
|
||||||
|
EndGroup(); // name
|
||||||
|
EndGroup(); // group
|
||||||
|
}
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadUIValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Ui));
|
||||||
|
|
||||||
|
UISettings::values.theme = ReadStringSetting(
|
||||||
|
std::string("theme"),
|
||||||
|
std::string(UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second));
|
||||||
|
|
||||||
|
ReadUIGamelistValues();
|
||||||
|
ReadUILayoutValues();
|
||||||
|
ReadPathValues();
|
||||||
|
ReadScreenshotValues();
|
||||||
|
ReadShortcutValues();
|
||||||
|
ReadMultiplayerValues();
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Ui);
|
||||||
|
ReadCategory(Settings::Category::UiGeneral);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadUIGamelistValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::UiGameList);
|
||||||
|
|
||||||
|
const int favorites_size = BeginArray("favorites");
|
||||||
|
for (int i = 0; i < favorites_size; i++) {
|
||||||
|
SetArrayIndex(i);
|
||||||
|
UISettings::values.favorited_ids.append(ReadIntegerSetting(std::string("program_id")));
|
||||||
|
}
|
||||||
|
EndArray();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadUILayoutValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::UiLayout);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadMultiplayerValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Multiplayer));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Multiplayer);
|
||||||
|
|
||||||
|
// Read ban list back
|
||||||
|
int size = BeginArray(std::string("username_ban_list"));
|
||||||
|
UISettings::values.multiplayer_ban_list.first.resize(size);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
SetArrayIndex(i);
|
||||||
|
UISettings::values.multiplayer_ban_list.first[i] =
|
||||||
|
ReadStringSetting(std::string("username"), std::string(""));
|
||||||
|
}
|
||||||
|
EndArray();
|
||||||
|
|
||||||
|
size = BeginArray(std::string("ip_ban_list"));
|
||||||
|
UISettings::values.multiplayer_ban_list.second.resize(size);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
UISettings::values.multiplayer_ban_list.second[i] =
|
||||||
|
ReadStringSetting("username", std::string(""));
|
||||||
|
}
|
||||||
|
EndArray();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveQtValues() {
|
||||||
|
if (global) {
|
||||||
|
SaveUIValues();
|
||||||
|
}
|
||||||
|
SaveQtControlValues();
|
||||||
|
|
||||||
|
WriteToIni();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveQtPlayerValues(const std::size_t player_index) {
|
||||||
|
std::string player_prefix;
|
||||||
|
if (type != ConfigType::InputProfile) {
|
||||||
|
player_prefix = std::string("player_").append(ToString(player_index)).append("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
|
if (IsCustomConfig() && player.profile_name.empty()) {
|
||||||
|
// No custom profile selected
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
|
WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]),
|
||||||
|
player.buttons[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
|
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||||
|
WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]),
|
||||||
|
player.analogs[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||||
|
WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]),
|
||||||
|
player.motions[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveDebugControlValues() {
|
||||||
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
|
WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]),
|
||||||
|
Settings::values.debug_pad_buttons[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
|
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||||
|
WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]),
|
||||||
|
Settings::values.debug_pad_analogs[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveHidbusValues() {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
|
||||||
|
WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs,
|
||||||
|
std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveQtControlValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||||
|
|
||||||
|
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||||
|
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||||
|
SaveQtPlayerValues(p);
|
||||||
|
}
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
EndGroup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SaveDebugControlValues();
|
||||||
|
SaveHidbusValues();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SavePathValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
|
||||||
|
|
||||||
|
WriteSetting(std::string("romsPath"), UISettings::values.roms_path);
|
||||||
|
WriteSetting(std::string("symbolsPath"), UISettings::values.symbols_path);
|
||||||
|
BeginArray(std::string("gamedirs"));
|
||||||
|
for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) {
|
||||||
|
SetArrayIndex(i);
|
||||||
|
const auto& game_dir = UISettings::values.game_dirs[i];
|
||||||
|
WriteSetting(std::string("path"), game_dir.path);
|
||||||
|
WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false));
|
||||||
|
WriteSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true));
|
||||||
|
}
|
||||||
|
EndArray();
|
||||||
|
|
||||||
|
WriteSetting(std::string("recentFiles"),
|
||||||
|
UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString());
|
||||||
|
WriteSetting(std::string("language"), UISettings::values.language);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveShortcutValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts));
|
||||||
|
|
||||||
|
// Lengths of UISettings::values.shortcuts & default_hotkeys are same.
|
||||||
|
// However, their ordering must also be the same.
|
||||||
|
for (std::size_t i = 0; i < UISettings::default_hotkeys.size(); i++) {
|
||||||
|
const auto& [name, group, shortcut] = UISettings::values.shortcuts[i];
|
||||||
|
const auto& default_hotkey = UISettings::default_hotkeys[i].shortcut;
|
||||||
|
|
||||||
|
BeginGroup(group);
|
||||||
|
BeginGroup(name);
|
||||||
|
|
||||||
|
WriteSetting(std::string("KeySeq"), shortcut.keyseq,
|
||||||
|
std::make_optional(default_hotkey.keyseq));
|
||||||
|
WriteSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq,
|
||||||
|
std::make_optional(default_hotkey.controller_keyseq));
|
||||||
|
WriteSetting(std::string("Context"), shortcut.context,
|
||||||
|
std::make_optional(default_hotkey.context));
|
||||||
|
WriteSetting(std::string("Repeat"), shortcut.repeat,
|
||||||
|
std::make_optional(default_hotkey.repeat));
|
||||||
|
|
||||||
|
EndGroup(); // name
|
||||||
|
EndGroup(); // group
|
||||||
|
}
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveUIValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Ui));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Ui);
|
||||||
|
WriteCategory(Settings::Category::UiGeneral);
|
||||||
|
|
||||||
|
WriteSetting(std::string("theme"), UISettings::values.theme,
|
||||||
|
std::make_optional(std::string(
|
||||||
|
UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second)));
|
||||||
|
|
||||||
|
SaveUIGamelistValues();
|
||||||
|
SaveUILayoutValues();
|
||||||
|
SavePathValues();
|
||||||
|
SaveScreenshotValues();
|
||||||
|
SaveShortcutValues();
|
||||||
|
SaveMultiplayerValues();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveUIGamelistValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::UiGameList);
|
||||||
|
|
||||||
|
BeginArray(std::string("favorites"));
|
||||||
|
for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
|
||||||
|
SetArrayIndex(i);
|
||||||
|
WriteSetting(std::string("program_id"), UISettings::values.favorited_ids[i]);
|
||||||
|
}
|
||||||
|
EndArray(); // favorites
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveUILayoutValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::UiLayout));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::UiLayout);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveMultiplayerValues() {
|
||||||
|
BeginGroup(std::string("Multiplayer"));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Multiplayer);
|
||||||
|
|
||||||
|
// Write ban list
|
||||||
|
BeginArray(std::string("username_ban_list"));
|
||||||
|
for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) {
|
||||||
|
SetArrayIndex(static_cast<int>(i));
|
||||||
|
WriteSetting(std::string("username"), UISettings::values.multiplayer_ban_list.first[i]);
|
||||||
|
}
|
||||||
|
EndArray(); // username_ban_list
|
||||||
|
|
||||||
|
BeginArray(std::string("ip_ban_list"));
|
||||||
|
for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) {
|
||||||
|
SetArrayIndex(static_cast<int>(i));
|
||||||
|
WriteSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]);
|
||||||
|
}
|
||||||
|
EndArray(); // ip_ban_list
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Settings::BasicSetting*>& QtConfig::FindRelevantList(Settings::Category category) {
|
||||||
|
auto& map = Settings::values.linkage.by_category;
|
||||||
|
if (map.contains(category)) {
|
||||||
|
return Settings::values.linkage.by_category[category];
|
||||||
|
}
|
||||||
|
return UISettings::values.linkage.by_category[category];
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::ReadQtControlPlayerValues(std::size_t player_index) {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||||
|
|
||||||
|
ReadPlayerValues(player_index);
|
||||||
|
ReadQtPlayerValues(player_index);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||||
|
|
||||||
|
SavePlayerValues(player_index);
|
||||||
|
SaveQtPlayerValues(player_index);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
|
||||||
|
WriteToIni();
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
|
#include "frontend_common/config.h"
|
||||||
|
|
||||||
|
class QtConfig final : public Config {
|
||||||
|
public:
|
||||||
|
explicit QtConfig(const std::string& config_name = "qt-config",
|
||||||
|
ConfigType config_type = ConfigType::GlobalConfig);
|
||||||
|
~QtConfig() override;
|
||||||
|
|
||||||
|
void ReloadAllValues() override;
|
||||||
|
void SaveAllValues() override;
|
||||||
|
|
||||||
|
void ReadQtControlPlayerValues(std::size_t player_index);
|
||||||
|
void SaveQtControlPlayerValues(std::size_t player_index);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ReadQtValues();
|
||||||
|
void ReadQtPlayerValues(std::size_t player_index);
|
||||||
|
void ReadQtControlValues();
|
||||||
|
void ReadHidbusValues() override;
|
||||||
|
void ReadDebugControlValues() override;
|
||||||
|
void ReadPathValues() override;
|
||||||
|
void ReadShortcutValues() override;
|
||||||
|
void ReadUIValues() override;
|
||||||
|
void ReadUIGamelistValues() override;
|
||||||
|
void ReadUILayoutValues() override;
|
||||||
|
void ReadMultiplayerValues() override;
|
||||||
|
|
||||||
|
void SaveQtValues();
|
||||||
|
void SaveQtPlayerValues(std::size_t player_index);
|
||||||
|
void SaveQtControlValues();
|
||||||
|
void SaveHidbusValues() override;
|
||||||
|
void SaveDebugControlValues() override;
|
||||||
|
void SavePathValues() override;
|
||||||
|
void SaveShortcutValues() override;
|
||||||
|
void SaveUIValues() override;
|
||||||
|
void SaveUIGamelistValues() override;
|
||||||
|
void SaveUILayoutValues() override;
|
||||||
|
void SaveMultiplayerValues() override;
|
||||||
|
|
||||||
|
std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
||||||
|
static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
|
||||||
|
static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
||||||
|
static const std::array<int, 2> default_stick_mod;
|
||||||
|
static const std::array<int, 2> default_ringcon_analogs;
|
||||||
|
};
|
@ -1,279 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
#include <sstream>
|
|
||||||
#include <INIReader.h>
|
|
||||||
#include <SDL.h>
|
|
||||||
#include "common/fs/file.h"
|
|
||||||
#include "common/fs/fs.h"
|
|
||||||
#include "common/fs/path_util.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "core/hle/service/acc/profile_manager.h"
|
|
||||||
#include "input_common/main.h"
|
|
||||||
#include "yuzu_cmd/config.h"
|
|
||||||
#include "yuzu_cmd/default_ini.h"
|
|
||||||
|
|
||||||
namespace FS = Common::FS;
|
|
||||||
|
|
||||||
const std::filesystem::path default_config_path =
|
|
||||||
FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini";
|
|
||||||
|
|
||||||
Config::Config(std::optional<std::filesystem::path> config_path)
|
|
||||||
: sdl2_config_loc{config_path.value_or(default_config_path)},
|
|
||||||
sdl2_config{std::make_unique<INIReader>(FS::PathToUTF8String(sdl2_config_loc))} {
|
|
||||||
Reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
Config::~Config() = default;
|
|
||||||
|
|
||||||
bool Config::LoadINI(const std::string& default_contents, bool retry) {
|
|
||||||
const auto config_loc_str = FS::PathToUTF8String(sdl2_config_loc);
|
|
||||||
if (sdl2_config->ParseError() < 0) {
|
|
||||||
if (retry) {
|
|
||||||
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...",
|
|
||||||
config_loc_str);
|
|
||||||
|
|
||||||
void(FS::CreateParentDir(sdl2_config_loc));
|
|
||||||
void(FS::WriteStringToFile(sdl2_config_loc, FS::FileType::TextFile, default_contents));
|
|
||||||
|
|
||||||
sdl2_config = std::make_unique<INIReader>(config_loc_str);
|
|
||||||
|
|
||||||
return LoadINI(default_contents, false);
|
|
||||||
}
|
|
||||||
LOG_ERROR(Config, "Failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LOG_INFO(Config, "Successfully loaded {}", config_loc_str);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons = {
|
|
||||||
SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T,
|
|
||||||
SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W,
|
|
||||||
SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::array<int, Settings::NativeMotion::NumMotions> default_motions = {
|
|
||||||
SDL_SCANCODE_7,
|
|
||||||
SDL_SCANCODE_8,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs{{
|
|
||||||
{
|
|
||||||
SDL_SCANCODE_UP,
|
|
||||||
SDL_SCANCODE_DOWN,
|
|
||||||
SDL_SCANCODE_LEFT,
|
|
||||||
SDL_SCANCODE_RIGHT,
|
|
||||||
SDL_SCANCODE_D,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
SDL_SCANCODE_I,
|
|
||||||
SDL_SCANCODE_K,
|
|
||||||
SDL_SCANCODE_J,
|
|
||||||
SDL_SCANCODE_L,
|
|
||||||
SDL_SCANCODE_D,
|
|
||||||
},
|
|
||||||
}};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
|
|
||||||
std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
|
|
||||||
if (setting_value.empty()) {
|
|
||||||
setting_value = setting.GetDefault();
|
|
||||||
}
|
|
||||||
setting = std::move(setting_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
|
|
||||||
setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Type, bool ranged>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
|
|
||||||
setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
|
|
||||||
static_cast<long>(setting.GetDefault())));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::ReadCategory(Settings::Category category) {
|
|
||||||
for (const auto setting : Settings::values.linkage.by_category[category]) {
|
|
||||||
const char* category_name = [&]() {
|
|
||||||
if (category == Settings::Category::Controls) {
|
|
||||||
// For compatibility with older configs
|
|
||||||
return "ControlsGeneral";
|
|
||||||
} else {
|
|
||||||
return Settings::TranslateCategory(category);
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
std::string setting_value =
|
|
||||||
sdl2_config->Get(category_name, setting->GetLabel(), setting->DefaultToString());
|
|
||||||
setting->LoadString(setting_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::ReadValues() {
|
|
||||||
// Controls
|
|
||||||
ReadCategory(Settings::Category::Controls);
|
|
||||||
|
|
||||||
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
|
||||||
auto& player = Settings::values.players.GetValue()[p];
|
|
||||||
|
|
||||||
const auto group = fmt::format("ControlsP{}", p);
|
|
||||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
|
||||||
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
|
||||||
player.buttons[i] =
|
|
||||||
sdl2_config->Get(group, Settings::NativeButton::mapping[i], default_param);
|
|
||||||
if (player.buttons[i].empty()) {
|
|
||||||
player.buttons[i] = default_param;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
|
||||||
std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
|
||||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
|
||||||
default_analogs[i][3], default_analogs[i][4], 0.5f);
|
|
||||||
player.analogs[i] =
|
|
||||||
sdl2_config->Get(group, Settings::NativeAnalog::mapping[i], default_param);
|
|
||||||
if (player.analogs[i].empty()) {
|
|
||||||
player.analogs[i] = default_param;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
|
||||||
const std::string default_param =
|
|
||||||
InputCommon::GenerateKeyboardParam(default_motions[i]);
|
|
||||||
auto& player_motions = player.motions[i];
|
|
||||||
|
|
||||||
player_motions =
|
|
||||||
sdl2_config->Get(group, Settings::NativeMotion::mapping[i], default_param);
|
|
||||||
if (player_motions.empty()) {
|
|
||||||
player_motions = default_param;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
player.connected = sdl2_config->GetBoolean(group, "connected", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
|
||||||
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
|
||||||
Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
|
|
||||||
"ControlsGeneral", std::string("debug_pad_") + Settings::NativeButton::mapping[i],
|
|
||||||
default_param);
|
|
||||||
if (Settings::values.debug_pad_buttons[i].empty())
|
|
||||||
Settings::values.debug_pad_buttons[i] = default_param;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
|
||||||
std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
|
||||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
|
||||||
default_analogs[i][3], default_analogs[i][4], 0.5f);
|
|
||||||
Settings::values.debug_pad_analogs[i] = sdl2_config->Get(
|
|
||||||
"ControlsGeneral", std::string("debug_pad_") + Settings::NativeAnalog::mapping[i],
|
|
||||||
default_param);
|
|
||||||
if (Settings::values.debug_pad_analogs[i].empty())
|
|
||||||
Settings::values.debug_pad_analogs[i] = default_param;
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.touchscreen.enabled =
|
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
|
|
||||||
Settings::values.touchscreen.rotation_angle =
|
|
||||||
sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0);
|
|
||||||
Settings::values.touchscreen.diameter_x =
|
|
||||||
sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
|
|
||||||
Settings::values.touchscreen.diameter_y =
|
|
||||||
sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
|
|
||||||
|
|
||||||
int num_touch_from_button_maps =
|
|
||||||
sdl2_config->GetInteger("ControlsGeneral", "touch_from_button_map", 0);
|
|
||||||
if (num_touch_from_button_maps > 0) {
|
|
||||||
for (int i = 0; i < num_touch_from_button_maps; ++i) {
|
|
||||||
Settings::TouchFromButtonMap map;
|
|
||||||
map.name = sdl2_config->Get("ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) +
|
|
||||||
std::string("_name"),
|
|
||||||
"default");
|
|
||||||
const int num_touch_maps = sdl2_config->GetInteger(
|
|
||||||
"ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"),
|
|
||||||
0);
|
|
||||||
map.buttons.reserve(num_touch_maps);
|
|
||||||
|
|
||||||
for (int j = 0; j < num_touch_maps; ++j) {
|
|
||||||
std::string touch_mapping =
|
|
||||||
sdl2_config->Get("ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) +
|
|
||||||
std::string("_bind_") + std::to_string(j),
|
|
||||||
"");
|
|
||||||
map.buttons.emplace_back(std::move(touch_mapping));
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.touch_from_button_maps.emplace_back(std::move(map));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Settings::values.touch_from_button_maps.emplace_back(
|
|
||||||
Settings::TouchFromButtonMap{"default", {}});
|
|
||||||
num_touch_from_button_maps = 1;
|
|
||||||
}
|
|
||||||
Settings::values.touch_from_button_map_index = std::clamp(
|
|
||||||
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
|
|
||||||
|
|
||||||
ReadCategory(Settings::Category::Audio);
|
|
||||||
ReadCategory(Settings::Category::Core);
|
|
||||||
ReadCategory(Settings::Category::Cpu);
|
|
||||||
ReadCategory(Settings::Category::CpuDebug);
|
|
||||||
ReadCategory(Settings::Category::CpuUnsafe);
|
|
||||||
ReadCategory(Settings::Category::Renderer);
|
|
||||||
ReadCategory(Settings::Category::RendererAdvanced);
|
|
||||||
ReadCategory(Settings::Category::RendererDebug);
|
|
||||||
ReadCategory(Settings::Category::System);
|
|
||||||
ReadCategory(Settings::Category::SystemAudio);
|
|
||||||
ReadCategory(Settings::Category::DataStorage);
|
|
||||||
ReadCategory(Settings::Category::Debugging);
|
|
||||||
ReadCategory(Settings::Category::DebuggingGraphics);
|
|
||||||
ReadCategory(Settings::Category::Miscellaneous);
|
|
||||||
ReadCategory(Settings::Category::Network);
|
|
||||||
ReadCategory(Settings::Category::WebService);
|
|
||||||
|
|
||||||
// Data Storage
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::NANDDir,
|
|
||||||
sdl2_config->Get("Data Storage", "nand_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::SDMCDir,
|
|
||||||
sdl2_config->Get("Data Storage", "sdmc_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::LoadDir,
|
|
||||||
sdl2_config->Get("Data Storage", "load_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::DumpDir,
|
|
||||||
sdl2_config->Get("Data Storage", "dump_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
|
|
||||||
|
|
||||||
// Debugging
|
|
||||||
Settings::values.record_frame_times =
|
|
||||||
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
|
|
||||||
|
|
||||||
const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
|
|
||||||
std::stringstream ss(title_list);
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(ss, line, '|')) {
|
|
||||||
const auto title_id = std::strtoul(line.c_str(), nullptr, 16);
|
|
||||||
const auto disabled_list = sdl2_config->Get("AddOns", "disabled_" + line, "");
|
|
||||||
|
|
||||||
std::stringstream inner_ss(disabled_list);
|
|
||||||
std::string inner_line;
|
|
||||||
std::vector<std::string> out;
|
|
||||||
while (std::getline(inner_ss, inner_line, '|')) {
|
|
||||||
out.push_back(inner_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.disabled_addons.insert_or_assign(title_id, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::Reload() {
|
|
||||||
LoadINI(DefaultINI::sdl2_config_file);
|
|
||||||
ReadValues();
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
|
|
||||||
class INIReader;
|
|
||||||
|
|
||||||
class Config {
|
|
||||||
std::filesystem::path sdl2_config_loc;
|
|
||||||
std::unique_ptr<INIReader> sdl2_config;
|
|
||||||
|
|
||||||
bool LoadINI(const std::string& default_contents = "", bool retry = true);
|
|
||||||
void ReadValues();
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Config(std::optional<std::filesystem::path> config_path);
|
|
||||||
~Config();
|
|
||||||
|
|
||||||
void Reload();
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Applies a value read from the sdl2_config to a Setting.
|
|
||||||
*
|
|
||||||
* @param group The name of the INI group
|
|
||||||
* @param setting The yuzu setting to modify
|
|
||||||
*/
|
|
||||||
template <typename Type, bool ranged>
|
|
||||||
void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
|
|
||||||
void ReadCategory(Settings::Category category);
|
|
||||||
};
|
|
@ -0,0 +1,257 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
// SDL will break our main function in yuzu-cmd if we don't define this before adding SDL.h
|
||||||
|
#define SDL_MAIN_HANDLED
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#include "input_common/main.h"
|
||||||
|
#include "sdl_config.h"
|
||||||
|
|
||||||
|
const std::array<int, Settings::NativeButton::NumButtons> SdlConfig::default_buttons = {
|
||||||
|
SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T,
|
||||||
|
SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W,
|
||||||
|
SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<int, Settings::NativeMotion::NumMotions> SdlConfig::default_motions = {
|
||||||
|
SDL_SCANCODE_7,
|
||||||
|
SDL_SCANCODE_8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> SdlConfig::default_analogs{
|
||||||
|
{
|
||||||
|
{
|
||||||
|
SDL_SCANCODE_UP,
|
||||||
|
SDL_SCANCODE_DOWN,
|
||||||
|
SDL_SCANCODE_LEFT,
|
||||||
|
SDL_SCANCODE_RIGHT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SDL_SCANCODE_I,
|
||||||
|
SDL_SCANCODE_K,
|
||||||
|
SDL_SCANCODE_J,
|
||||||
|
SDL_SCANCODE_L,
|
||||||
|
},
|
||||||
|
}};
|
||||||
|
|
||||||
|
const std::array<int, 2> SdlConfig::default_stick_mod = {
|
||||||
|
SDL_SCANCODE_D,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<int, 2> SdlConfig::default_ringcon_analogs{{
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
}};
|
||||||
|
|
||||||
|
SdlConfig::SdlConfig(const std::optional<std::string> config_path) {
|
||||||
|
Initialize(config_path);
|
||||||
|
ReadSdlValues();
|
||||||
|
SaveSdlValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
SdlConfig::~SdlConfig() {
|
||||||
|
if (global) {
|
||||||
|
SdlConfig::SaveAllValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::ReloadAllValues() {
|
||||||
|
Reload();
|
||||||
|
ReadSdlValues();
|
||||||
|
SaveSdlValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::SaveAllValues() {
|
||||||
|
Save();
|
||||||
|
SaveSdlValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::ReadSdlValues() {
|
||||||
|
ReadSdlControlValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::ReadSdlControlValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||||
|
|
||||||
|
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||||
|
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||||
|
ReadSdlPlayerValues(p);
|
||||||
|
}
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
EndGroup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ReadDebugControlValues();
|
||||||
|
ReadHidbusValues();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) {
|
||||||
|
std::string player_prefix;
|
||||||
|
if (type != ConfigType::InputProfile) {
|
||||||
|
player_prefix.append("player_").append(ToString(player_index)).append("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
const auto profile_name =
|
||||||
|
ReadStringSetting(std::string(player_prefix).append("profile_name"));
|
||||||
|
if (profile_name.empty()) {
|
||||||
|
// Use the global input config
|
||||||
|
player = Settings::values.players.GetValue(true)[player_index];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
|
auto& player_buttons = player.buttons[i];
|
||||||
|
|
||||||
|
player_buttons = ReadStringSetting(
|
||||||
|
std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param);
|
||||||
|
if (player_buttons.empty()) {
|
||||||
|
player_buttons = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
|
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||||
|
auto& player_analogs = player.analogs[i];
|
||||||
|
|
||||||
|
player_analogs = ReadStringSetting(
|
||||||
|
std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param);
|
||||||
|
if (player_analogs.empty()) {
|
||||||
|
player_analogs = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||||
|
auto& player_motions = player.motions[i];
|
||||||
|
|
||||||
|
player_motions = ReadStringSetting(
|
||||||
|
std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param);
|
||||||
|
if (player_motions.empty()) {
|
||||||
|
player_motions = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::ReadDebugControlValues() {
|
||||||
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
|
auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i];
|
||||||
|
debug_pad_buttons = ReadStringSetting(
|
||||||
|
std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param);
|
||||||
|
if (debug_pad_buttons.empty()) {
|
||||||
|
debug_pad_buttons = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
|
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||||
|
auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
|
||||||
|
debug_pad_analogs = ReadStringSetting(
|
||||||
|
std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param);
|
||||||
|
if (debug_pad_analogs.empty()) {
|
||||||
|
debug_pad_analogs = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::ReadHidbusValues() {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
|
||||||
|
auto& ringcon_analogs = Settings::values.ringcon_analogs;
|
||||||
|
|
||||||
|
ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param);
|
||||||
|
if (ringcon_analogs.empty()) {
|
||||||
|
ringcon_analogs = default_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::SaveSdlValues() {
|
||||||
|
SaveSdlControlValues();
|
||||||
|
|
||||||
|
WriteToIni();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::SaveSdlControlValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||||
|
|
||||||
|
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||||
|
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||||
|
SaveSdlPlayerValues(p);
|
||||||
|
}
|
||||||
|
if (IsCustomConfig()) {
|
||||||
|
EndGroup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SaveDebugControlValues();
|
||||||
|
SaveHidbusValues();
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) {
|
||||||
|
std::string player_prefix;
|
||||||
|
if (type != ConfigType::InputProfile) {
|
||||||
|
player_prefix = std::string("player_").append(ToString(player_index)).append("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
|
if (IsCustomConfig() && player.profile_name.empty()) {
|
||||||
|
// No custom profile selected
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
|
WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]),
|
||||||
|
player.buttons[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
|
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||||
|
WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]),
|
||||||
|
player.analogs[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||||
|
WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]),
|
||||||
|
player.motions[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::SaveDebugControlValues() {
|
||||||
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
|
WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]),
|
||||||
|
Settings::values.debug_pad_buttons[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
|
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||||
|
WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]),
|
||||||
|
Settings::values.debug_pad_analogs[i], std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdlConfig::SaveHidbusValues() {
|
||||||
|
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
|
0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
|
||||||
|
WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs,
|
||||||
|
std::make_optional(default_param));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Settings::BasicSetting*>& SdlConfig::FindRelevantList(Settings::Category category) {
|
||||||
|
return Settings::values.linkage.by_category[category];
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "frontend_common/config.h"
|
||||||
|
|
||||||
|
class SdlConfig final : public Config {
|
||||||
|
public:
|
||||||
|
explicit SdlConfig(std::optional<std::string> config_path);
|
||||||
|
~SdlConfig() override;
|
||||||
|
|
||||||
|
void ReloadAllValues() override;
|
||||||
|
void SaveAllValues() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ReadSdlValues();
|
||||||
|
void ReadSdlPlayerValues(std::size_t player_index);
|
||||||
|
void ReadSdlControlValues();
|
||||||
|
void ReadHidbusValues() override;
|
||||||
|
void ReadDebugControlValues() override;
|
||||||
|
void ReadPathValues() override {}
|
||||||
|
void ReadShortcutValues() override {}
|
||||||
|
void ReadUIValues() override {}
|
||||||
|
void ReadUIGamelistValues() override {}
|
||||||
|
void ReadUILayoutValues() override {}
|
||||||
|
void ReadMultiplayerValues() override {}
|
||||||
|
|
||||||
|
void SaveSdlValues();
|
||||||
|
void SaveSdlPlayerValues(std::size_t player_index);
|
||||||
|
void SaveSdlControlValues();
|
||||||
|
void SaveHidbusValues() override;
|
||||||
|
void SaveDebugControlValues() override;
|
||||||
|
void SavePathValues() override {}
|
||||||
|
void SaveShortcutValues() override {}
|
||||||
|
void SaveUIValues() override {}
|
||||||
|
void SaveUIGamelistValues() override {}
|
||||||
|
void SaveUILayoutValues() override {}
|
||||||
|
void SaveMultiplayerValues() override {}
|
||||||
|
|
||||||
|
std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
||||||
|
static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
|
||||||
|
static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
||||||
|
static const std::array<int, 2> default_stick_mod;
|
||||||
|
static const std::array<int, 2> default_ringcon_analogs;
|
||||||
|
};
|
Loading…
Reference in New Issue