Move GUI settings from CemuConfig to the wxWidgets code

This commit is contained in:
SSimco 2025-07-12 10:06:57 +03:00
parent b95f8331a8
commit 68299a98e6
25 changed files with 620 additions and 456 deletions

View File

@ -85,7 +85,7 @@ bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules)
auto gp = std::make_shared<GraphicPack2>(rulesPath, rules);
// check if enabled and preset set
const auto& config_entries = g_config.data().graphic_pack_entries;
const auto& config_entries = GetConfigHandle().data().graphic_pack_entries;
// legacy absolute path checking for not breaking compatibility
auto file = gp->GetRulesPath();

View File

@ -60,14 +60,6 @@ bool ActiveSettings::DisplayDRCEnabled()
return g_current_game_profile->StartWithGamepadView();
}
bool ActiveSettings::FullscreenEnabled()
{
if (LaunchSettings::FullscreenEnabled().has_value())
return LaunchSettings::FullscreenEnabled().value();
return GetConfig().fullscreen;
}
CPUMode ActiveSettings::GetCPUMode()
{
auto mode = g_current_game_profile->GetCPUMode().value_or(CPUMode::Auto);

View File

@ -83,7 +83,6 @@ public:
// general
[[nodiscard]] static bool LoadSharedLibrariesEnabled();
[[nodiscard]] static bool DisplayDRCEnabled();
[[nodiscard]] static bool FullscreenEnabled();
// cpu
[[nodiscard]] static CPUMode GetCPUMode();

View File

@ -6,17 +6,15 @@
#include "ActiveSettings.h"
XMLCemuConfig_t g_config(L"settings.xml");
void CemuConfig::SetMLCPath(fs::path path, bool save)
{
mlc_path.SetValue(_pathToUtf8(path));
if(save)
g_config.Save();
GetConfigHandle().Save();
Account::RefreshAccounts();
}
void CemuConfig::Load(XMLConfigParser& parser)
XMLConfigParser CemuConfig::Load(XMLConfigParser& parser)
{
auto new_parser = parser.get("content");
if (new_parser.valid())
@ -32,94 +30,11 @@ void CemuConfig::Load(XMLConfigParser& parser)
permanent_storage = parser.get("permanent_storage", permanent_storage);
language = parser.get<sint32>("language", 0);
use_discord_presence = parser.get("use_discord_presence", true);
fullscreen_menubar = parser.get("fullscreen_menubar", false);
feral_gamemode = parser.get("feral_gamemode", false);
check_update = parser.get("check_update", check_update);
receive_untested_updates = parser.get("receive_untested_updates", receive_untested_updates);
save_screenshot = parser.get("save_screenshot", save_screenshot);
did_show_vulkan_warning = parser.get("vk_warning", did_show_vulkan_warning);
did_show_graphic_pack_download = parser.get("gp_download", did_show_graphic_pack_download);
did_show_macos_disclaimer = parser.get("macos_disclaimer", did_show_macos_disclaimer);
fullscreen = parser.get("fullscreen", fullscreen);
proxy_server = parser.get("proxy_server", "");
disable_screensaver = parser.get("disable_screensaver", disable_screensaver);
play_boot_sound = parser.get("play_boot_sound", play_boot_sound);
console_language = parser.get("console_language", console_language.GetInitValue());
window_position.x = parser.get("window_position").get("x", -1);
window_position.y = parser.get("window_position").get("y", -1);
window_size.x = parser.get("window_size").get("x", -1);
window_size.y = parser.get("window_size").get("y", -1);
window_maximized = parser.get("window_maximized", false);
pad_open = parser.get("open_pad", false);
pad_position.x = parser.get("pad_position").get("x", -1);
pad_position.y = parser.get("pad_position").get("y", -1);
pad_size.x = parser.get("pad_size").get("x", -1);
pad_size.y = parser.get("pad_size").get("y", -1);
pad_maximized = parser.get("pad_maximized", false);
auto gamelist = parser.get("GameList");
game_list_style = gamelist.get("style", 0);
game_list_column_order = gamelist.get("order", "");
show_icon_column = parser.get("show_icon_column", true);
// return default width if value in config file out of range
auto loadColumnSize = [&gamelist] (const char *name, uint32 defaultWidth)
{
sint64 val = gamelist.get(name, DefaultColumnSize::name);
if (val < 0 || val > (sint64) std::numeric_limits<uint32>::max)
return defaultWidth;
return static_cast<uint32>(val);
};
column_width.name = loadColumnSize("name_width", DefaultColumnSize::name);
column_width.version = loadColumnSize("version_width", DefaultColumnSize::version);
column_width.dlc = loadColumnSize("dlc_width", DefaultColumnSize::dlc);
column_width.game_time = loadColumnSize("game_time_width", DefaultColumnSize::game_time);
column_width.game_started = loadColumnSize("game_started_width", DefaultColumnSize::game_started);
column_width.region = loadColumnSize("region_width", DefaultColumnSize::region);
column_width.title_id = loadColumnSize("title_id", DefaultColumnSize::title_id);
recent_launch_files.clear();
auto launch_parser = parser.get("RecentLaunchFiles");
for (auto element = launch_parser.get("Entry"); element.valid(); element = launch_parser.get("Entry", element))
{
const std::string path = element.value("");
if (path.empty())
continue;
try
{
recent_launch_files.emplace_back(path);
}
catch (const std::exception&)
{
cemuLog_log(LogType::Force, "config load error: can't load recently launched game file: {}", path);
}
}
recent_nfc_files.clear();
auto nfc_parser = parser.get("RecentNFCFiles");
for (auto element = nfc_parser.get("Entry"); element.valid(); element = nfc_parser.get("Entry", element))
{
const std::string path = element.value("");
if (path.empty())
continue;
try
{
recent_nfc_files.emplace_back(path);
}
catch (const std::exception&)
{
cemuLog_log(LogType::Force, "config load error: can't load recently launched nfc file: {}", path);
}
}
game_paths.clear();
auto game_path_parser = parser.get("GamePaths");
for (auto element = game_path_parser.get("Entry"); element.valid(); element = game_path_parser.get("Entry", element))
@ -353,23 +268,16 @@ void CemuConfig::Load(XMLConfigParser& parser)
dsu_client.host = dsuc.get_attribute("host", dsu_client.host);
dsu_client.port = dsuc.get_attribute("port", dsu_client.port);
// hotkeys
auto xml_hotkeys = parser.get("Hotkeys");
hotkeys.modifiers = xml_hotkeys.get("modifiers", WindowSystem::getDefaultHotkeyConfig(WindowSystem::HotKey::MODIFIERS));
hotkeys.exitFullscreen = xml_hotkeys.get("ExitFullscreen", WindowSystem::getDefaultHotkeyConfig(WindowSystem::HotKey::EXIT_FULLSCREEN));
hotkeys.toggleFullscreen = xml_hotkeys.get("ToggleFullscreen", WindowSystem::getDefaultHotkeyConfig(WindowSystem::HotKey::TOGGLE_FULLSCREEN));
hotkeys.toggleFullscreenAlt = xml_hotkeys.get("ToggleFullscreenAlt", WindowSystem::getDefaultHotkeyConfig(WindowSystem::HotKey::TOGGLE_FULLSCREEN_ALT));
hotkeys.takeScreenshot = xml_hotkeys.get("TakeScreenshot", WindowSystem::getDefaultHotkeyConfig(WindowSystem::HotKey::TAKE_SCREENSHOT));
hotkeys.toggleFastForward = xml_hotkeys.get("ToggleFastForward", WindowSystem::getDefaultHotkeyConfig(WindowSystem::HotKey::TOGGLE_FAST_FORWARD));
// emulatedusbdevices
auto usbdevices = parser.get("EmulatedUsbDevices");
emulated_usb_devices.emulate_skylander_portal = usbdevices.get("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal);
emulated_usb_devices.emulate_infinity_base = usbdevices.get("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base);
emulated_usb_devices.emulate_dimensions_toypad = usbdevices.get("EmulateDimensionsToypad", emulated_usb_devices.emulate_dimensions_toypad);
return parser;
}
void CemuConfig::Save(XMLConfigParser& parser)
XMLConfigParser CemuConfig::Save(XMLConfigParser& parser)
{
auto config = parser.set("content");
// general settings
@ -377,65 +285,12 @@ void CemuConfig::Save(XMLConfigParser& parser)
config.set("advanced_ppc_logging", advanced_ppc_logging.GetValue());
config.set("mlc_path", mlc_path.GetValue().c_str());
config.set<bool>("permanent_storage", permanent_storage);
config.set<sint32>("language", language);
config.set<bool>("use_discord_presence", use_discord_presence);
config.set<bool>("fullscreen_menubar", fullscreen_menubar);
config.set<bool>("feral_gamemode", feral_gamemode);
config.set<bool>("check_update", check_update);
config.set<bool>("receive_untested_updates", receive_untested_updates);
config.set<bool>("save_screenshot", save_screenshot);
config.set<bool>("vk_warning", did_show_vulkan_warning);
config.set<bool>("gp_download", did_show_graphic_pack_download);
config.set<bool>("macos_disclaimer", did_show_macos_disclaimer);
config.set<bool>("fullscreen", fullscreen);
config.set("proxy_server", proxy_server.GetValue().c_str());
config.set<bool>("disable_screensaver", disable_screensaver);
config.set<bool>("play_boot_sound", play_boot_sound);
// config.set("cpu_mode", cpu_mode.GetValue());
//config.set("console_region", console_region.GetValue());
config.set("console_language", console_language.GetValue());
auto wpos = config.set("window_position");
wpos.set<sint32>("x", window_position.x);
wpos.set<sint32>("y", window_position.y);
auto wsize = config.set("window_size");
wsize.set<sint32>("x", window_size.x);
wsize.set<sint32>("y", window_size.y);
config.set<bool>("window_maximized", window_maximized);
config.set<bool>("open_pad", pad_open);
auto ppos = config.set("pad_position");
ppos.set<sint32>("x", pad_position.x);
ppos.set<sint32>("y", pad_position.y);
auto psize = config.set("pad_size");
psize.set<sint32>("x", pad_size.x);
psize.set<sint32>("y", pad_size.y);
config.set<bool>("pad_maximized", pad_maximized);
config.set<bool>("show_icon_column" , show_icon_column);
auto gamelist = config.set("GameList");
gamelist.set("style", game_list_style);
gamelist.set("order", game_list_column_order);
gamelist.set("name_width", column_width.name);
gamelist.set("version_width", column_width.version);
gamelist.set("dlc_width", column_width.dlc);
gamelist.set("game_time_width", column_width.game_time);
gamelist.set("game_started_width", column_width.game_started);
gamelist.set("region_width", column_width.region);
gamelist.set("title_id", column_width.title_id);
auto launch_files_parser = config.set("RecentLaunchFiles");
for (const auto& entry : recent_launch_files)
{
launch_files_parser.set("Entry", entry.c_str());
}
auto nfc_files_parser = config.set("RecentNFCFiles");
for (const auto& entry : recent_nfc_files)
{
nfc_files_parser.set("Entry", entry.c_str());
}
// game paths
auto game_path_parser = config.set("GamePaths");
@ -565,20 +420,13 @@ void CemuConfig::Save(XMLConfigParser& parser)
dsuc.set_attribute("host", dsu_client.host);
dsuc.set_attribute("port", dsu_client.port);
// hotkeys
auto xml_hotkeys = config.set("Hotkeys");
xml_hotkeys.set("modifiers", hotkeys.modifiers);
xml_hotkeys.set("ExitFullscreen", hotkeys.exitFullscreen);
xml_hotkeys.set("ToggleFullscreen", hotkeys.toggleFullscreen);
xml_hotkeys.set("ToggleFullscreenAlt", hotkeys.toggleFullscreenAlt);
xml_hotkeys.set("TakeScreenshot", hotkeys.takeScreenshot);
xml_hotkeys.set("ToggleFastForward", hotkeys.toggleFastForward);
// emulated usb devices
auto usbdevices = config.set("EmulatedUsbDevices");
usbdevices.set("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal.GetValue());
usbdevices.set("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base.GetValue());
usbdevices.set("EmulateDimensionsToypad", emulated_usb_devices.emulate_dimensions_toypad.GetValue());
return config;
}
GameEntry* CemuConfig::GetGameEntryByTitleId(uint64 titleId)
@ -645,22 +493,6 @@ void CemuConfig::SetGameListCustomName(uint64 titleId, std::string customName)
gameEntry->custom_name = std::move(customName);
}
void CemuConfig::AddRecentlyLaunchedFile(std::string_view file)
{
recent_launch_files.insert(recent_launch_files.begin(), std::string(file));
RemoveDuplicatesKeepOrder(recent_launch_files);
while(recent_launch_files.size() > kMaxRecentEntries)
recent_launch_files.pop_back();
}
void CemuConfig::AddRecentNfcFile(std::string_view file)
{
recent_nfc_files.insert(recent_nfc_files.begin(), std::string(file));
RemoveDuplicatesKeepOrder(recent_nfc_files);
while (recent_nfc_files.size() > kMaxRecentEntries)
recent_nfc_files.pop_back();
}
NetworkService CemuConfig::GetAccountNetworkService(uint32 persistentId)
{
auto it = account.service_select.find(persistentId);

View File

@ -188,49 +188,6 @@ enum class CrashDump
ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled);
#endif
typedef union
{
struct
{
uint16 key : 13; // enough bits for all keycodes
uint16 alt : 1;
uint16 ctrl : 1;
uint16 shift : 1;
};
uint16 raw;
} uKeyboardHotkey;
typedef sint16 ControllerHotkey_t;
struct sHotkeyCfg
{
static constexpr uint8 keyboardNone{0};
static constexpr sint8 controllerNone{-1}; // no enums to work with, but buttons start from 0
uKeyboardHotkey keyboard{keyboardNone};
ControllerHotkey_t controller{controllerNone};
/* for defaults */
sHotkeyCfg(const uKeyboardHotkey& keyboard = {keyboardNone}, const ControllerHotkey_t& controller = {controllerNone}) : keyboard(keyboard), controller(controller) {};
/* for reading from xml */
sHotkeyCfg(const char* xml_values)
{
std::istringstream iss(xml_values);
iss >> keyboard.raw >> controller;
}
};
template <>
struct fmt::formatter<sHotkeyCfg> : formatter<string_view>
{
template <typename FormatContext>
auto format(const sHotkeyCfg c, FormatContext &ctx) const {
std::string xml_values = fmt::format("{} {}", c.keyboard.raw, c.controller);
return formatter<string_view>::format(xml_values, ctx);
}
};
template <>
struct fmt::formatter<PrecompiledShaderOption> : formatter<string_view> {
template <typename FormatContext>
@ -375,17 +332,6 @@ struct fmt::formatter<CrashDump> : formatter<string_view> {
};
#endif
namespace DefaultColumnSize {
enum : uint32 {
name = 500u,
version = 60u,
dlc = 50u,
game_time = 140u,
game_started = 160u,
region = 80u,
title_id = 160u
};
};
struct CemuConfig
{
@ -404,12 +350,7 @@ struct CemuConfig
ConfigValue<bool> permanent_storage{ true };
ConfigValue<sint32> language{ 0 };
ConfigValue<bool> use_discord_presence{ true };
ConfigValue<std::string> mlc_path{};
ConfigValue<bool> fullscreen_menubar{ false };
ConfigValue<bool> fullscreen{ false };
ConfigValue<bool> feral_gamemode{false};
ConfigValue<std::string> proxy_server{};
// temporary workaround because feature crashes on macOS
@ -440,43 +381,6 @@ struct CemuConfig
ConfigValueBounds<CPUMode> cpu_mode{ CPUMode::Auto };
ConfigValueBounds<CafeConsoleLanguage> console_language{ CafeConsoleLanguage::EN };
// max 15 entries
static constexpr size_t kMaxRecentEntries = 15;
std::vector<std::string> recent_launch_files;
std::vector<std::string> recent_nfc_files;
Vector2i window_position{-1,-1};
Vector2i window_size{ -1,-1 };
ConfigValue<bool> window_maximized;
ConfigValue<bool> pad_open;
Vector2i pad_position{ -1,-1 };
Vector2i pad_size{ -1,-1 };
ConfigValue<bool> pad_maximized;
ConfigValue<bool> check_update{true};
ConfigValue<bool> receive_untested_updates{false};
ConfigValue<bool> save_screenshot{true};
ConfigValue<bool> did_show_vulkan_warning{false};
ConfigValue<bool> did_show_graphic_pack_download{false}; // no longer used but we keep the config value around in case people downgrade Cemu. Despite the name this was used for the Getting Started dialog
ConfigValue<bool> did_show_macos_disclaimer{false};
ConfigValue<bool> show_icon_column{ true };
int game_list_style = 0;
std::string game_list_column_order;
struct
{
uint32 name = DefaultColumnSize::name;
uint32 version = DefaultColumnSize::version;
uint32 dlc = DefaultColumnSize::dlc;
uint32 game_time = DefaultColumnSize::game_time;
uint32 game_started = DefaultColumnSize::game_started;
uint32 region = DefaultColumnSize::region;
uint32 title_id = 0;
} column_width{};
// graphics
ConfigValue<GraphicAPI> graphic_api{ kVulkan };
std::array<uint8, 16> graphic_device_uuid;
@ -539,26 +443,12 @@ struct CemuConfig
ConfigValue<uint16> port{ 26760 };
}dsu_client{};
// hotkeys
struct
{
sHotkeyCfg modifiers;
sHotkeyCfg toggleFullscreen;
sHotkeyCfg toggleFullscreenAlt;
sHotkeyCfg exitFullscreen;
sHotkeyCfg takeScreenshot;
sHotkeyCfg toggleFastForward;
} hotkeys{};
// debug
ConfigValueBounds<CrashDump> crash_dump{ CrashDump::Disabled };
ConfigValue<uint16> gdb_port{ 1337 };
void Load(XMLConfigParser& parser);
void Save(XMLConfigParser& parser);
void AddRecentlyLaunchedFile(std::string_view file);
void AddRecentNfcFile(std::string_view file);
XMLConfigParser Load(XMLConfigParser& parser);
XMLConfigParser Save(XMLConfigParser& parser);
bool IsGameListFavorite(uint64 titleId);
void SetGameListFavorite(uint64 titleId, bool isFavorite);
@ -594,8 +484,15 @@ struct CemuConfig
GameEntry* CreateGameEntry(uint64 titleId);
};
typedef XMLDataConfig<CemuConfig, &CemuConfig::Load, &CemuConfig::Save> XMLCemuConfig_t;
extern XMLCemuConfig_t g_config;
inline CemuConfig& GetConfig() { return g_config.data(); }
typedef XMLDataConfig<CemuConfig> XMLCemuConfig_t;
inline XMLCemuConfig_t& GetConfigHandle()
{
static XMLCemuConfig_t config;
return config;
}
inline CemuConfig& GetConfig()
{
return GetConfigHandle().data();
}

View File

@ -71,7 +71,7 @@ struct PretendoURLs {
inline static std::string OLVURL = "https://discovery.olv.pretendo.cc/v1/endpoint";
};
typedef XMLDataConfig<NetworkConfig, &NetworkConfig::Load, &NetworkConfig::Save> XMLNetworkConfig_t;
typedef XMLDataConfig<NetworkConfig> XMLNetworkConfig_t;
extern XMLNetworkConfig_t n_config;
inline NetworkConfig& GetNetworkConfig() { return n_config.data();};

View File

@ -320,7 +320,15 @@ private:
bool m_is_root;
};
template <typename T, void(T::*L)(XMLConfigParser&) = nullptr, void(T::*S)(XMLConfigParser&) = nullptr>
using ChildXMLConfigParser = std::pair<std::function<void(XMLConfigParser&)>, std::function<void(XMLConfigParser&)>>;
template<typename T>
concept XMLConfigurable = requires(T t, XMLConfigParser& configParser) {
{ t.Save(configParser) } -> std::same_as<XMLConfigParser>;
{ t.Load(configParser) } -> std::same_as<XMLConfigParser>;
};
template <XMLConfigurable T>
class XMLConfig
{
public:
@ -339,9 +347,6 @@ public:
bool Load()
{
if (L == nullptr)
return false;
if (m_filename.empty())
return false;
@ -350,8 +355,6 @@ public:
bool Load(const std::wstring& filename)
{
if (L == nullptr)
return false;
FileStream* fs = FileStream::openFile(filename.c_str());
if (!fs)
{
@ -370,19 +373,23 @@ public:
{
cemuLog_logDebug(LogType::Force, "XMLConfig::Load > LoadFile {}", error);
}
if (success)
if (!success)
{
auto parser = XMLConfigParser(&doc);
(m_instance.*L)(parser);
return false;
}
auto parser = XMLConfigParser(&doc);
auto parentParser = m_instance.Load(parser);
for (auto [save, load] : m_childConfigParsers)
load(parentParser);
return true;
}
bool Save()
{
if (S == nullptr)
return false;
if (m_filename.empty())
return false;
@ -391,9 +398,6 @@ public:
bool Save(const std::wstring& filename)
{
if (S == nullptr)
return false;
std::wstring tmp_name = fmt::format(L"{}_{}.tmp", filename,rand() % 1000);
std::error_code err;
fs::create_directories(fs::path(filename).parent_path(), err);
@ -420,7 +424,10 @@ public:
doc.InsertFirstChild(declaration);
auto parser = XMLConfigParser(&doc);
(m_instance.*S)(parser);
auto parentParser = m_instance.Save(parser);
for (auto [save, load] : m_childConfigParsers)
save(parentParser);
const tinyxml2::XMLError error = doc.SaveFile(file);
const bool success = error == tinyxml2::XML_SUCCESS;
@ -445,24 +452,96 @@ public:
std::unique_lock<std::mutex> Lock() { return std::unique_lock(m_mutex); }
private:
void AddChildConfig(ChildXMLConfigParser childConfigParser)
{
m_childConfigParsers.push_back(childConfigParser);
}
private:
std::vector<ChildXMLConfigParser> m_childConfigParsers;
T& m_instance;
std::wstring m_filename;
std::mutex m_mutex;
};
template <typename T, void(T::*L)(XMLConfigParser&), void(T::*S)(XMLConfigParser&)>
class XMLDataConfig : public XMLConfig<T, L, S>
template<typename T>
concept XMLConfigProvider = requires(T t, ChildXMLConfigParser& configParser) {
{ t().Save() } -> std::same_as<bool>;
{ t().Load() } -> std::same_as<bool>;
{ t().Lock() } -> std::same_as<std::unique_lock<std::mutex>>;
{ t().AddChildConfig(configParser) } -> std::same_as<void>;
};
template<typename T, void (T::*L)(XMLConfigParser&), void (T::*S)(XMLConfigParser&)>
class XMLChildConfig
{
public:
XMLChildConfig(XMLConfigProvider auto getParentConfig)
{
m_parentConfig = {
.lock = [getParentConfig]() { return getParentConfig().Lock(); },
.save = [getParentConfig]() { return getParentConfig().Load(); },
.load = [getParentConfig]() { return getParentConfig().Save(); },
};
auto configParser = std::make_pair(
[this](XMLConfigParser& parser) {
(m_data.*S)(parser);
},
[this](XMLConfigParser& parser) {
(m_data.*L)(parser);
});
getParentConfig().AddChildConfig(configParser);
}
bool Save()
{
return m_parentConfig.save();
}
bool Load()
{
return m_parentConfig.load();
}
T& Data()
{
return m_data;
}
std::unique_lock<std::mutex> Lock()
{
return m_parentConfig.lock();
}
virtual ~XMLChildConfig() = default;
private:
T m_data;
struct
{
std::function<std::unique_lock<std::mutex>()> lock;
std::function<bool()> save;
std::function<bool()> load;
} m_parentConfig;
};
template<typename T>
struct XMLDataConfig {};
template <XMLConfigurable T>
class XMLDataConfig<T> : public XMLConfig<T>
{
public:
XMLDataConfig()
: XMLConfig<T, L, S>::XMLConfig(m_data), m_data() {}
: XMLConfig<T>::XMLConfig(m_data), m_data() {}
XMLDataConfig(std::wstring_view filename)
: XMLConfig<T, L, S>::XMLConfig(m_data, filename), m_data() {}
: XMLConfig<T>::XMLConfig(m_data, filename), m_data() {}
XMLDataConfig(std::wstring_view filename, T init_data)
: XMLConfig<T, L, S>::XMLConfig(m_data, filename), m_data(std::move(init_data)) {}
: XMLConfig<T>::XMLConfig(m_data, filename), m_data(std::move(init_data)) {}
XMLDataConfig(const XMLDataConfig& o) = delete;
@ -471,3 +550,51 @@ public:
private:
T m_data;
};
template<typename T>
concept XMLStandaloneConfigurable = requires(T t, XMLConfigParser& configParser) {
{ t.Save(configParser) } -> std::same_as<void>;
{ t.Load(configParser) } -> std::same_as<void>;
};
template<XMLStandaloneConfigurable T>
struct XMLConfigWrapper
{
XMLConfigParser Save(XMLConfigParser& configParser)
{
data.Save(configParser);
return configParser;
}
XMLConfigParser Load(XMLConfigParser& configParser)
{
data.Load(configParser);
return configParser;
}
T data;
};
template<XMLStandaloneConfigurable T>
class XMLDataConfig<T> : public XMLConfig<XMLConfigWrapper<T>>
{
public:
XMLDataConfig()
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper), m_configWrapper() {}
XMLDataConfig(std::wstring_view filename)
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper, filename), m_configWrapper() {}
XMLDataConfig(std::wstring_view filename, T init_data)
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper, filename), m_configWrapper(std::move(init_data)) {}
XMLDataConfig(const XMLDataConfig& o) = delete;
T& data()
{
return m_configWrapper.data;
}
private:
XMLConfigWrapper<T> m_configWrapper;
};

View File

@ -123,17 +123,4 @@ namespace WindowSystem
bool isFullScreen();
void captureInput(const ControllerState& currentState, const ControllerState& lastState);
enum class HotKey
{
MODIFIERS,
EXIT_FULLSCREEN,
TOGGLE_FULLSCREEN,
TOGGLE_FULLSCREEN_ALT,
TAKE_SCREENSHOT,
TOGGLE_FAST_FORWARD,
};
sHotkeyCfg getDefaultHotkeyConfig(HotKey hotKey);
}; // namespace WindowSystem

View File

@ -104,6 +104,8 @@ add_library(CemuWxGui
PadViewFrame.h
TitleManager.cpp
TitleManager.h
wxCemuConfig.cpp
wxCemuConfig.h
EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp
EmulatedUSBDevices/EmulatedUSBDeviceFrame.h
windows/PPCThreadsViewer

View File

@ -1,4 +1,5 @@
#include "wxgui/CemuApp.h"
#include "wxCemuConfig.h"
#include "wxgui/MainWindow.h"
#include "wxgui/wxgui.h"
#include "config/CemuConfig.h"
@ -11,6 +12,7 @@
#include "wxgui/helpers/wxHelpers.h"
#include "Cemu/ncrypto/ncrypto.h"
#include "wxgui/input/HotkeySettings.h"
#include <wx/language.h>
#if BOOST_OS_LINUX && HAS_WAYLAND
#include "wxgui/helpers/wxWayland.h"
@ -237,7 +239,7 @@ void CemuApp::InitializeExistingMLCOrFail(fs::path mlc)
else // reset path
{
GetConfig().mlc_path = "";
g_config.Save();
GetConfigHandle().Save();
}
}
else
@ -263,16 +265,19 @@ bool CemuApp::OnInit()
// make sure default cemu directories exist
CreateDefaultCemuFiles();
g_config.SetFilename(ActiveSettings::GetConfigPath("settings.xml").generic_wstring());
GetConfigHandle().SetFilename(ActiveSettings::GetConfigPath("settings.xml").generic_wstring());
auto& config = GetWxGUIConfig();
std::error_code ec;
bool isFirstStart = !fs::exists(ActiveSettings::GetConfigPath("settings.xml"), ec);
NetworkConfig::LoadOnce();
if(!isFirstStart)
if (!isFirstStart)
{
g_config.Load();
LocalizeUI(static_cast<wxLanguage>(GetConfig().language == wxLANGUAGE_DEFAULT ? wxLocale::GetSystemLanguage() : GetConfig().language.GetValue()));
GetConfigHandle().Load();
sint32 language = config.language.GetValue();
LocalizeUI(static_cast<wxLanguage>(language == wxLANGUAGE_DEFAULT ? wxLocale::GetSystemLanguage() : language));
}
else
{
@ -293,7 +298,7 @@ bool CemuApp::OnInit()
GettingStartedDialog dia(nullptr);
dia.ShowModal();
// make sure config is created. Gfx pack UI and input UI may create it earlier already, but we still want to update it
g_config.Save();
GetConfigHandle().Save();
// create mlc, on failure the user can quit here. So do this after the Getting Started dialog
InitializeNewMLCOrFail(ActiveSettings::GetMlcPath());
}
@ -332,7 +337,6 @@ bool CemuApp::OnInit()
Bind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this);
auto& config = GetConfig();
m_mainFrame = new MainWindow();
std::unique_lock lock(g_mutex);
@ -350,7 +354,7 @@ bool CemuApp::OnInit()
// show warning on macOS about state of builds
#if BOOST_OS_MACOS
if (!GetConfig().did_show_macos_disclaimer)
if (!config.did_show_macos_disclaimer)
{
const auto message = _(
"Thank you for testing the in-development build of Cemu for macOS.\n \n"
@ -359,8 +363,8 @@ bool CemuApp::OnInit()
wxMessageDialog dialog(nullptr, message, _("Preview version"), wxCENTRE | wxOK | wxICON_WARNING);
dialog.SetOKLabel(_("I understand"));
dialog.ShowModal();
GetConfig().did_show_macos_disclaimer = true;
g_config.Save();
config.did_show_macos_disclaimer = true;
GetConfigHandle().Save();
}
#endif

View File

@ -5,6 +5,7 @@
#include "util/helpers/SystemException.h"
#include "config/ActiveSettings.h"
#include "Common/FileStream.h"
#include "wxCemuConfig.h"
#include <wx/sizer.h>
#include <wx/gauge.h>
@ -118,7 +119,7 @@ bool CemuUpdateWindow::QueryUpdateInfo(std::string& downloadUrlOut, std::string&
#elif
#error Name for current platform is missing
#endif
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
if(config.receive_untested_updates)
urlStr.append("&allowNewUpdates=1");

View File

@ -73,7 +73,7 @@ wxPanel* EmulatedUSBDeviceFrame::AddSkylanderPage(wxNotebook* notebook)
m_emulatePortal->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
GetConfig().emulated_usb_devices.emulate_skylander_portal =
m_emulatePortal->IsChecked();
g_config.Save();
GetConfigHandle().Save();
});
row->Add(m_emulatePortal, 1, wxEXPAND | wxALL, 2);
boxSizer->Add(row, 1, wxEXPAND | wxALL, 2);
@ -103,7 +103,7 @@ wxPanel* EmulatedUSBDeviceFrame::AddInfinityPage(wxNotebook* notebook)
m_emulateBase->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
GetConfig().emulated_usb_devices.emulate_infinity_base =
m_emulateBase->IsChecked();
g_config.Save();
GetConfigHandle().Save();
});
row->Add(m_emulateBase, 1, wxEXPAND | wxALL, 2);
boxSizer->Add(row, 1, wxEXPAND | wxALL, 2);
@ -139,7 +139,7 @@ wxPanel* EmulatedUSBDeviceFrame::AddDimensionsPage(wxNotebook* notebook)
m_emulateToypad->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
GetConfig().emulated_usb_devices.emulate_dimensions_toypad =
m_emulateToypad->IsChecked();
g_config.Save();
GetConfigHandle().Save();
});
row->Add(m_emulateToypad, 1, wxEXPAND | wxALL, 2);
box_sizer->Add(row, 1, wxEXPAND | wxALL, 2);

