diff --git a/GlosSIConfig/Resource.rc b/GlosSIConfig/Resource.rc index cc7ca13..2d28795 100644 --- a/GlosSIConfig/Resource.rc +++ b/GlosSIConfig/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,2,0018002705604 - PRODUCTVERSION 0,1,2,0018002705604 + FILEVERSION 0,1,2,0030000050130 + PRODUCTVERSION 0,1,2,0030000050130 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - Config" - VALUE "FileVersion", "0.1.2.0-18-g27056b4" + VALUE "FileVersion", "0.1.2.0-30-geb5f13f" VALUE "InternalName", "GlosSIConfig" VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSIConfig.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.1.2.0-18-g27056b4" + VALUE "ProductVersion", "0.1.2.0-30-geb5f13f" END END BLOCK "VarFileInfo" diff --git a/GlosSIConfig/UIModel.cpp b/GlosSIConfig/UIModel.cpp index 62c86aa..7fd66ba 100644 --- a/GlosSIConfig/UIModel.cpp +++ b/GlosSIConfig/UIModel.cpp @@ -398,8 +398,8 @@ QVariantMap UIModel::getDefaultConf() const QJsonValue::fromVariant(QString::fromStdWString(getSteamPath(false).wstring()))}, {"steamUserId", QJsonValue::fromVariant(QString::fromStdWString(getSteamUserId(false)))}, - {"standaloneModeGameId", ""}, - {"standaloneUseGamepadUI", false}, + {"globalModeGameId", ""}, + {"globalModeUseGamepadUI", false}, {"controller", QJsonObject{{"maxControllers", 1}, {"emulateDS4", false}, {"allowDesktopConfig", false}}}, {"devices", QJsonObject{ @@ -474,36 +474,36 @@ void UIModel::saveDefaultConf(QVariantMap conf) const file.close(); } -Q_INVOKABLE QVariant UIModel::standaloneShortcutConf() { +Q_INVOKABLE QVariant UIModel::globalModeShortcutConf() { for (auto& target : targets_) { const auto map = target.toMap(); - if (map["name"] == "GlosSI Standalone/Desktop") { + if (map["name"] == "GlosSI GlobalMode/Desktop") { return target; } } return QVariant(); } -Q_INVOKABLE bool UIModel::standaloneModeShortcutExists() { - const auto map = standaloneShortcutConf().toMap(); - if (map["name"] == "GlosSI Standalone/Desktop") { +Q_INVOKABLE bool UIModel::globalModeShortcutExists() { + const auto map = globalModeShortcutConf().toMap(); + if (map["name"] == "GlosSI GlobalMode/Desktop") { return true; } return false; } -Q_INVOKABLE uint32_t UIModel::standaloneModeShortcutAppId() { - if (!standaloneModeShortcutExists()) { +Q_INVOKABLE uint32_t UIModel::globalModeShortcutAppId() { + if (!globalModeShortcutExists()) { return 0; } - return getAppId(standaloneShortcutConf()); + return getAppId(globalModeShortcutConf()); } -Q_INVOKABLE QString UIModel::standaloneModeShortcutGameId() { - if (!standaloneModeShortcutExists()) { +Q_INVOKABLE QString UIModel::globalModeShortcutGameId() { + if (!globalModeShortcutExists()) { return ""; } - return getGameId(standaloneShortcutConf()); + return getGameId(globalModeShortcutConf()); } #ifdef _WIN32 diff --git a/GlosSIConfig/UIModel.h b/GlosSIConfig/UIModel.h index 10cdb3a..05ddf35 100644 --- a/GlosSIConfig/UIModel.h +++ b/GlosSIConfig/UIModel.h @@ -64,10 +64,10 @@ class UIModel : public QObject { Q_INVOKABLE QVariantMap getDefaultConf() const; Q_INVOKABLE void saveDefaultConf(QVariantMap conf) const; - Q_INVOKABLE QVariant standaloneShortcutConf(); - Q_INVOKABLE bool standaloneModeShortcutExists(); - Q_INVOKABLE uint32_t standaloneModeShortcutAppId(); - Q_INVOKABLE QString standaloneModeShortcutGameId(); + Q_INVOKABLE QVariant globalModeShortcutConf(); + Q_INVOKABLE bool globalModeShortcutExists(); + Q_INVOKABLE uint32_t globalModeShortcutAppId(); + Q_INVOKABLE QString globalModeShortcutGameId(); #ifdef _WIN32 Q_INVOKABLE QVariantList uwpApps(); diff --git a/GlosSIConfig/qml/GlobalConf.qml b/GlosSIConfig/qml/GlobalConf.qml index 4cda0e7..a2c39b1 100644 --- a/GlosSIConfig/qml/GlobalConf.qml +++ b/GlosSIConfig/qml/GlobalConf.qml @@ -140,10 +140,10 @@ Item { Row { Row { CheckBox { - id: standaloneUseGamepadUI - text: qsTr("Use BPM for standalone-/desktop-mode") - checked: config.standaloneUseGamepadUI - onCheckedChanged: config.standaloneUseGamepadUI = checked + id: globalModeUseGamepadUI + text: qsTr("Use BPM for global-/desktop-mode") + checked: config.globalModeUseGamepadUI + onCheckedChanged: config.globalModeUseGamepadUI = checked } } } @@ -153,44 +153,44 @@ Item { spacing: 16 Label { topPadding: 8 - id: standAloneGameIdLabel - text: qsTr("StandaloneGameId") + id: GlobalModeGameIdLabel + text: qsTr("GlobalMode GameId") } FluentTextInput { width: 128 - id: standAloneGameId + id: GlobalModeGameId enabled: false - text: config.standaloneModeGameId - onTextChanged: config.standaloneModeGameId = text + text: config.globalModeGameId + onTextChanged: config.globalModeGameId = text } Button { - id: standAloneGameIdButton - text: qsTr("Create standalone-/desktop-mode shortcut") + id: GlobalModeGameIdButton + text: qsTr("Create global-/desktop-mode shortcut") onClicked: { - const standaloneConf = uiModel.getDefaultConf(); - standaloneConf.name = "GlosSI Standalone/Desktop"; - standaloneConf.launch.launch = false; - uiModel.addTarget(standaloneConf); - if (uiModel.addToSteam(standaloneConf, "")) { + const globalModeConf = uiModel.getDefaultConf(); + globalModeConf.name = "GlosSI GlobalMode/Desktop"; + globalModeConf.launch.launch = false; + uiModel.addTarget(globalModeConf); + if (uiModel.addToSteam(globalModeConf, "")) { steamChangedDialog.open(); } - const standaloneGID = uiModel.standaloneModeShortcutGameId(); - standAloneGameId.text = standaloneGID; + const globalModeGID = uiModel.globalModeShortcutGameId(); + GlobalModeGameId.text = globalModeGID; setTimeout(() => { uiModel.saveDefaultConf(config); done(); }, 10); } highlighted: true - visible: !uiModel.standaloneModeShortcutExists() + visible: !uiModel.globalModeShortcutExists() } Button { - id: standAloneGameIdConfigButton - text: qsTr("Open standalone-/desktop-mode controller config") + id: GlobalModeGameIdConfigButton + text: qsTr("Open global-/desktop-mode controller config") onClicked: { - Qt.openUrlExternally("steam://currentcontrollerconfig/" + uiModel.standaloneModeShortcutAppId() + "/"); + Qt.openUrlExternally("steam://currentcontrollerconfig/" + uiModel.globalModeShortcutAppId() + "/"); } - visible: uiModel.standaloneModeShortcutExists() + visible: uiModel.globalModeShortcutExists() } } } diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp index c52ec56..a008366 100644 --- a/GlosSITarget/SteamTarget.cpp +++ b/GlosSITarget/SteamTarget.cpp @@ -215,25 +215,25 @@ void SteamTarget::focusWindow(WindowHandle hndl) void SteamTarget::init_FuckingRenameMe() { if (!SteamOverlayDetector::IsSteamInjected()) { - if (Settings::common.allowStandAlone) { + if (Settings::common.allowGlobalMode) { spdlog::warn("GlosSI not launched via Steam.\nEnabling EXPERIMENTAL global controller and overlay..."); - if (Settings::common.standaloneModeGameId == L"") { - spdlog::error("No game id set for standalone mode. Controller will use desktop-config!"); + if (Settings::common.globalModeGameId == L"") { + spdlog::error("No game id set for global mode. Controller will use desktop-config!"); } SetEnvironmentVariable(L"SteamAppId", L"0"); SetEnvironmentVariable(L"SteamClientLaunch", L"0"); SetEnvironmentVariable(L"SteamEnv", L"1"); SetEnvironmentVariable(L"SteamPath", steam_path_.wstring().c_str()); - SetEnvironmentVariable(L"SteamTenfoot", Settings::common.standaloneUseGamepadUI ? L"1" : L"0"); + SetEnvironmentVariable(L"SteamTenfoot", Settings::common.globalModeUseGamepadUI ? L"1" : L"0"); // SetEnvironmentVariable(L"SteamTenfootHybrid", L"1"); - SetEnvironmentVariable(L"SteamGamepadUI", Settings::common.standaloneUseGamepadUI ? L"1" : L"0"); - SetEnvironmentVariable(L"SteamGameId", Settings::common.standaloneModeGameId.c_str()); - SetEnvironmentVariable(L"SteamOverlayGameId", Settings::common.standaloneModeGameId.c_str()); + SetEnvironmentVariable(L"SteamGamepadUI", Settings::common.globalModeUseGamepadUI ? L"1" : L"0"); + SetEnvironmentVariable(L"SteamGameId", Settings::common.globalModeGameId.c_str()); + SetEnvironmentVariable(L"SteamOverlayGameId", Settings::common.globalModeGameId.c_str()); SetEnvironmentVariable(L"EnableConfiguratorSupport", L"15"); SetEnvironmentVariable(L"SteamStreamingForceWindowedD3D9", L"1"); - if (Settings::common.standaloneUseGamepadUI) { + if (Settings::common.globalModeUseGamepadUI) { system("start steam://open/bigpicture"); auto steamwindow = FindWindow(L"Steam Big Picture Mode", nullptr); auto timer = sf::Clock{}; diff --git a/Installer/Installer.nsi b/Installer/Installer.nsi index 0d9a1dc..a27ec7f 100644 --- a/Installer/Installer.nsi +++ b/Installer/Installer.nsi @@ -3,7 +3,7 @@ !define APP_NAME "GlosSI" !define COMP_NAME "Peter Repukat - Flatspotsoftware" !define WEB_SITE "https://glossi.flatspot.pictures/" -!define VERSION "0.1.2.0-18-g27056b4" +!define VERSION "0.1.2.0-31-gd2b43ff" !define COPYRIGHT "Peter Repukat - FlatspotSoftware © 2017-2022" !define DESCRIPTION "SteamInput compatibility tool" !define INSTALLER_NAME "GlosSI-Installer.exe" diff --git a/common/Settings.h b/common/Settings.h index 83dcc1d..ece94ac 100644 --- a/common/Settings.h +++ b/common/Settings.h @@ -31,285 +31,331 @@ limitations under the License. #include "../common/nlohmann_json_wstring.h" #include "../common/util.h" - -namespace Settings { - - inline struct Launch { - bool launch = false; - std::wstring launchPath; - std::wstring launchAppArgs; - bool closeOnExit = true; - bool waitForChildProcs = true; - bool isUWP = false; - bool ignoreLauncher = true; - bool killLauncher = false; - std::vector launcherProcesses{}; - } launch; - - inline struct Devices { - bool hideDevices = true; - bool realDeviceIds = false; - } devices; - - inline struct Window { - bool windowMode = false; - int maxFps = 0; - float scale = 0.f; - bool disableOverlay = false; - bool hideAltTab = true; - bool disableGlosSIOverlay = false; - } window; - - inline struct Controller { - int maxControllers = 1; - bool allowDesktopConfig = false; - bool emulateDS4 = false; - } controller; - - inline struct Common { - bool no_uwp_overlay = false; - bool disable_watchdog = false; - bool extendedLogging = false; - std::wstring name; - std::wstring icon; - int version; - std::wstring steamPath; - std::wstring steamUserId; - std::wstring standaloneModeGameId; /* = L"12605636929694728192"; */ - bool standaloneUseGamepadUI = false; - bool allowStandAlone = true; - } common; - - inline const std::map> cmd_args = { - {L"-disableuwpoverlay", [&]() { common.no_uwp_overlay = true; }}, - {L"-disablewatchdog", [&]() { common.disable_watchdog = true; }}, - {L"-ignorelauncher", [&]() { launch.ignoreLauncher = true; }}, - {L"-window", [&]() { window.windowMode = true; }}, - {L"-extendedLogging", [&]() { common.extendedLogging = true; }}, - {L"-standaloneUseGamepadUI", [&]() { common.standaloneUseGamepadUI = true; }}, - {L"-disallowStandAlone", [&]() { common.allowStandAlone = false; }}, - }; - - inline std::filesystem::path settings_path_ = ""; - - inline bool checkIsUwp(const std::wstring& launch_path) - { - if (launch_path.find(L"://") != std::wstring::npos) { - return false; - } - std::wsmatch m; - if (!std::regex_search(launch_path, m, std::wregex(L"^.{1,5}:"))) { - return true; - } - return false; - } +namespace Settings +{ + + inline struct Launch + { + bool launch = false; + std::wstring launchPath; + std::wstring launchAppArgs; + bool closeOnExit = true; + bool waitForChildProcs = true; + bool isUWP = false; + bool ignoreLauncher = true; + bool killLauncher = false; + std::vector launcherProcesses{}; + } launch; + + inline struct Devices + { + bool hideDevices = true; + bool realDeviceIds = false; + } devices; + + inline struct Window + { + bool windowMode = false; + int maxFps = 0; + float scale = 0.f; + bool disableOverlay = false; + bool hideAltTab = true; + bool disableGlosSIOverlay = false; + } window; + + inline struct Controller + { + int maxControllers = 1; + bool allowDesktopConfig = false; + bool emulateDS4 = false; + } controller; + + inline struct Common + { + bool no_uwp_overlay = false; + bool disable_watchdog = false; + bool extendedLogging = false; + std::wstring name; + std::wstring icon; + int version; + std::wstring steamPath; + std::wstring steamUserId; + std::wstring globalModeGameId; /* = L"12605636929694728192"; */ + bool globalModeUseGamepadUI = false; + bool allowGlobalMode = true; + } common; + + inline const std::map> cmd_args = { + {L"-disableuwpoverlay", [&]() + { common.no_uwp_overlay = true; }}, + {L"-disablewatchdog", [&]() + { common.disable_watchdog = true; }}, + {L"-ignorelauncher", [&]() + { launch.ignoreLauncher = true; }}, + {L"-window", [&]() + { window.windowMode = true; }}, + {L"-extendedLogging", [&]() + { common.extendedLogging = true; }}, + {L"-globalModeUseGamepadUI", [&]() + { common.globalModeUseGamepadUI = true; }}, + {L"-disallowGlobalMode", [&]() + { common.allowGlobalMode = false; }}, + }; + + inline std::filesystem::path settings_path_ = ""; + + inline bool checkIsUwp(const std::wstring &launch_path) + { + if (launch_path.find(L"://") != std::wstring::npos) + { + return false; + } + std::wsmatch m; + if (!std::regex_search(launch_path, m, std::wregex(L"^.{1,5}:"))) + { + return true; + } + return false; + } #ifdef WIN32 - inline bool isWin10 = false; - - inline void checkWinVer() - { - auto VN = util::win::GetRealOSVersion(); - isWin10 = VN.dwBuildNumber < 22000; - - if (isWin10) { - spdlog::info("Running on Windows 10; Winver: {}.{}.{}", VN.dwMajorVersion, VN.dwMinorVersion, VN.dwBuildNumber); - } - else { - spdlog::info("Running on Windows 11; Winver: {}.{}.{}", VN.dwMajorVersion, VN.dwMinorVersion, VN.dwBuildNumber); - } - } + inline bool isWin10 = false; + + inline void checkWinVer() + { + auto VN = util::win::GetRealOSVersion(); + isWin10 = VN.dwBuildNumber < 22000; + + if (isWin10) + { + spdlog::info("Running on Windows 10; Winver: {}.{}.{}", VN.dwMajorVersion, VN.dwMinorVersion, VN.dwBuildNumber); + } + else + { + spdlog::info("Running on Windows 11; Winver: {}.{}.{}", VN.dwMajorVersion, VN.dwMinorVersion, VN.dwBuildNumber); + } + } #endif - inline void Parse(const nlohmann::basic_json<>& json) - { - constexpr auto safeParseValue = [](const auto & object, const auto & key, T & value) { - try { - if (object.is_null() || object.empty() || object.at(key).empty() || object.at(key).is_null()) { - return; - } - if constexpr (std::is_same_v) { - value = util::string::to_wstring(object[key].get()); - } - else { - value = object[key]; - } - } - catch (const nlohmann::json::exception& e) { - e.id == 403 - ? spdlog::trace("Err parsing \"{}\"; {}", key, e.what()) - : spdlog::warn("Err parsing \"{}\"; {}", key, e.what()); - - } - catch (const std::exception& e) { - spdlog::warn("Err parsing \"{}\"; {}", key, e.what()); - } - }; - - int version; - safeParseValue(json, "version", version); - if (version != 1) { // TODO: versioning stuff - spdlog::warn("Config version doesn't match application version."); - } - - // TODO: make this as much generic as fits in about the same amount of code if one would parse every value separately. - try { - if (const auto launchconf = json["launch"]; !launchconf.is_null() && !launchconf.empty() && launchconf.is_object()) { - safeParseValue(launchconf, "launch", launch.launch); - safeParseValue(launchconf, "launchPath", launch.launchPath); - safeParseValue(launchconf, "launchAppArgs", launch.launchAppArgs); - safeParseValue(launchconf, "closeOnExit", launch.closeOnExit); - safeParseValue(launchconf, "waitForChildProcs", launch.waitForChildProcs); - safeParseValue(launchconf, "killLauncher", launch.killLauncher); - safeParseValue(launchconf, "ignoreLauncher", launch.ignoreLauncher); - - if (launchconf.contains("launcherProcesses") && launchconf["launcherProcesses"].is_array()) { - if (const auto launcherProcs = launchconf["launcherProcesses"]; - !launcherProcs.is_null() && !launcherProcs.empty() && launcherProcs.is_array()) { - launch.launcherProcesses.clear(); - launch.launcherProcesses.reserve(launcherProcs.size()); - for (auto& proc : launcherProcs) { - launch.launcherProcesses.push_back(util::string::to_wstring(proc)); - } - } - } - } - - if (const auto devconf = json["devices"]; !devconf.is_null() && !devconf.empty() && devconf.is_object()) { - safeParseValue(devconf, "hideDevices", devices.hideDevices); - safeParseValue(devconf, "realDeviceIds", devices.realDeviceIds); - } - - if (const auto winconf = json["window"]; !winconf.is_null() && !winconf.empty() && winconf.is_object()) { - safeParseValue(winconf, "windowMode", window.windowMode); - safeParseValue(winconf, "maxFps", window.maxFps); - safeParseValue(winconf, "scale", window.scale); - safeParseValue(winconf, "disableOverlay", window.disableOverlay); - safeParseValue(winconf, "hideAltTab", window.hideAltTab); - safeParseValue(winconf, "disableGlosSIOverlay", window.disableGlosSIOverlay); - } - - if (const auto controllerConf = json["controller"]; !controllerConf.is_null() && !controllerConf.empty() && controllerConf.is_object()) { - safeParseValue(controllerConf, "maxControllers", controller.maxControllers); - safeParseValue(controllerConf, "allowDesktopConfig", controller.allowDesktopConfig); - safeParseValue(controllerConf, "emulateDS4", controller.emulateDS4); - } - safeParseValue(json, "extendedLogging", common.extendedLogging); - safeParseValue(json, "name", common.name); - safeParseValue(json, "icon", common.icon); - safeParseValue(json, "version", common.version); - - safeParseValue(json, "steamPath", common.steamPath); - safeParseValue(json, "steamUserId", common.steamUserId); - - safeParseValue(json, "standaloneModeGameId", common.standaloneModeGameId); - safeParseValue(json, "standaloneUseGamepadUI", common.standaloneUseGamepadUI); - } - catch (const nlohmann::json::exception& e) { - spdlog::warn("Err parsing config: {}", e.what()); - } - catch (const std::exception& e) { - spdlog::warn("Err parsing config: {}", e.what()); - } - if (launch.launch) { - launch.isUWP = checkIsUwp(launch.launchPath); - } - } - - inline void Parse(const std::vector& args) - { - std::wstring configName; - std::vector> cli_overrides; - for (const auto& arg : args) { - if (arg.empty()) { - continue; - } - if (cmd_args.contains(arg)) - { - cli_overrides.push_back(cmd_args.at(arg)); - } - else { - configName += L" " + std::wstring(arg.begin(), arg.end()); - } - } - if (!configName.empty()) { - if (configName[0] == L' ') { - configName.erase(configName.begin()); - } - if (!configName.ends_with(L".json")) { - configName += L".json"; - } - } - auto path = util::path::getDataDirPath(); - if (!configName.empty()) { - path /= "Targets"; - path /= configName; - } - else { - spdlog::info("No config file specified, using default"); - path /= "default.json"; - } - - std::ifstream json_file; - json_file.open(path); - if (!json_file.is_open()) { - spdlog::error(L"Couldn't open settings file {}", path.wstring()); - spdlog::debug(L"Using sane defaults..."); - for (const auto& ovr : cli_overrides) { - ovr(); - } - return; - } - settings_path_ = path; - const auto& json = nlohmann::json::parse(json_file); - Parse(json); - - for (const auto& ovr : cli_overrides) { - ovr(); - } - spdlog::debug("Read config file \"{}\"; config: {}", path.string(), json.dump()); - json_file.close(); - } - - inline nlohmann::json toJson() - { - nlohmann::json json; - json["version"] = 1; - json["launch"]["launch"] = launch.launch; - json["launch"]["launchPath"] = launch.launchPath; - json["launch"]["launchAppArgs"] = launch.launchAppArgs; - json["launch"]["closeOnExit"] = launch.closeOnExit; - json["launch"]["waitForChildProcs"] = launch.waitForChildProcs; - json["devices"]["hideDevices"] = devices.hideDevices; - json["devices"]["realDeviceIds"] = devices.realDeviceIds; - json["window"]["windowMode"] = window.windowMode; - json["window"]["maxFps"] = window.maxFps; - json["window"]["scale"] = window.scale; - json["window"]["disableOverlay"] = window.disableOverlay; - json["window"]["hideAltTab"] = window.hideAltTab; - json["controller"]["maxControllers"] = controller.maxControllers; - json["controller"]["allowDesktopConfig"] = controller.allowDesktopConfig; - json["controller"]["emulateDS4"] = controller.emulateDS4; - - json["extendedLogging"] = common.extendedLogging; - json["name"] = common.name; - json["icon"] = common.icon; - json["version"] = common.version; - return json; - } - - inline void StoreSettings() - { - const auto& json = toJson(); - - std::ofstream json_file; - json_file.open(settings_path_); - if (!json_file.is_open()) { - spdlog::error(L"Couldn't open settings file {}", settings_path_.wstring()); - return; - } - json_file << json.dump(4); - json_file.close(); - } + inline void Parse(const nlohmann::basic_json<> &json) + { + constexpr auto safeParseValue = [](const auto &object, const auto &key, T &value) + { + try + { + if (object.is_null() || object.empty() || object.at(key).empty() || object.at(key).is_null()) + { + return; + } + if constexpr (std::is_same_v) + { + value = util::string::to_wstring(object[key].get()); + } + else + { + value = object[key]; + } + } + catch (const nlohmann::json::exception &e) + { + e.id == 403 + ? spdlog::trace("Err parsing \"{}\"; {}", key, e.what()) + : spdlog::warn("Err parsing \"{}\"; {}", key, e.what()); + } + catch (const std::exception &e) + { + spdlog::warn("Err parsing \"{}\"; {}", key, e.what()); + } + }; + + int version; + safeParseValue(json, "version", version); + if (version != 1) + { // TODO: versioning stuff + spdlog::warn("Config version doesn't match application version."); + } + + // TODO: make this as much generic as fits in about the same amount of code if one would parse every value separately. + try + { + if (const auto launchconf = json["launch"]; !launchconf.is_null() && !launchconf.empty() && launchconf.is_object()) + { + safeParseValue(launchconf, "launch", launch.launch); + safeParseValue(launchconf, "launchPath", launch.launchPath); + safeParseValue(launchconf, "launchAppArgs", launch.launchAppArgs); + safeParseValue(launchconf, "closeOnExit", launch.closeOnExit); + safeParseValue(launchconf, "waitForChildProcs", launch.waitForChildProcs); + safeParseValue(launchconf, "killLauncher", launch.killLauncher); + safeParseValue(launchconf, "ignoreLauncher", launch.ignoreLauncher); + + if (launchconf.contains("launcherProcesses") && launchconf["launcherProcesses"].is_array()) + { + if (const auto launcherProcs = launchconf["launcherProcesses"]; + !launcherProcs.is_null() && !launcherProcs.empty() && launcherProcs.is_array()) + { + launch.launcherProcesses.clear(); + launch.launcherProcesses.reserve(launcherProcs.size()); + for (auto &proc : launcherProcs) + { + launch.launcherProcesses.push_back(util::string::to_wstring(proc)); + } + } + } + } + + if (const auto devconf = json["devices"]; !devconf.is_null() && !devconf.empty() && devconf.is_object()) + { + safeParseValue(devconf, "hideDevices", devices.hideDevices); + safeParseValue(devconf, "realDeviceIds", devices.realDeviceIds); + } + + if (const auto winconf = json["window"]; !winconf.is_null() && !winconf.empty() && winconf.is_object()) + { + safeParseValue(winconf, "windowMode", window.windowMode); + safeParseValue(winconf, "maxFps", window.maxFps); + safeParseValue(winconf, "scale", window.scale); + safeParseValue(winconf, "disableOverlay", window.disableOverlay); + safeParseValue(winconf, "hideAltTab", window.hideAltTab); + safeParseValue(winconf, "disableGlosSIOverlay", window.disableGlosSIOverlay); + } + + if (const auto controllerConf = json["controller"]; !controllerConf.is_null() && !controllerConf.empty() && controllerConf.is_object()) + { + safeParseValue(controllerConf, "maxControllers", controller.maxControllers); + safeParseValue(controllerConf, "allowDesktopConfig", controller.allowDesktopConfig); + safeParseValue(controllerConf, "emulateDS4", controller.emulateDS4); + } + safeParseValue(json, "extendedLogging", common.extendedLogging); + safeParseValue(json, "name", common.name); + safeParseValue(json, "icon", common.icon); + safeParseValue(json, "version", common.version); + + safeParseValue(json, "steamPath", common.steamPath); + safeParseValue(json, "steamUserId", common.steamUserId); + + safeParseValue(json, "globalModeGameId", common.globalModeGameId); + safeParseValue(json, "globalModeUseGamepadUI", common.globalModeUseGamepadUI); + } + catch (const nlohmann::json::exception &e) + { + spdlog::warn("Err parsing config: {}", e.what()); + } + catch (const std::exception &e) + { + spdlog::warn("Err parsing config: {}", e.what()); + } + if (launch.launch) + { + launch.isUWP = checkIsUwp(launch.launchPath); + } + } + + inline void Parse(const std::vector &args) + { + std::wstring configName; + std::vector> cli_overrides; + for (const auto &arg : args) + { + if (arg.empty()) + { + continue; + } + if (cmd_args.contains(arg)) + { + cli_overrides.push_back(cmd_args.at(arg)); + } + else + { + configName += L" " + std::wstring(arg.begin(), arg.end()); + } + } + if (!configName.empty()) + { + if (configName[0] == L' ') + { + configName.erase(configName.begin()); + } + if (!configName.ends_with(L".json")) + { + configName += L".json"; + } + } + auto path = util::path::getDataDirPath(); + if (!configName.empty()) + { + path /= "Targets"; + path /= configName; + } + else + { + spdlog::info("No config file specified, using default"); + path /= "default.json"; + } + + std::ifstream json_file; + json_file.open(path); + if (!json_file.is_open()) + { + spdlog::error(L"Couldn't open settings file {}", path.wstring()); + spdlog::debug(L"Using sane defaults..."); + for (const auto &ovr : cli_overrides) + { + ovr(); + } + return; + } + settings_path_ = path; + const auto &json = nlohmann::json::parse(json_file); + Parse(json); + + for (const auto &ovr : cli_overrides) + { + ovr(); + } + spdlog::debug("Read config file \"{}\"; config: {}", path.string(), json.dump()); + json_file.close(); + } + + inline nlohmann::json toJson() + { + nlohmann::json json; + json["version"] = 1; + json["launch"]["launch"] = launch.launch; + json["launch"]["launchPath"] = launch.launchPath; + json["launch"]["launchAppArgs"] = launch.launchAppArgs; + json["launch"]["closeOnExit"] = launch.closeOnExit; + json["launch"]["waitForChildProcs"] = launch.waitForChildProcs; + json["devices"]["hideDevices"] = devices.hideDevices; + json["devices"]["realDeviceIds"] = devices.realDeviceIds; + json["window"]["windowMode"] = window.windowMode; + json["window"]["maxFps"] = window.maxFps; + json["window"]["scale"] = window.scale; + json["window"]["disableOverlay"] = window.disableOverlay; + json["window"]["hideAltTab"] = window.hideAltTab; + json["controller"]["maxControllers"] = controller.maxControllers; + json["controller"]["allowDesktopConfig"] = controller.allowDesktopConfig; + json["controller"]["emulateDS4"] = controller.emulateDS4; + + json["extendedLogging"] = common.extendedLogging; + json["name"] = common.name; + json["icon"] = common.icon; + json["version"] = common.version; + return json; + } + + inline void StoreSettings() + { + const auto &json = toJson(); + + std::ofstream json_file; + json_file.open(settings_path_); + if (!json_file.is_open()) + { + spdlog::error(L"Couldn't open settings file {}", settings_path_.wstring()); + return; + } + json_file << json.dump(4); + json_file.close(); + } } // namespace Settings