From f7df3deb7db3a1c0aa2ad05e7ba0a8a1ff17c689 Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Sun, 29 Jan 2023 16:43:01 +0100 Subject: [PATCH] Cleanup --- GlosSIConfig/Resource.rc | 1437 +-------------------------------- GlosSITarget/HttpServer.cpp | 5 +- GlosSITarget/Resource.rc | 261 +----- GlosSITarget/SteamTarget.cpp | 229 +----- GlosSITarget/SteamTarget.h | 27 +- Installer/Installer.nsi | 43 +- common/Settings.h | 535 ++++++------ common/UnhookUtil.cpp | 2 + common/common.vcxproj | 14 +- common/common.vcxproj.filters | 3 + common/steam_util.h | 181 +++++ common/util.h | 6 +- 12 files changed, 543 insertions(+), 2200 deletions(-) create mode 100644 common/steam_util.h diff --git a/GlosSIConfig/Resource.rc b/GlosSIConfig/Resource.rc index b01172c..1f1efe3 100644 --- a/GlosSIConfig/Resource.rc +++ b/GlosSIConfig/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,2,0010004309958 - PRODUCTVERSION 0,1,2,0010004309958 + FILEVERSION 0,1,2,0011001030052 + PRODUCTVERSION 0,1,2,0011001030052 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-10-g43c9958" + VALUE "FileVersion", "0.1.2.0-11-g1f3fb52" VALUE "InternalName", "GlosSIConfig" VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSIConfig.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.1.2.0-10-g43c9958" + VALUE "ProductVersion", "0.1.2.0-11-g1f3fb52" END END BLOCK "VarFileInfo" @@ -107,1432 +107,3 @@ IDI_ICON1 ICON "..\GlosSI_Icon.ico" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/GlosSITarget/HttpServer.cpp b/GlosSITarget/HttpServer.cpp index 37798e7..ef0a49b 100644 --- a/GlosSITarget/HttpServer.cpp +++ b/GlosSITarget/HttpServer.cpp @@ -17,11 +17,12 @@ limitations under the License. #include #include +#include #include "AppLauncher.h" -#include "..\common\Settings.h" +#include "../common/Settings.h" -HttpServer::HttpServer(AppLauncher& app_launcher, std::function close) : app_launcher_(app_launcher), close_(close) +HttpServer::HttpServer(AppLauncher& app_launcher, std::function close) : app_launcher_(app_launcher), close_(std::move(close)) { } diff --git a/GlosSITarget/Resource.rc b/GlosSITarget/Resource.rc index 29f06bd..806d632 100644 --- a/GlosSITarget/Resource.rc +++ b/GlosSITarget/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,2,0010004309958 - PRODUCTVERSION 0,1,2,0010004309958 + FILEVERSION 0,1,2,0011001030052 + PRODUCTVERSION 0,1,2,0011001030052 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - SteamTarget" - VALUE "FileVersion", "0.1.2.0-10-g43c9958" + VALUE "FileVersion", "0.1.2.0-11-g1f3fb52" VALUE "InternalName", "GlosSITarget" VALUE "LegalCopyright", "Copyright (C) 2021-2022 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSITarget.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.1.2.0-10-g43c9958" + VALUE "ProductVersion", "0.1.2.0-11-g1f3fb52" END END BLOCK "VarFileInfo" @@ -107,256 +107,3 @@ IDI_ICON1 ICON "..\\GlosSI_Icon.ico" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp index 2c4f338..30592e6 100644 --- a/GlosSITarget/SteamTarget.cpp +++ b/GlosSITarget/SteamTarget.cpp @@ -23,7 +23,6 @@ limitations under the License. #include #include #include -#include #ifdef _WIN32 #include "UWPOverlayEnabler.h" @@ -36,7 +35,7 @@ SteamTarget::SteamTarget() : window_( [this] { run_ = false; }, [this] { toggleGlossiOverlay(); }, - getScreenshotHotkey(), + util::steam::getScreenshotHotkey(steam_path_, steam_user_id_), [this]() { target_window_handle_ = window_.getSystemHandle(); overlay_ = window_.getOverlay(); @@ -65,26 +64,24 @@ int SteamTarget::run() auto closeBPM = false; auto closeBPMTimer = sf::Clock{}; if (!SteamOverlayDetector::IsSteamInjected()) { - return 1; 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!"); } - SetEnvironmentVariable(L"SteamAppId", L"0"); SetEnvironmentVariable(L"SteamClientLaunch", L"0"); SetEnvironmentVariable(L"SteamEnv", L"1"); - SetEnvironmentVariable(L"SteamPath", getSteamPath().wstring().c_str()); + SetEnvironmentVariable(L"SteamPath", steam_path_.wstring().c_str()); SetEnvironmentVariable(L"SteamTenfoot", Settings::common.standaloneUseGamepadUI ? L"1" : L"0"); - //SetEnvironmentVariable(L"SteamTenfootHybrid", L"1"); + // 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"EnableConfiguratorSupport", L"15"); SetEnvironmentVariable(L"SteamStreamingForceWindowedD3D9", L"1"); - if (Settings::common.standaloneUseGamepadUI) { + if (Settings::common.standaloneUseGamepadUI) { system("start steam://open/bigpicture"); auto steamwindow = FindWindow(L"Steam Big Picture Mode", nullptr); auto timer = sf::Clock{}; @@ -94,22 +91,21 @@ int SteamTarget::run() } Sleep(6000); // DIRTY HACK to wait until BPM (GamepadUI) is initialized // TODO: find way to force BPM even if BPM is not active - LoadLibrary((getSteamPath() / "GameOverlayRenderer64.dll").wstring().c_str()); - - // Overlay switches back to desktop one, once BPM is closed... Disable closing BPM for now. - // TODO: find way to force BPM even if BPM is not active + LoadLibrary((steam_path_ / "GameOverlayRenderer64.dll").wstring().c_str()); + + // Overlay switches back to desktop one, once BPM is closed... Disable closing BPM for now. + // TODO: find way to force BPM even if BPM is not active // closeBPM = true; closeBPMTimer.restart(); } else { - LoadLibrary( (getSteamPath() / "GameOverlayRenderer64.dll").wstring().c_str()); + LoadLibrary((steam_path_ / "GameOverlayRenderer64.dll").wstring().c_str()); } window_.setClickThrough(true); if (!overlay_.expired()) overlay_.lock()->setEnabled(false); steam_overlay_present_ = true; - } else { spdlog::info("Steam-overlay detected."); @@ -130,7 +126,7 @@ int SteamTarget::run() } #endif } - getXBCRebindingEnabled(); + util::steam::getXBCRebindingEnabled(steam_path_, steam_user_id_); run_ = true; @@ -145,29 +141,7 @@ int SteamTarget::run() keepControllerConfig(true); -#ifdef _WIN32 - HICON icon = 0; - TCHAR path[MAX_PATH]; - GetModuleFileName(nullptr, path, MAX_PATH); - icon = (HICON)LoadImage( - 0, - path, - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_LOADFROMFILE | LR_LOADMAP3DCOLORS); - if (!icon) { - ExtractIconEx(path, 0, &icon, nullptr, 1); - } - Tray::Tray tray{"GlosSITarget", icon}; -#else - Tray::Tray tray{"GlosSITarget", "ico.png"}; -#endif - - tray.addEntry(Tray::Button{ - "Quit", [this, &tray]() { - run_ = false; - }}); + const auto tray = createTrayMenu(); server_.run(); @@ -176,9 +150,9 @@ int SteamTarget::run() overlayHotkeyWorkaround(); window_.update(); - if (closeBPM && closeBPMTimer.getElapsedTime().asSeconds() >= 3) { - system("start steam://close/bigpicture"); - closeBPM = false; + if (closeBPM && closeBPMTimer.getElapsedTime().asSeconds() >= 3) { + system("start steam://close/bigpicture"); + closeBPM = false; } // Wait on shutdown; User might get confused if window closes to fast if anything with launchApp get's borked. @@ -191,7 +165,7 @@ int SteamTarget::run() launcher_.update(); } } - tray.exit(); + tray->exit(); server_.stop(); #ifdef _WIN32 @@ -290,154 +264,11 @@ void SteamTarget::focusWindow(WindowHandle hndl) #endif } -std::filesystem::path SteamTarget::getSteamPath() const -{ -#ifdef _WIN32 - try { - // TODO: check if keys/value exist - // steam should always be open and have written reg values... - winreg::RegKey key{HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam"}; - const auto res = key.GetStringValue(L"SteamPath"); - spdlog::info(L"Detected Steam Path: {}", res); - return res; - } - catch (const winreg::RegException& e) { - spdlog::error("Couldn't get Steam path from Registry; {}", e.what()); - } - return Settings::common.steamPath; -#else - return L""; // TODO -#endif -} - -std::wstring SteamTarget::getSteamUserId() const -{ -#ifdef _WIN32 - try { - // TODO: check if keys/value exist - // steam should always be open and have written reg values... - winreg::RegKey key{HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam\\ActiveProcess"}; - const auto res = std::to_wstring(key.GetDwordValue(L"ActiveUser")); - spdlog::info(L"Detected Steam UserId: {}", res); - return res; - } - catch (const winreg::RegException& e) { - spdlog::error("Couldn't get Steam path from Registry; {}", e.what()); - } - return Settings::common.steamUserId; -#else - return L""; // TODO -#endif -} - -std::vector SteamTarget::getOverlayHotkey() -{ - const auto config_path = std::wstring(steam_path_) + std::wstring(user_data_path_) + steam_user_id_ + std::wstring(config_file_name_); - if (!std::filesystem::exists(config_path)) { - spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path); - return {"Shift", "KEY_TAB"}; // default - } - std::ifstream config_file(config_path); - auto root = tyti::vdf::read(config_file); - - std::shared_ptr> children = root.childs["system"]; - if (!children || children->attribs.empty() || !children->attribs.contains("InGameOverlayShortcutKey")) { - spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab"); - return {"Shift", "KEY_TAB"}; // default - } - auto hotkeys = children->attribs.at("InGameOverlayShortcutKey"); - - // has anyone more than 4 keys to open overlay?! - std::smatch m; - if (!std::regex_match(hotkeys, m, std::regex(R"((\w*)\s*(\w*)\s*(\w*)\s*(\w*))"))) { - spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab"); - return {"Shift", "KEY_TAB"}; // default - } - - std::vector res; - for (auto i = 1; i < m.size(); i++) { - const auto s = std::string(m[i]); - if (!s.empty()) { - res.push_back(s); - } - } - if (res.empty()) { - spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab"); - return {"Shift", "KEY_TAB"}; // default - } - spdlog::info("Detected Overlay hotkey(s): {}", std::accumulate( - res.begin() + 1, res.end(), res[0], - [](auto acc, const auto curr) { return acc += "+" + curr; })); - return res; -} - -std::vector SteamTarget::getScreenshotHotkey() -{ - const auto config_path = std::wstring(steam_path_) + std::wstring(user_data_path_) + steam_user_id_ + std::wstring(config_file_name_); - if (!std::filesystem::exists(config_path)) { - spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path); - return {"KEY_F12"}; // default - } - std::ifstream config_file(config_path); - auto root = tyti::vdf::read(config_file); - - std::shared_ptr> children = root.childs["system"]; - if (!children || children->attribs.empty() || !children->attribs.contains("InGameOverlayScreenshotHotKey")) { - spdlog::warn("Couldn't detect overlay hotkey, using default: F12"); - return {"KEY_F12"}; // default - } - auto hotkeys = children->attribs.at("InGameOverlayScreenshotHotKey"); - - // has anyone more than 4 keys to screenshot?! - std::smatch m; - if (!std::regex_match(hotkeys, m, std::regex(R"((\w*)\s*(\w*)\s*(\w*)\s*(\w*))"))) { - spdlog::warn("Couldn't detect overlay hotkey, using default: F12"); - return {"KEY_F12"}; // default - } - - std::vector res; - for (auto i = 1; i < m.size(); i++) { - const auto s = std::string(m[i]); - if (!s.empty()) { - res.push_back(s); - } - } - if (res.empty()) { - spdlog::warn("Couldn't detect overlay hotkey, using default: F12"); - return {"KEY_F12"}; // default - } - spdlog::info("Detected screenshot hotkey(s): {}", std::accumulate( - res.begin() + 1, res.end(), res[0], - [](auto acc, const auto curr) { return acc += "+" + curr; })); - return res; -} - -bool SteamTarget::getXBCRebindingEnabled() -{ - const auto config_path = std::wstring(steam_path_) + std::wstring(user_data_path_) + steam_user_id_ + std::wstring(config_file_name_); - if (!std::filesystem::exists(config_path)) { - spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path); - return false; - } - std::ifstream config_file(config_path); - auto root = tyti::vdf::read(config_file); - - if (root.attribs.empty() || !root.attribs.contains("SteamController_XBoxSupport")) { - spdlog::warn("\"Xbox Configuration Support\" is disabled in Steam. This may cause doubled Inputs!"); - return false; - } - auto xbsup = root.attribs.at("SteamController_XBoxSupport"); - if (xbsup != "1") { - spdlog::warn("\"Xbox Configuration Support\" is disabled in Steam. This may cause doubled Inputs!"); - } - return xbsup == "1"; -} - /* * The "magic" that keeps a controller-config forced (without hooking into Steam) * * Hook into own process and detour "GetForegroundWindow" - * Deatour function always returns HWND of own application window + * Detour function always returns HWND of own application window * Steam now doesn't detect application changes and keeps the game-specific input config without reverting to desktop-conf */ void SteamTarget::keepControllerConfig(bool keep) @@ -488,6 +319,34 @@ HWND SteamTarget::keepFgWindowHookFn() } #endif +std::unique_ptr SteamTarget::createTrayMenu() +{ +#ifdef _WIN32 + HICON icon = 0; + TCHAR path[MAX_PATH]; + GetModuleFileName(nullptr, path, MAX_PATH); + icon = (HICON)LoadImage( + 0, + path, + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_LOADFROMFILE | LR_LOADMAP3DCOLORS); + if (!icon) { + ExtractIconEx(path, 0, &icon, nullptr, 1); + } + auto tray = std::make_unique("GlosSITarget", icon); +#else + auto tray = std::make_unique("GlosSITarget", "ico.png"); +#endif + + tray->addEntry(Tray::Button{ + "Quit", [this, &tray]() { + run_ = false; + }}); + return tray; +} + void SteamTarget::overlayHotkeyWorkaround() { static bool pressed = false; diff --git a/GlosSITarget/SteamTarget.h b/GlosSITarget/SteamTarget.h index c4220b9..0ce56ef 100644 --- a/GlosSITarget/SteamTarget.h +++ b/GlosSITarget/SteamTarget.h @@ -26,13 +26,17 @@ limitations under the License. #include #endif +#include + #include "AppLauncher.h" #include "Overlay.h" #include "HttpServer.h" +#include "../common/steam_util.h" -#include - +namespace Tray { +class Tray; +} class SteamTarget { public: explicit SteamTarget(); @@ -42,15 +46,9 @@ class SteamTarget { void onOverlayChanged(bool overlay_open); void toggleGlossiOverlay(); void focusWindow(WindowHandle hndl); - std::filesystem::path getSteamPath() const; - std::wstring getSteamUserId() const; - std::filesystem::path steam_path_ = getSteamPath(); - std::wstring steam_user_id_ = getSteamUserId(); - - std::vector getOverlayHotkey(); - std::vector getScreenshotHotkey(); - bool getXBCRebindingEnabled(); + std::filesystem::path steam_path_ = util::steam::getSteamPath(); + std::wstring steam_user_id_ = util::steam::getSteamUserId(); bool steam_overlay_present_ = false; @@ -65,6 +63,8 @@ class SteamTarget { static inline HWND last_real_hwnd_ = nullptr; #endif + std::unique_ptr createTrayMenu(); + /* * Run once per frame * detects steam configured overlay hotkey, and simulates key presses to window @@ -74,7 +74,7 @@ class SteamTarget { void overlayHotkeyWorkaround(); bool run_ = false; - std::vector overlay_hotkey_ = getOverlayHotkey(); + std::vector overlay_hotkey_ = util::steam::getOverlayHotkey(steam_path_, steam_user_id_); #ifdef _WIN32 HidHide hidhide_; @@ -94,9 +94,4 @@ class SteamTarget { bool delayed_shutdown_ = false; sf::Clock delay_shutdown_clock_; - - static constexpr std::wstring_view user_data_path_ = L"/userdata/"; - static constexpr std::wstring_view config_file_name_ = L"/config/localconfig.vdf"; - static constexpr std::string_view overlay_hotkey_name_ = "InGameOverlayShortcutKey "; - static constexpr std::string_view screenshot_hotkey_name_ = "InGameOverlayScreenshotHotKey "; }; diff --git a/Installer/Installer.nsi b/Installer/Installer.nsi index 65c96aa..80553ae 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-10-g43c9958" +!define VERSION "0.1.2.0-11-g1f3fb52" !define COPYRIGHT "Peter Repukat - FlatspotSoftware © 2017-2022" !define DESCRIPTION "SteamInput compatibility tool" !define INSTALLER_NAME "GlosSI-Installer.exe" @@ -191,44 +191,3 @@ DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}" DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}" SectionEnd - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/common/Settings.h b/common/Settings.h index 09bbe0c..f0e4fa6 100644 --- a/common/Settings.h +++ b/common/Settings.h @@ -15,11 +15,13 @@ limitations under the License. */ #pragma once +#define SPDLOG_WCHAR_TO_UTF8_SUPPORT +#define SPDLOG_WCHAR_FILENAMES +#include #include #include #include #include -#include #ifdef WIN32 #define NOMINMAX @@ -32,269 +34,280 @@ limitations under the License. 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; - } common; - - 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; - } + 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; + } #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 (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 (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 (auto devconf = json["devices"]; !devconf.is_null() && !devconf.empty() && devconf.is_object()) { - safeParseValue(devconf, "hideDevices", devices.hideDevices); - safeParseValue(devconf, "realDeviceIds", devices.realDeviceIds); - } - - if (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 (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; - for (const auto& arg : args) { - if (arg.empty()) { - continue; - } - if (arg == L"-disableuwpoverlay") { - common.no_uwp_overlay = true; - } - else if (arg == L"-disablewatchdog") { - common.disable_watchdog = true; - } - else if (arg == L"-ignorelauncher") { - launch.ignoreLauncher = true; - } - else if (arg == L"-window") { - window.windowMode = true; - } - 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..."); - return; - } - settings_path_ = path; - const auto& json = nlohmann::json::parse(json_file); - Parse(json); - - 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) { + if constexpr (std::is_same_v) { + e.id == 403 + ? spdlog::trace("Err parsing \"{}\"; {}; Using default: {}", key, e.what(), util::string::to_string(value)) + : spdlog::warn("Err parsing \"{}\"; {}", key, e.what()); + } + else + { + e.id == 403 + ? spdlog::trace("Err parsing \"{}\"; {}; Using default: {}", key, e.what(), value) + : 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 (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; + for (const auto& arg : args) { + if (arg.empty()) { + continue; + } + if (cmd_args.contains(arg)) + { + 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..."); + return; + } + settings_path_ = path; + const auto& json = nlohmann::json::parse(json_file); + Parse(json); + + 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 diff --git a/common/UnhookUtil.cpp b/common/UnhookUtil.cpp index f5d04d4..1b77540 100644 --- a/common/UnhookUtil.cpp +++ b/common/UnhookUtil.cpp @@ -18,6 +18,8 @@ limitations under the License. #include "util.h" #ifndef CONFIGAPP +#define SPDLOG_WCHAR_TO_UTF8_SUPPORT +#define SPDLOG_WCHAR_FILENAMES #include #include "Settings.h" diff --git a/common/common.vcxproj b/common/common.vcxproj index 5e38350..cf0b1d2 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -1,5 +1,6 @@ + Debug @@ -71,10 +72,10 @@ - ..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;$(IncludePath) + ..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;..\deps\WinReg;..\deps\ValveFileVDF;$(IncludePath) - ..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;$(IncludePath) + ..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;..\deps\WinReg;..\deps\ValveFileVDF;$(IncludePath) @@ -138,6 +139,7 @@ + @@ -147,5 +149,13 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index cd5e20b..aa49593 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -30,6 +30,9 @@ Header Files + + Header Files + diff --git a/common/steam_util.h b/common/steam_util.h new file mode 100644 index 0000000..43c60cb --- /dev/null +++ b/common/steam_util.h @@ -0,0 +1,181 @@ +/* +Copyright 2021-2023 Peter Repukat - FlatspotSoftware + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#pragma once + +#define SPDLOG_WCHAR_TO_UTF8_SUPPORT +#define SPDLOG_WCHAR_FILENAMES +#include +#include +#include + + +#include "util.h" +#include "Settings.h" + +namespace util +{ + namespace steam + { + + static constexpr std::wstring_view user_data_path = L"/userdata/"; + static constexpr std::wstring_view config_file_name = L"/config/localconfig.vdf"; + static constexpr std::string_view overlay_hotkey_name = "InGameOverlayShortcutKey "; + static constexpr std::string_view screenshot_hotkey_name = "InGameOverlayScreenshotHotKey "; + + inline std::filesystem::path getSteamPath() + { +#ifdef _WIN32 + try { + // TODO: check if keys/value exist + // steam should always be open and have written reg values... + winreg::RegKey key{ HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam" }; + const auto res = key.GetStringValue(L"SteamPath"); + spdlog::info(L"Detected Steam Path: {}", res); + return res; + } + catch (const winreg::RegException& e) { + spdlog::error("Couldn't get Steam path from Registry; {}", e.what()); + } + return Settings::common.steamPath; +#else + return L""; // TODO +#endif + } + + inline std::wstring getSteamUserId() + { +#ifdef _WIN32 + try { + // TODO: check if keys/value exist + // steam should always be open and have written reg values... + winreg::RegKey key{ HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam\\ActiveProcess" }; + const auto res = std::to_wstring(key.GetDwordValue(L"ActiveUser")); + spdlog::info(L"Detected Steam UserId: {}", res); + return res; + } + catch (const winreg::RegException& e) { + spdlog::error("Couldn't get Steam path from Registry; {}", e.what()); + } + return Settings::common.steamUserId; +#else + return L""; // TODO +#endif + } + + inline std::vector getOverlayHotkey(const std::wstring& steam_path = getSteamPath(), const std::wstring& steam_user_id = getSteamPath()) + { + const auto config_path = std::wstring(steam_path) + std::wstring(user_data_path) + steam_user_id + std::wstring(config_file_name); + if (!std::filesystem::exists(config_path)) { + spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path); + return { "Shift", "KEY_TAB" }; // default + } + std::ifstream config_file(config_path); + auto root = tyti::vdf::read(config_file); + + std::shared_ptr> children = root.childs["system"]; + if (!children || children->attribs.empty() || !children->attribs.contains("InGameOverlayShortcutKey")) { + spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab"); + return { "Shift", "KEY_TAB" }; // default + } + auto hotkeys = children->attribs.at("InGameOverlayShortcutKey"); + + // has anyone more than 4 keys to open overlay?! + std::smatch m; + if (!std::regex_match(hotkeys, m, std::regex(R"((\w*)\s*(\w*)\s*(\w*)\s*(\w*))"))) { + spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab"); + return { "Shift", "KEY_TAB" }; // default + } + + std::vector res; + for (auto i = 1; i < m.size(); i++) { + const auto s = std::string(m[i]); + if (!s.empty()) { + res.push_back(s); + } + } + if (res.empty()) { + spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab"); + return { "Shift", "KEY_TAB" }; // default + } + spdlog::info("Detected Overlay hotkey(s): {}", std::accumulate( + res.begin() + 1, res.end(), res[0], + [](auto acc, const auto curr) { return acc += "+" + curr; })); + return res; + } + + inline std::vector getScreenshotHotkey(const std::wstring& steam_path = getSteamPath(), const std::wstring& steam_user_id = getSteamPath()) + { + const auto config_path = std::wstring(steam_path) + std::wstring(user_data_path) + steam_user_id + std::wstring(config_file_name); + if (!std::filesystem::exists(config_path)) { + spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path); + return { "KEY_F12" }; // default + } + std::ifstream config_file(config_path); + auto root = tyti::vdf::read(config_file); + + std::shared_ptr> children = root.childs["system"]; + if (!children || children->attribs.empty() || !children->attribs.contains("InGameOverlayScreenshotHotKey")) { + spdlog::warn("Couldn't detect overlay hotkey, using default: F12"); + return { "KEY_F12" }; // default + } + auto hotkeys = children->attribs.at("InGameOverlayScreenshotHotKey"); + + // has anyone more than 4 keys to screenshot?! + std::smatch m; + if (!std::regex_match(hotkeys, m, std::regex(R"((\w*)\s*(\w*)\s*(\w*)\s*(\w*))"))) { + spdlog::warn("Couldn't detect overlay hotkey, using default: F12"); + return { "KEY_F12" }; // default + } + + std::vector res; + for (auto i = 1; i < m.size(); i++) { + const auto s = std::string(m[i]); + if (!s.empty()) { + res.push_back(s); + } + } + if (res.empty()) { + spdlog::warn("Couldn't detect overlay hotkey, using default: F12"); + return { "KEY_F12" }; // default + } + spdlog::info("Detected screenshot hotkey(s): {}", std::accumulate( + res.begin() + 1, res.end(), res[0], + [](auto acc, const auto curr) { return acc += "+" + curr; })); + return res; + } + + inline bool getXBCRebindingEnabled(const std::wstring& steam_path = getSteamPath(), const std::wstring& steam_user_id = getSteamPath()) + { + const auto config_path = std::wstring(steam_path) + std::wstring(user_data_path) + steam_user_id + std::wstring(config_file_name); + if (!std::filesystem::exists(config_path)) { + spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path); + return false; + } + std::ifstream config_file(config_path); + auto root = tyti::vdf::read(config_file); + + if (root.attribs.empty() || !root.attribs.contains("SteamController_XBoxSupport")) { + spdlog::warn("\"Xbox Configuration Support\" is disabled in Steam. This may cause doubled Inputs!"); + return false; + } + auto xbsup = root.attribs.at("SteamController_XBoxSupport"); + if (xbsup != "1") { + spdlog::warn("\"Xbox Configuration Support\" is disabled in Steam. This may cause doubled Inputs!"); + } + return xbsup == "1"; + } + } +} \ No newline at end of file diff --git a/common/util.h b/common/util.h index 52cadc6..b12da09 100644 --- a/common/util.h +++ b/common/util.h @@ -31,6 +31,8 @@ limitations under the License. #include #ifdef SPDLOG_H +#define SPDLOG_WCHAR_TO_UTF8_SUPPORT +#define SPDLOG_WCHAR_FILENAMES #include #endif @@ -158,6 +160,6 @@ namespace util { return res; } } - } + } #endif - } \ No newline at end of file +} \ No newline at end of file