View File

@ -1,3 +1,4 @@
#include "wxCemuConfig.h"
#include "wxgui/wxgui.h"
#include "wxgui/GeneralSettings2.h"
#include "wxgui/CemuApp.h"
@ -959,14 +960,15 @@ void GeneralSettings2::StoreConfig()
{
auto* app = (CemuApp*)wxTheApp;
auto& config = GetConfig();
auto& wxGuiConfig = GetWxGUIConfig();
config.use_discord_presence = m_discord_presence->IsChecked();
config.fullscreen_menubar = m_fullscreen_menubar->IsChecked();
config.check_update = m_auto_update->IsChecked();
config.save_screenshot = m_save_screenshot->IsChecked();
config.receive_untested_updates = m_receive_untested_releases->IsChecked();
wxGuiConfig.use_discord_presence = m_discord_presence->IsChecked();
wxGuiConfig.fullscreen_menubar = m_fullscreen_menubar->IsChecked();
wxGuiConfig.check_update = m_auto_update->IsChecked();
wxGuiConfig.save_screenshot = m_save_screenshot->IsChecked();
wxGuiConfig.receive_untested_updates = m_receive_untested_releases->IsChecked();
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
config.feral_gamemode = m_feral_gamemode->IsChecked();
wxGuiConfig.feral_gamemode = m_feral_gamemode->IsChecked();
#endif
config.play_boot_sound = m_play_boot_sound->IsChecked();
config.disable_screensaver = m_disable_screensaver->IsChecked();
@ -978,10 +980,10 @@ void GeneralSettings2::StoreConfig()
// -1 is default wx widget value -> set to dummy 0 so mainwindow and padwindow will update it
config.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
config.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
config.pad_position = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
config.pad_size = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
wxGuiConfig.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
wxGuiConfig.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
wxGuiConfig.pad_position = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
wxGuiConfig.pad_size = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
config.game_paths.clear();
for (auto& path : m_game_paths->GetStrings())
@ -989,7 +991,7 @@ void GeneralSettings2::StoreConfig()
auto selection = m_language->GetSelection();
if (selection == 0)
GetConfig().language = wxLANGUAGE_DEFAULT;
wxGuiConfig.language = wxLANGUAGE_DEFAULT;
else
{
const auto language = m_language->GetStringSelection();
@ -997,7 +999,7 @@ void GeneralSettings2::StoreConfig()
{
if (lang->DescriptionNative == language)
{
GetConfig().language = lang->Language;
wxGuiConfig.language = lang->Language;
break;
}
}
@ -1112,7 +1114,7 @@ void GeneralSettings2::StoreConfig()
config.crash_dump = (CrashDump)m_crash_dump->GetSelection();
config.gdb_port = m_gdb_port->GetValue();
g_config.Save();
GetConfigHandle().Save();
}
GeneralSettings2::~GeneralSettings2()
@ -1133,9 +1135,9 @@ void GeneralSettings2::OnClose(wxCloseEvent& event)
void GeneralSettings2::ValidateConfig()
{
g_config.Load();
GetConfigHandle().Load();
auto& data = g_config.data();
auto& data = GetConfigHandle().data();
// todo
//data.fullscreen_scaling = min(max(data.fullscreen_scaling,))
}
@ -1610,6 +1612,7 @@ void GeneralSettings2::HandleGraphicsApiSelection()
void GeneralSettings2::ApplyConfig()
{
ValidateConfig();
auto& wxGUIconfig = GetWxGUIConfig();
auto& config = GetConfig();
if (LaunchSettings::GetMLCPath().has_value())
@ -1617,20 +1620,20 @@ void GeneralSettings2::ApplyConfig()
else
m_mlc_path->SetValue(wxHelper::FromUtf8(config.mlc_path.GetValue()));
m_save_window_position_size->SetValue(config.window_position != Vector2i{-1,-1});
m_save_padwindow_position_size->SetValue(config.pad_position != Vector2i{-1,-1});
m_save_window_position_size->SetValue(wxGUIconfig.window_position != Vector2i{-1,-1});
m_save_padwindow_position_size->SetValue(wxGUIconfig.pad_position != Vector2i{-1,-1});
m_discord_presence->SetValue(config.use_discord_presence);
m_fullscreen_menubar->SetValue(config.fullscreen_menubar);
m_discord_presence->SetValue(wxGUIconfig.use_discord_presence);
m_fullscreen_menubar->SetValue(wxGUIconfig.fullscreen_menubar);
m_auto_update->SetValue(config.check_update);
m_receive_untested_releases->SetValue(config.receive_untested_updates);
m_save_screenshot->SetValue(config.save_screenshot);
m_auto_update->SetValue(wxGUIconfig.check_update);
m_receive_untested_releases->SetValue(wxGUIconfig.receive_untested_updates);
m_save_screenshot->SetValue(wxGUIconfig.save_screenshot);
m_disable_screensaver->SetValue(config.disable_screensaver);
m_play_boot_sound->SetValue(config.play_boot_sound);
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
m_feral_gamemode->SetValue(config.feral_gamemode);
m_feral_gamemode->SetValue(wxGUIconfig.feral_gamemode);
#endif
// temporary workaround because feature crashes on macOS
#if BOOST_OS_MACOS
@ -1646,7 +1649,7 @@ void GeneralSettings2::ApplyConfig()
const auto app = (CemuApp*)wxTheApp;
for (const auto& language : app->GetLanguages())
{
if (config.language == language->Language)
if (wxGUIconfig.language == language->Language)
{
m_language->SetStringSelection(language->DescriptionNative);
break;
@ -2124,7 +2127,7 @@ void GeneralSettings2::OnMLCPathClear(wxCommandEvent& event)
return;
GetConfig().SetMLCPath("");
StoreConfig();
g_config.Save();
GetConfigHandle().Save();
wxMessageBox(_("Cemu needs to be restarted for the changes to take effect."), _("Information"), wxOK | wxCENTRE | wxICON_INFORMATION, this);
// close settings and then cemu
wxCloseEvent closeEvent(wxEVT_CLOSE_WINDOW);

View File

@ -8,6 +8,7 @@
#include <wx/button.h>
#include "config/ActiveSettings.h"
#include "wxCemuConfig.h"
#include "wxgui/CemuApp.h"
#include "wxgui/DownloadGraphicPacksWindow.h"
#include "wxgui/GraphicPacksWindow2.h"
@ -204,7 +205,7 @@ wxPanel* GettingStartedDialog::CreatePage2()
void GettingStartedDialog::ApplySettings()
{
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
m_page2.fullscreenCheckbox->SetValue(config.fullscreen.GetValue());
m_page2.updateCheckbox->SetValue(config.check_update.GetValue());
m_page2.separateCheckbox->SetValue(config.pad_open.GetValue());
@ -225,11 +226,12 @@ void GettingStartedDialog::OnClose(wxCloseEvent& event)
{
event.Skip();
auto& config = GetConfig();
config.fullscreen = m_page2.fullscreenCheckbox->GetValue();
config.check_update = m_page2.updateCheckbox->GetValue();
config.pad_open = m_page2.separateCheckbox->GetValue();
auto& wxGUIConfig = GetWxGUIConfig();
wxGUIConfig.fullscreen = m_page2.fullscreenCheckbox->GetValue();
wxGUIConfig.check_update = m_page2.updateCheckbox->GetValue();
wxGUIConfig.pad_open = m_page2.separateCheckbox->GetValue();
auto& config = GetConfig();
const fs::path gamePath = wxHelper::MakeFSPath(m_page1.gamePathPicker->GetPath());
std::error_code ec;
if (!gamePath.empty() && fs::exists(gamePath, ec))

View File

@ -325,7 +325,7 @@ GraphicPacksWindow2::GraphicPacksWindow2(wxWindow* parent, uint64_t title_id_fil
void GraphicPacksWindow2::SaveStateToConfig()
{
auto& data = g_config.data();
auto& data = GetConfigHandle().data();
data.graphic_pack_entries.clear();
for (const auto& gp : GraphicPack2::GetGraphicPacks())
@ -348,7 +348,7 @@ void GraphicPacksWindow2::SaveStateToConfig()
}
}
g_config.Save();
GetConfigHandle().Save();
}
GraphicPacksWindow2::~GraphicPacksWindow2()

View File

@ -1,5 +1,6 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "interface/WindowSystem.h"
#include "wxCemuConfig.h"
#include "wxgui/wxgui.h"
#include "wxgui/MainWindow.h"
@ -274,7 +275,7 @@ public:
std::string path = filenames[0].utf8_string();
if (nfc::TouchTagFromFile(_utf8ToPath(path), &nfcError))
{
GetConfig().AddRecentNfcFile(path);
GetWxGUIConfig().AddRecentNfcFile(path);
m_window->UpdateNFCMenu();
return true;
}
@ -363,9 +364,8 @@ MainWindow::MainWindow()
LoadSettings();
auto& config = GetConfig();
#ifdef ENABLE_DISCORD_RPC
if (config.use_discord_presence)
if (GetWxGUIConfig().use_discord_presence)
m_discord = std::make_unique<DiscordPresence>();
#endif
@ -374,7 +374,7 @@ MainWindow::MainWindow()
if (LaunchSettings::GDBStubEnabled())
{
g_gdbstub = std::make_unique<GDBServer>(config.gdb_port);
g_gdbstub = std::make_unique<GDBServer>(GetConfig().gdb_port);
}
}
@ -572,9 +572,9 @@ bool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATE
}
if(launchTitle.IsValid())
GetConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchTitle.GetPath()));
GetWxGUIConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchTitle.GetPath()));
else
GetConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchPath));
GetWxGUIConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchPath));
wxWindowUpdateLocker lock(this);
@ -599,12 +599,12 @@ bool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATE
// ScreenSaver::SetInhibit(false);
}
if (ActiveSettings::FullscreenEnabled())
if (FullscreenEnabled())
SetFullScreen(true);
//GameMode support
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
if(GetConfig().feral_gamemode)
if(GetWxGUIConfig().feral_gamemode)
{
// attempt to start gamemode
if(gamemode_request_start() < 0)
@ -666,7 +666,7 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
}
else if (menuId >= MAINFRAME_MENU_ID_FILE_RECENT_0 && menuId <= MAINFRAME_MENU_ID_FILE_RECENT_LAST)
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
const size_t index = menuId - MAINFRAME_MENU_ID_FILE_RECENT_0;
if (index < config.recent_launch_files.size())
{
@ -760,14 +760,14 @@ void MainWindow::OnNFCMenu(wxCommandEvent& event)
}
else
{
GetConfig().AddRecentNfcFile(wxStrFilePath.utf8_string());
GetWxGUIConfig().AddRecentNfcFile(wxStrFilePath.utf8_string());
UpdateNFCMenu();
}
}
else if (event.GetId() >= MAINFRAME_MENU_ID_NFC_RECENT_0 && event.GetId() <= MAINFRAME_MENU_ID_NFC_RECENT_LAST)
{
const size_t index = event.GetId() - MAINFRAME_MENU_ID_NFC_RECENT_0;
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
if (index < config.recent_nfc_files.size())
{
const auto& path = config.recent_nfc_files[index];
@ -800,7 +800,7 @@ void MainWindow::OnFileExit(wxCommandEvent& event)
void MainWindow::TogglePadView()
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
if (config.pad_open)
{
if (m_padView)
@ -849,7 +849,7 @@ WXLRESULT MainWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
void MainWindow::OpenSettings()
{
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
const auto language = config.language;
GeneralSettings2 frame(this, m_game_launched);
@ -901,8 +901,8 @@ void MainWindow::OnOptionsInput(wxCommandEvent& event)
}
case MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW:
{
GetConfig().pad_open = !GetConfig().pad_open;
g_config.Save();
GetWxGUIConfig().pad_open = !GetWxGUIConfig().pad_open;
g_wxConfig.Save();
TogglePadView();
break;
@ -954,7 +954,7 @@ void MainWindow::OnAccountSelect(wxCommandEvent& event)
auto& config = GetConfig();
config.account.m_persistent_id = accounts[index].GetPersistentId();
// config.account.online_enabled.value = false; // reset online for safety
g_config.Save();
GetConfigHandle().Save();
}
void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
@ -1005,7 +1005,7 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
m_game_list->DeleteCachedStrings();
m_game_list->ReloadGameEntries(false);
}
g_config.Save();
GetConfigHandle().Save();
}
//void MainWindow::OnCPUMode(wxCommandEvent& event)
@ -1021,7 +1021,7 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
// else
// cemu_assert_debug(false);
//
// g_config.Save();
// GetConfigHandle().Save();
//}
void MainWindow::OnDebugSetting(wxCommandEvent& event)
@ -1085,7 +1085,7 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event)
else
cemu_assert_debug(false);
g_config.Save();
GetConfigHandle().Save();
}
void MainWindow::OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event)
@ -1102,14 +1102,14 @@ void MainWindow::OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event)
else
GetConfig().log_flag = GetConfig().log_flag.GetValue() & ~cemuLog_getFlag(loggingType);
cemuLog_setActiveLoggingFlags(GetConfig().log_flag.GetValue());
g_config.Save();
GetConfigHandle().Save();
}
}
void MainWindow::OnPPCInfoToggle(wxCommandEvent& event)
{
GetConfig().advanced_ppc_logging = !GetConfig().advanced_ppc_logging.GetValue();
g_config.Save();
GetConfigHandle().Save();
}
void MainWindow::OnDebugDumpGeneric(wxCommandEvent& event)
@ -1290,8 +1290,8 @@ wxRect MainWindow::GetDesktopRect()
void MainWindow::LoadSettings()
{
g_config.Load();
const auto& config = GetConfig();
GetConfigHandle().Load();
const auto& config = GetWxGUIConfig();
if(config.check_update)
m_update_available = CemuUpdateWindow::IsUpdateAvailableAsync();
@ -1329,8 +1329,8 @@ void MainWindow::LoadSettings()
void MainWindow::SaveSettings()
{
auto lock = g_config.Lock();
auto& config = GetConfig();
auto lock = GetConfigHandle().Lock();
auto& config = GetWxGUIConfig();
if (config.window_position != Vector2i{ -1,-1 })
{
@ -1369,7 +1369,7 @@ void MainWindow::SaveSettings()
if(m_game_list)
m_game_list->SaveConfig();
g_config.Save();
g_wxConfig.Save();
}
void MainWindow::OnMouseMove(wxMouseEvent& event)
@ -1389,7 +1389,7 @@ void MainWindow::OnMouseMove(wxMouseEvent& event)
if (!IsFullScreen())
return;
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
// if mouse goes to upper screen then show our menu in fullscreen mode
if (config.fullscreen_menubar)
SetMenuVisible(event.GetPosition().y < 50);
@ -1688,7 +1688,7 @@ void MainWindow::OnDebuggerClose(wxCloseEvent& event)
void MainWindow::OnPadClose(wxCloseEvent& event)
{
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
config.pad_open = false;
if (config.pad_position != Vector2i{ -1,-1 })
m_padView->GetPosition(&config.pad_position.x, &config.pad_position.y);
@ -1696,7 +1696,7 @@ void MainWindow::OnPadClose(wxCloseEvent& event)
if (config.pad_size != Vector2i{ -1,-1 })
m_padView->GetSize(&config.pad_size.x, &config.pad_size.y);
g_config.Save();
g_wxConfig.Save();
// already deleted by wxwidget
m_padView = nullptr;
@ -1727,8 +1727,8 @@ void MainWindow::SetFullScreen(bool state)
// only update config entry if we dont't have launch parameters
if (!LaunchSettings::FullscreenEnabled().has_value())
{
GetConfig().fullscreen = state;
g_config.Save();
GetWxGUIConfig().fullscreen = state;
g_wxConfig.Save();
}
if (state && !m_game_launched)
return;
@ -1760,14 +1760,14 @@ void MainWindow::UpdateNFCMenu()
m_nfcMenuSeparator0 = nullptr;
}
// remove recent files list
for (sint32 i = 0; i < CemuConfig::kMaxRecentEntries; i++)
for (sint32 i = 0; i < wxCemuConfig::kMaxRecentEntries; i++)
{
if (m_nfcMenu->FindChildItem(MAINFRAME_MENU_ID_NFC_RECENT_0 + i) == nullptr)
continue;
m_nfcMenu->Remove(MAINFRAME_MENU_ID_NFC_RECENT_0 + i);
}
// add entries
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
sint32 recentFileIndex = 0;
for (size_t i = 0; i < config.recent_nfc_files.size(); i++)
{
@ -2098,7 +2098,7 @@ void MainWindow::RecreateMenu()
m_menuBar = nullptr;
}
auto& config = GetConfig();
auto& guiConfig = GetWxGUIConfig();
m_menuBar = new wxMenuBar();
// file submenu
@ -2112,9 +2112,9 @@ void MainWindow::RecreateMenu()
sint32 recentFileIndex = 0;
m_fileMenuSeparator0 = nullptr;
m_fileMenuSeparator1 = nullptr;
for (size_t i = 0; i < config.recent_launch_files.size(); i++)
for (size_t i = 0; i < guiConfig.recent_launch_files.size(); i++)
{
const std::string& pathStr = config.recent_launch_files[i];
const std::string& pathStr = guiConfig.recent_launch_files[i];
if (pathStr.empty())
continue;
if (recentFileIndex == 0)
@ -2156,6 +2156,8 @@ void MainWindow::RecreateMenu()
++index;
}
auto& config = GetConfig();
auto& wxConfig = GetWxGUIConfig();
// options->console language submenu
wxMenu* optionsConsoleLanguageMenu = new wxMenu();
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH, _("&English"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::EN);
@ -2182,11 +2184,11 @@ void MainWindow::RecreateMenu()
// options submenu
wxMenu* optionsMenu = new wxMenu();
m_fullscreenMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN, _("&Fullscreen"), wxEmptyString);
m_fullscreenMenuItem->Check(ActiveSettings::FullscreenEnabled());
m_fullscreenMenuItem->Check(FullscreenEnabled());
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, _("&Graphic packs"));
m_padViewMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, _("&Separate GamePad view"), wxEmptyString);
m_padViewMenuItem->Check(GetConfig().pad_open);
m_padViewMenuItem->Check(wxConfig.pad_open);
optionsMenu->AppendSeparator();
#if BOOST_OS_MACOS
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS, _("&Settings..." "\tCtrl-,"));
@ -2409,3 +2411,8 @@ void MainWindow::CafeRecreateCanvas()
wxQueueEvent(g_mainFrame, evt);
sem.decrementWithWait();
}
bool MainWindow::FullscreenEnabled() const
{
return LaunchSettings::FullscreenEnabled().value_or(GetWxGUIConfig().fullscreen);
}

View File

@ -145,6 +145,7 @@ public:
static void RequestLaunchGame(fs::path filePath, wxLaunchGameEvent::INITIATED_BY initiatedBy);
private:
bool FullscreenEnabled() const;
void RecreateMenu();
void UpdateChildWindowTitleRunningState();
static wxString GetInitialWindowTitle();

View File

@ -1,6 +1,7 @@
#include "wxgui/components/wxGameList.h"
#include "wxgui/helpers/wxCustomData.h"
#include "wxCemuConfig.h"
#include "util/helpers/helpers.h"
#include "wxgui/GameProfileWindow.h"
@ -137,7 +138,7 @@ bool writeICNS(const fs::path& pngPath, const fs::path& icnsPath) {
wxGameList::wxGameList(wxWindow* parent, wxWindowID id)
: wxListView(parent, id, wxDefaultPosition, wxDefaultSize, GetStyleFlags(Style::kList)), m_style(Style::kList)
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0);
if(config.show_icon_column)
@ -221,7 +222,7 @@ wxGameList::~wxGameList()
void wxGameList::LoadConfig()
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
SetStyle((Style)config.game_list_style, false);
if (!config.game_list_column_order.empty())
@ -327,7 +328,7 @@ int wxGameList::GetColumnDefaultWidth(int column)
void wxGameList::SaveConfig(bool flush)
{
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
config.game_list_style = (int)m_style;
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
@ -335,7 +336,7 @@ void wxGameList::SaveConfig(bool flush)
#endif
if (flush)
g_config.Save();
GetConfigHandle().Save();
}
bool wxGameList::IsVisible(long item) const
@ -426,8 +427,8 @@ void wxGameList::SetStyle(Style style, bool save)
if(save)
{
GetConfig().game_list_style = (int)m_style;
g_config.Save();
GetWxGUIConfig().game_list_style = (int)m_style;
GetConfigHandle().Save();
}
if (style == Style::kList)
@ -726,7 +727,7 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
const auto custom_name = dialog.GetValue();
GetConfig().SetGameListCustomName(title_id, custom_name.utf8_string());
m_name_cache.clear();
g_config.Save();
GetConfigHandle().Save();
// update list entry
for (int i = 0; i < GetItemCount(); ++i)
{
@ -906,7 +907,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
const auto menu = dynamic_cast<wxMenu*>(event.GetEventObject());
const int column = dynamic_cast<wxCustomData<int>*>(menu->GetClientObject())->GetData();
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
switch (event.GetId())
{
@ -980,7 +981,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
}
}
g_config.Save();
GetConfigHandle().Save();
ApplyGameListColumnWidths();
});
@ -990,7 +991,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
void wxGameList::ApplyGameListColumnWidths()
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
wxWindowUpdateLocker lock(this);
if(config.show_icon_column)
SetColumnWidth(ColumnIcon, kListIconWidth);
@ -1044,7 +1045,7 @@ void wxGameList::OnColumnResize(wxListEvent& event)
const int column = event.GetColumn();
const int width = GetColumnWidth(column);
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
switch (column)
{
case ColumnName:
@ -1069,7 +1070,7 @@ void wxGameList::OnColumnResize(wxListEvent& event)
break;
}
g_config.Save();
GetConfigHandle().Save();
AdjustLastColumnWidth();
}

View File

@ -42,7 +42,7 @@ struct DebuggerConfig
void Load(XMLConfigParser& parser);
void Save(XMLConfigParser& parser);
};
typedef XMLDataConfig<DebuggerConfig, &DebuggerConfig::Load, &DebuggerConfig::Save> XMLDebuggerConfig;
typedef XMLDataConfig<DebuggerConfig> XMLDebuggerConfig;
struct DebuggerModuleStorage
{
@ -54,7 +54,7 @@ struct DebuggerModuleStorage
void Load(XMLConfigParser& parser);
void Save(XMLConfigParser& parser);
};
typedef XMLDataConfig<DebuggerModuleStorage, &DebuggerModuleStorage::Load, &DebuggerModuleStorage::Save> XMLDebuggerModuleConfig;
typedef XMLDataConfig<DebuggerModuleStorage> XMLDebuggerModuleConfig;
class DebuggerWindow2 : public wxFrame, public DebuggerCallbacks
{

View File

@ -81,7 +81,7 @@ std::optional<std::string> SaveScreenshot(std::vector<uint8> data, int width, in
// to make this work we need to call OleInitialize() on the same thread
OleInitialize(nullptr);
#endif
bool save_screenshot = g_config.data().save_screenshot;
bool save_screenshot = GetWxGUIConfig().save_screenshot;
wxImage image(width, height, data.data(), true);
if (mainWindow)
{
@ -174,7 +174,7 @@ HotkeySettings::~HotkeySettings()
m_controllerTimer->Stop();
if (m_needToSave)
{
g_config.Save();
GetConfigHandle().Save();
}
}

View File

@ -1,7 +1,7 @@
#pragma once
#include <wx/wx.h>
#include "config/CemuConfig.h"
#include "wxCemuConfig.h"
#include "input/api/Controller.h"
class HotkeyEntry;
@ -22,7 +22,7 @@ private:
static const std::unordered_map<sHotkeyCfg*, std::function<void(void)>> s_cfgHotkeyToFuncMap;
inline static std::unordered_map<uint16, std::function<void(void)>> s_keyboardHotkeyToFuncMap{};
inline static std::unordered_map<uint16, std::function<void(void)>> s_controllerHotkeyToFuncMap{};
inline static auto& s_cfgHotkeys = GetConfig().hotkeys;
inline static auto& s_cfgHotkeys = GetWxGUIConfig().hotkeys;
wxPanel* m_panel;
wxFlexGridSizer* m_sizer;

View File

@ -0,0 +1,184 @@
#include "wxCemuConfig.h"
#include "Common/precompiled.h"
#include "config/CemuConfig.h"
#include "config/XMLConfig.h"
#include "util/helpers/helpers.h"
#include <wx/language.h>
XMLWxCemuConfig_t g_wxConfig(&GetConfigHandle);
void wxCemuConfig::AddRecentlyLaunchedFile(std::string_view file)
{
recent_launch_files.insert(recent_launch_files.begin(), std::string(file));
RemoveDuplicatesKeepOrder(recent_launch_files);
while (recent_launch_files.size() > kMaxRecentEntries)
recent_launch_files.pop_back();
}
void wxCemuConfig::AddRecentNfcFile(std::string_view file)
{
recent_nfc_files.insert(recent_nfc_files.begin(), std::string(file));
RemoveDuplicatesKeepOrder(recent_nfc_files);
while (recent_nfc_files.size() > kMaxRecentEntries)
recent_nfc_files.pop_back();
}
void wxCemuConfig::Load(XMLConfigParser& parser)
{
language = parser.get<sint32>("language", wxLANGUAGE_DEFAULT);
use_discord_presence = parser.get("use_discord_presence", true);
fullscreen_menubar = parser.get("fullscreen_menubar", false);
feral_gamemode = parser.get("feral_gamemode", false);
check_update = parser.get("check_update", check_update);
receive_untested_updates = parser.get("receive_untested_updates", receive_untested_updates);
save_screenshot = parser.get("save_screenshot", save_screenshot);
did_show_vulkan_warning = parser.get("vk_warning", did_show_vulkan_warning);
did_show_graphic_pack_download = parser.get("gp_download", did_show_graphic_pack_download);
did_show_macos_disclaimer = parser.get("macos_disclaimer", did_show_macos_disclaimer);
fullscreen = parser.get("fullscreen", fullscreen);
window_position.x = parser.get("window_position").get("x", -1);
window_position.y = parser.get("window_position").get("y", -1);
window_size.x = parser.get("window_size").get("x", -1);
window_size.y = parser.get("window_size").get("y", -1);
window_maximized = parser.get("window_maximized", false);
pad_open = parser.get("open_pad", false);
pad_position.x = parser.get("pad_position").get("x", -1);
pad_position.y = parser.get("pad_position").get("y", -1);
pad_size.x = parser.get("pad_size").get("x", -1);
pad_size.y = parser.get("pad_size").get("y", -1);
pad_maximized = parser.get("pad_maximized", false);
auto gamelist = parser.get("GameList");
game_list_style = gamelist.get("style", 0);
game_list_column_order = gamelist.get("order", "");
show_icon_column = parser.get("show_icon_column", true);
// return default width if value in config file out of range
auto loadColumnSize = [&gamelist](const char* name, uint32 defaultWidth) {
sint64 val = gamelist.get(name, DefaultColumnSize::name);
if (val < 0 || val > (sint64)std::numeric_limits<uint32>::max)
return defaultWidth;
return static_cast<uint32>(val);
};
column_width.name = loadColumnSize("name_width", DefaultColumnSize::name);
column_width.version = loadColumnSize("version_width", DefaultColumnSize::version);
column_width.dlc = loadColumnSize("dlc_width", DefaultColumnSize::dlc);
column_width.game_time = loadColumnSize("game_time_width", DefaultColumnSize::game_time);
column_width.game_started = loadColumnSize("game_started_width", DefaultColumnSize::game_started);
column_width.region = loadColumnSize("region_width", DefaultColumnSize::region);
column_width.title_id = loadColumnSize("title_id", DefaultColumnSize::title_id);
recent_launch_files.clear();
auto launch_parser = parser.get("RecentLaunchFiles");
for (auto element = launch_parser.get("Entry"); element.valid(); element = launch_parser.get("Entry", element))
{
const std::string path = element.value("");
if (path.empty())
continue;
try
{
recent_launch_files.emplace_back(path);
} catch (const std::exception&)
{
cemuLog_log(LogType::Force, "config load error: can't load recently launched game file: {}", path);
}
}
recent_nfc_files.clear();
auto nfc_parser = parser.get("RecentNFCFiles");
for (auto element = nfc_parser.get("Entry"); element.valid(); element = nfc_parser.get("Entry", element))
{
const std::string path = element.value("");
if (path.empty())
continue;
try
{
recent_nfc_files.emplace_back(path);
} catch (const std::exception&)
{
cemuLog_log(LogType::Force, "config load error: can't load recently launched nfc file: {}", path);
}
}
// hotkeys
auto xml_hotkeys = parser.get("Hotkeys");
hotkeys.modifiers = xml_hotkeys.get("modifiers", sHotkeyCfg{});
hotkeys.exitFullscreen = xml_hotkeys.get("ExitFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_ESCAPE}});
hotkeys.toggleFullscreen = xml_hotkeys.get("ToggleFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_F11}});
hotkeys.toggleFullscreenAlt = xml_hotkeys.get("ToggleFullscreenAlt", sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}); // ALT+ENTER
hotkeys.takeScreenshot = xml_hotkeys.get("TakeScreenshot", sHotkeyCfg{uKeyboardHotkey{WXK_F12}});
hotkeys.toggleFastForward = xml_hotkeys.get("ToggleFastForward", sHotkeyCfg{});
}
void wxCemuConfig::Save(XMLConfigParser& config)
{
// general settings
config.set<sint32>("language", language);
config.set<bool>("use_discord_presence", use_discord_presence);
config.set<bool>("fullscreen_menubar", fullscreen_menubar);
config.set<bool>("feral_gamemode", feral_gamemode);
config.set<bool>("check_update", check_update);
config.set<bool>("receive_untested_updates", receive_untested_updates);
config.set<bool>("save_screenshot", save_screenshot);
config.set<bool>("vk_warning", did_show_vulkan_warning);
config.set<bool>("gp_download", did_show_graphic_pack_download);
config.set<bool>("macos_disclaimer", did_show_macos_disclaimer);
config.set<bool>("fullscreen", fullscreen);
auto wpos = config.set("window_position");
wpos.set<sint32>("x", window_position.x);
wpos.set<sint32>("y", window_position.y);
auto wsize = config.set("window_size");
wsize.set<sint32>("x", window_size.x);
cemu_assert_debug(window_size.x != 0);
wsize.set<sint32>("y", window_size.y);
config.set<bool>("window_maximized", window_maximized);
config.set<bool>("open_pad", pad_open);
auto ppos = config.set("pad_position");
ppos.set<sint32>("x", pad_position.x);
ppos.set<sint32>("y", pad_position.y);
auto psize = config.set("pad_size");
psize.set<sint32>("x", pad_size.x);
psize.set<sint32>("y", pad_size.y);
config.set<bool>("pad_maximized", pad_maximized);
config.set<bool>("show_icon_column", show_icon_column);
auto gamelist = config.set("GameList");
gamelist.set("style", game_list_style);
gamelist.set("order", game_list_column_order);
gamelist.set("name_width", column_width.name);
gamelist.set("version_width", column_width.version);
gamelist.set("dlc_width", column_width.dlc);
gamelist.set("game_time_width", column_width.game_time);
gamelist.set("game_started_width", column_width.game_started);
gamelist.set("region_width", column_width.region);
gamelist.set("title_id", column_width.title_id);
auto launch_files_parser = config.set("RecentLaunchFiles");
for (const auto& entry : recent_launch_files)
{
launch_files_parser.set("Entry", entry.c_str());
}
auto nfc_files_parser = config.set("RecentNFCFiles");
for (const auto& entry : recent_nfc_files)
{
nfc_files_parser.set("Entry", entry.c_str());
}
// hotkeys
auto xml_hotkeys = config.set("Hotkeys");
xml_hotkeys.set("modifiers", hotkeys.modifiers);
xml_hotkeys.set("ExitFullscreen", hotkeys.exitFullscreen);
xml_hotkeys.set("ToggleFullscreen", hotkeys.toggleFullscreen);
xml_hotkeys.set("ToggleFullscreenAlt", hotkeys.toggleFullscreenAlt);
xml_hotkeys.set("TakeScreenshot", hotkeys.takeScreenshot);
xml_hotkeys.set("ToggleFastForward", hotkeys.toggleFastForward);
}

View File

@ -0,0 +1,142 @@
#pragma once
#include "config/CemuConfig.h"
#include "config/XMLConfig.h"
#include "util/math/vector2.h"
#include "wxgui.h"
namespace DefaultColumnSize
{
enum : uint32
{
name = 500u,
version = 60u,
dlc = 50u,
game_time = 140u,
game_started = 160u,
region = 80u,
title_id = 160u
};
};
typedef union
{
struct
{
uint16 key : 13; // enough bits for all keycodes
uint16 alt : 1;
uint16 ctrl : 1;
uint16 shift : 1;
};
uint16 raw;
} uKeyboardHotkey;
typedef sint16 ControllerHotkey_t;
struct sHotkeyCfg
{
static constexpr uint8 keyboardNone{WXK_NONE};
static constexpr sint8 controllerNone{-1}; // no enums to work with, but buttons start from 0
uKeyboardHotkey keyboard{keyboardNone};
ControllerHotkey_t controller{controllerNone};
/* for defaults */
sHotkeyCfg(const uKeyboardHotkey& keyboard = {keyboardNone}, const ControllerHotkey_t& controller = {controllerNone}) : keyboard(keyboard), controller(controller) {};
/* for reading from xml */
sHotkeyCfg(const char* xml_values)
{
std::istringstream iss(xml_values);
iss >> keyboard.raw >> controller;
}
};
template<>
struct fmt::formatter<sHotkeyCfg> : formatter<string_view>
{
template<typename FormatContext>
auto format(const sHotkeyCfg c, FormatContext& ctx) const
{
std::string xml_values = fmt::format("{} {}", c.keyboard.raw, c.controller);
return formatter<string_view>::format(xml_values, ctx);
}
};
struct wxCemuConfig
{
ConfigValue<sint32> language{wxLANGUAGE_DEFAULT};
ConfigValue<bool> use_discord_presence{true};
ConfigValue<bool> fullscreen{ false };
ConfigValue<bool> fullscreen_menubar{false};
ConfigValue<bool> feral_gamemode{false};
// max 15 entries
static constexpr size_t kMaxRecentEntries = 15;
std::vector<std::string> recent_launch_files;
std::vector<std::string> recent_nfc_files;
Vector2i window_position{-1, -1};
Vector2i window_size{-1, -1};
ConfigValue<bool> window_maximized;
ConfigValue<bool> pad_open;
Vector2i pad_position{-1, -1};
Vector2i pad_size{-1, -1};
ConfigValue<bool> pad_maximized;
ConfigValue<bool> check_update{true};
ConfigValue<bool> receive_untested_updates{false};
ConfigValue<bool> save_screenshot{true};
ConfigValue<bool> did_show_vulkan_warning{false};
ConfigValue<bool> did_show_graphic_pack_download{false}; // no longer used but we keep the config value around in case people downgrade Cemu. Despite the name this was used for the Getting Started dialog
ConfigValue<bool> did_show_macos_disclaimer{false};
ConfigValue<bool> show_icon_column{true};
int game_list_style = 0;
std::string game_list_column_order;
struct
{
uint32 name = DefaultColumnSize::name;
uint32 version = DefaultColumnSize::version;
uint32 dlc = DefaultColumnSize::dlc;
uint32 game_time = DefaultColumnSize::game_time;
uint32 game_started = DefaultColumnSize::game_started;
uint32 region = DefaultColumnSize::region;
uint32 title_id = 0;
} column_width{};
// hotkeys
struct
{
sHotkeyCfg modifiers;
sHotkeyCfg toggleFullscreen;
sHotkeyCfg toggleFullscreenAlt;
sHotkeyCfg exitFullscreen;
sHotkeyCfg takeScreenshot;
sHotkeyCfg toggleFastForward;
} hotkeys{};
void AddRecentlyLaunchedFile(std::string_view file);
void AddRecentNfcFile(std::string_view file);
void Load(XMLConfigParser& parser);
void Save(XMLConfigParser& parser);
};
typedef XMLChildConfig<wxCemuConfig, &wxCemuConfig::Load, &wxCemuConfig::Save> XMLWxCemuConfig_t;
extern XMLWxCemuConfig_t g_wxConfig;
inline XMLWxCemuConfig_t& GetWxGuiConfigHandle()
{
return g_wxConfig;
}
inline wxCemuConfig& GetWxGUIConfig()
{
return GetWxGuiConfigHandle().Data();
}

View File

@ -343,23 +343,6 @@ void WindowSystem::captureInput(const ControllerState& currentState, const Contr
HotkeySettings::CaptureInput(currentState, lastState);
}
sHotkeyCfg WindowSystem::getDefaultHotkeyConfig(HotKey hotKey)
{
switch (hotKey)
{
case HotKey::EXIT_FULLSCREEN:
return sHotkeyCfg{uKeyboardHotkey{WXK_ESCAPE}};
case HotKey::TOGGLE_FULLSCREEN:
return sHotkeyCfg{uKeyboardHotkey{WXK_F11}};
case HotKey::TOGGLE_FULLSCREEN_ALT:
return sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}; // ALT+ENTER
case HotKey::TAKE_SCREENSHOT:
return sHotkeyCfg{uKeyboardHotkey{WXK_F12}};
default:
return sHotkeyCfg{};
}
}
bool WindowSystem::isFullScreen()
{
return g_window_info.is_fullscreen;

View File

@ -120,7 +120,7 @@ void CemuCommonInit()
WindowsInitCwd();
ExceptionHandler_Init();
// read config
g_config.Load();
GetConfigHandle().Load();
if (NetworkConfig::XMLExists())
n_config.Load();
// parallelize expensive init code