pull/239/head
Peter Repukat 1 year ago
parent 738803fa2e
commit f7df3deb7d

File diff suppressed because it is too large Load Diff

@ -17,11 +17,12 @@ limitations under the License.
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <utility>
#include "AppLauncher.h" #include "AppLauncher.h"
#include "..\common\Settings.h" #include "../common/Settings.h"
HttpServer::HttpServer(AppLauncher& app_launcher, std::function<void()> close) : app_launcher_(app_launcher), close_(close) HttpServer::HttpServer(AppLauncher& app_launcher, std::function<void()> close) : app_launcher_(app_launcher), close_(std::move(close))
{ {
} }

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,1,2,0010004309958 FILEVERSION 0,1,2,0011001030052
PRODUCTVERSION 0,1,2,0010004309958 PRODUCTVERSION 0,1,2,0011001030052
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -69,12 +69,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "CompanyName", "Peter Repukat - FlatspotSoftware"
VALUE "FileDescription", "GlosSI - SteamTarget" VALUE "FileDescription", "GlosSI - SteamTarget"
VALUE "FileVersion", "0.1.2.0-10-g43c9958" VALUE "FileVersion", "0.1.2.0-11-g1f3fb52"
VALUE "InternalName", "GlosSITarget" VALUE "InternalName", "GlosSITarget"
VALUE "LegalCopyright", "Copyright (C) 2021-2022 Peter Repukat - FlatspotSoftware" VALUE "LegalCopyright", "Copyright (C) 2021-2022 Peter Repukat - FlatspotSoftware"
VALUE "OriginalFilename", "GlosSITarget.exe" VALUE "OriginalFilename", "GlosSITarget.exe"
VALUE "ProductName", "GlosSI" VALUE "ProductName", "GlosSI"
VALUE "ProductVersion", "0.1.2.0-10-g43c9958" VALUE "ProductVersion", "0.1.2.0-11-g1f3fb52"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@ -107,256 +107,3 @@ IDI_ICON1 ICON "..\\GlosSI_Icon.ico"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED #endif // not APSTUDIO_INVOKED

@ -23,7 +23,6 @@ limitations under the License.
#include <numeric> #include <numeric>
#include <regex> #include <regex>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <vdf_parser.hpp>
#ifdef _WIN32 #ifdef _WIN32
#include "UWPOverlayEnabler.h" #include "UWPOverlayEnabler.h"
@ -36,7 +35,7 @@ SteamTarget::SteamTarget()
: window_( : window_(
[this] { run_ = false; }, [this] { run_ = false; },
[this] { toggleGlossiOverlay(); }, [this] { toggleGlossiOverlay(); },
getScreenshotHotkey(), util::steam::getScreenshotHotkey(steam_path_, steam_user_id_),
[this]() { [this]() {
target_window_handle_ = window_.getSystemHandle(); target_window_handle_ = window_.getSystemHandle();
overlay_ = window_.getOverlay(); overlay_ = window_.getOverlay();
@ -65,26 +64,24 @@ int SteamTarget::run()
auto closeBPM = false; auto closeBPM = false;
auto closeBPMTimer = sf::Clock{}; auto closeBPMTimer = sf::Clock{};
if (!SteamOverlayDetector::IsSteamInjected()) { if (!SteamOverlayDetector::IsSteamInjected()) {
return 1;
spdlog::warn("GlosSI not launched via Steam.\nEnabling EXPERIMENTAL global controller and overlay..."); spdlog::warn("GlosSI not launched via Steam.\nEnabling EXPERIMENTAL global controller and overlay...");
if (Settings::common.standaloneModeGameId == L"") { if (Settings::common.standaloneModeGameId == L"") {
spdlog::error("No game id set for standalone mode. Controller will use desktop-config!"); spdlog::error("No game id set for standalone mode. Controller will use desktop-config!");
} }
SetEnvironmentVariable(L"SteamAppId", L"0"); SetEnvironmentVariable(L"SteamAppId", L"0");
SetEnvironmentVariable(L"SteamClientLaunch", L"0"); SetEnvironmentVariable(L"SteamClientLaunch", L"0");
SetEnvironmentVariable(L"SteamEnv", L"1"); 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"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"SteamGamepadUI", Settings::common.standaloneUseGamepadUI ? L"1" : L"0");
SetEnvironmentVariable(L"SteamGameId", Settings::common.standaloneModeGameId.c_str()); SetEnvironmentVariable(L"SteamGameId", Settings::common.standaloneModeGameId.c_str());
SetEnvironmentVariable(L"SteamOverlayGameId", Settings::common.standaloneModeGameId.c_str()); SetEnvironmentVariable(L"SteamOverlayGameId", Settings::common.standaloneModeGameId.c_str());
SetEnvironmentVariable(L"EnableConfiguratorSupport", L"15"); SetEnvironmentVariable(L"EnableConfiguratorSupport", L"15");
SetEnvironmentVariable(L"SteamStreamingForceWindowedD3D9", L"1"); SetEnvironmentVariable(L"SteamStreamingForceWindowedD3D9", L"1");
if (Settings::common.standaloneUseGamepadUI) { if (Settings::common.standaloneUseGamepadUI) {
system("start steam://open/bigpicture"); system("start steam://open/bigpicture");
auto steamwindow = FindWindow(L"Steam Big Picture Mode", nullptr); auto steamwindow = FindWindow(L"Steam Big Picture Mode", nullptr);
auto timer = sf::Clock{}; auto timer = sf::Clock{};
@ -94,22 +91,21 @@ int SteamTarget::run()
} }
Sleep(6000); // DIRTY HACK to wait until BPM (GamepadUI) is initialized Sleep(6000); // DIRTY HACK to wait until BPM (GamepadUI) is initialized
// TODO: find way to force BPM even if BPM is not active // TODO: find way to force BPM even if BPM is not active
LoadLibrary((getSteamPath() / "GameOverlayRenderer64.dll").wstring().c_str()); LoadLibrary((steam_path_ / "GameOverlayRenderer64.dll").wstring().c_str());
// Overlay switches back to desktop one, once BPM is closed... Disable closing BPM for now. // 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 // TODO: find way to force BPM even if BPM is not active
// closeBPM = true; // closeBPM = true;
closeBPMTimer.restart(); closeBPMTimer.restart();
} }
else { else {
LoadLibrary( (getSteamPath() / "GameOverlayRenderer64.dll").wstring().c_str()); LoadLibrary((steam_path_ / "GameOverlayRenderer64.dll").wstring().c_str());
} }
window_.setClickThrough(true); window_.setClickThrough(true);
if (!overlay_.expired()) if (!overlay_.expired())
overlay_.lock()->setEnabled(false); overlay_.lock()->setEnabled(false);
steam_overlay_present_ = true; steam_overlay_present_ = true;
} }
else { else {
spdlog::info("Steam-overlay detected."); spdlog::info("Steam-overlay detected.");
@ -130,7 +126,7 @@ int SteamTarget::run()
} }
#endif #endif
} }
getXBCRebindingEnabled(); util::steam::getXBCRebindingEnabled(steam_path_, steam_user_id_);
run_ = true; run_ = true;
@ -145,29 +141,7 @@ int SteamTarget::run()
keepControllerConfig(true); keepControllerConfig(true);
#ifdef _WIN32 const auto tray = createTrayMenu();
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;
}});
server_.run(); server_.run();
@ -176,9 +150,9 @@ int SteamTarget::run()
overlayHotkeyWorkaround(); overlayHotkeyWorkaround();
window_.update(); window_.update();
if (closeBPM && closeBPMTimer.getElapsedTime().asSeconds() >= 3) { if (closeBPM && closeBPMTimer.getElapsedTime().asSeconds() >= 3) {
system("start steam://close/bigpicture"); system("start steam://close/bigpicture");
closeBPM = false; closeBPM = false;
} }
// Wait on shutdown; User might get confused if window closes to fast if anything with launchApp get's borked. // 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(); launcher_.update();
} }
} }
tray.exit(); tray->exit();
server_.stop(); server_.stop();
#ifdef _WIN32 #ifdef _WIN32
@ -290,154 +264,11 @@ void SteamTarget::focusWindow(WindowHandle hndl)
#endif #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<std::string> 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<tyti::vdf::basic_object<char>> 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<std::string> 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<std::string> 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<tyti::vdf::basic_object<char>> 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<std::string> 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) * The "magic" that keeps a controller-config forced (without hooking into Steam)
* *
* Hook into own process and detour "GetForegroundWindow" * 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 * Steam now doesn't detect application changes and keeps the game-specific input config without reverting to desktop-conf
*/ */
void SteamTarget::keepControllerConfig(bool keep) void SteamTarget::keepControllerConfig(bool keep)
@ -488,6 +319,34 @@ HWND SteamTarget::keepFgWindowHookFn()
} }
#endif #endif
std::unique_ptr<Tray::Tray> 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<Tray::Tray>("GlosSITarget", icon);
#else
auto tray = std::make_unique<Tray::Tray>("GlosSITarget", "ico.png");
#endif
tray->addEntry(Tray::Button{
"Quit", [this, &tray]() {
run_ = false;
}});
return tray;
}
void SteamTarget::overlayHotkeyWorkaround() void SteamTarget::overlayHotkeyWorkaround()
{ {
static bool pressed = false; static bool pressed = false;

@ -26,13 +26,17 @@ limitations under the License.
#include <subhook.h> #include <subhook.h>
#endif #endif
#include <filesystem>
#include "AppLauncher.h" #include "AppLauncher.h"
#include "Overlay.h" #include "Overlay.h"
#include "HttpServer.h" #include "HttpServer.h"
#include "../common/steam_util.h"
#include <filesystem> namespace Tray {
class Tray;
}
class SteamTarget { class SteamTarget {
public: public:
explicit SteamTarget(); explicit SteamTarget();
@ -42,15 +46,9 @@ class SteamTarget {
void onOverlayChanged(bool overlay_open); void onOverlayChanged(bool overlay_open);
void toggleGlossiOverlay(); void toggleGlossiOverlay();
void focusWindow(WindowHandle hndl); void focusWindow(WindowHandle hndl);
std::filesystem::path getSteamPath() const;
std::wstring getSteamUserId() const;
std::filesystem::path steam_path_ = getSteamPath(); std::filesystem::path steam_path_ = util::steam::getSteamPath();
std::wstring steam_user_id_ = getSteamUserId(); std::wstring steam_user_id_ = util::steam::getSteamUserId();
std::vector<std::string> getOverlayHotkey();
std::vector<std::string> getScreenshotHotkey();
bool getXBCRebindingEnabled();
bool steam_overlay_present_ = false; bool steam_overlay_present_ = false;
@ -65,6 +63,8 @@ class SteamTarget {
static inline HWND last_real_hwnd_ = nullptr; static inline HWND last_real_hwnd_ = nullptr;
#endif #endif
std::unique_ptr<Tray::Tray> createTrayMenu();
/* /*
* Run once per frame * Run once per frame
* detects steam configured overlay hotkey, and simulates key presses to window * detects steam configured overlay hotkey, and simulates key presses to window
@ -74,7 +74,7 @@ class SteamTarget {
void overlayHotkeyWorkaround(); void overlayHotkeyWorkaround();
bool run_ = false; bool run_ = false;
std::vector<std::string> overlay_hotkey_ = getOverlayHotkey(); std::vector<std::string> overlay_hotkey_ = util::steam::getOverlayHotkey(steam_path_, steam_user_id_);
#ifdef _WIN32 #ifdef _WIN32
HidHide hidhide_; HidHide hidhide_;
@ -94,9 +94,4 @@ class SteamTarget {
bool delayed_shutdown_ = false; bool delayed_shutdown_ = false;
sf::Clock delay_shutdown_clock_; 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 ";
}; };

@ -3,7 +3,7 @@
!define APP_NAME "GlosSI" !define APP_NAME "GlosSI"
!define COMP_NAME "Peter Repukat - Flatspotsoftware" !define COMP_NAME "Peter Repukat - Flatspotsoftware"
!define WEB_SITE "https://glossi.flatspot.pictures/" !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 COPYRIGHT "Peter Repukat - FlatspotSoftware © 2017-2022"
!define DESCRIPTION "SteamInput compatibility tool" !define DESCRIPTION "SteamInput compatibility tool"
!define INSTALLER_NAME "GlosSI-Installer.exe" !define INSTALLER_NAME "GlosSI-Installer.exe"
@ -191,44 +191,3 @@ DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}" DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
SectionEnd SectionEnd

@ -15,11 +15,13 @@ limitations under the License.
*/ */
#pragma once #pragma once
#define SPDLOG_WCHAR_TO_UTF8_SUPPORT
#define SPDLOG_WCHAR_FILENAMES
#include <spdlog/spdlog.h>
#include <fstream> #include <fstream>
#include <regex> #include <regex>
#include <string> #include <string>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#ifdef WIN32 #ifdef WIN32
#define NOMINMAX #define NOMINMAX
@ -32,269 +34,280 @@ limitations under the License.
namespace Settings { namespace Settings {
inline struct Launch { inline struct Launch {
bool launch = false; bool launch = false;
std::wstring launchPath; std::wstring launchPath;
std::wstring launchAppArgs; std::wstring launchAppArgs;
bool closeOnExit = true; bool closeOnExit = true;
bool waitForChildProcs = true; bool waitForChildProcs = true;
bool isUWP = false; bool isUWP = false;
bool ignoreLauncher = true; bool ignoreLauncher = true;
bool killLauncher = false; bool killLauncher = false;
std::vector<std::wstring> launcherProcesses{}; std::vector<std::wstring> launcherProcesses{};
} launch; } launch;
inline struct Devices { inline struct Devices {
bool hideDevices = true; bool hideDevices = true;
bool realDeviceIds = false; bool realDeviceIds = false;
} devices; } devices;
inline struct Window { inline struct Window {
bool windowMode = false; bool windowMode = false;
int maxFps = 0; int maxFps = 0;
float scale = 0.f; float scale = 0.f;
bool disableOverlay = false; bool disableOverlay = false;
bool hideAltTab = true; bool hideAltTab = true;
bool disableGlosSIOverlay = false; bool disableGlosSIOverlay = false;
} window; } window;
inline struct Controller { inline struct Controller {
int maxControllers = 1; int maxControllers = 1;
bool allowDesktopConfig = false; bool allowDesktopConfig = false;
bool emulateDS4 = false; bool emulateDS4 = false;
} controller; } controller;
inline struct Common { inline struct Common {
bool no_uwp_overlay = false; bool no_uwp_overlay = false;
bool disable_watchdog = false; bool disable_watchdog = false;
bool extendedLogging = false; bool extendedLogging = false;
std::wstring name; std::wstring name;
std::wstring icon; std::wstring icon;
int version; int version;
std::wstring steamPath; std::wstring steamPath;
std::wstring steamUserId; std::wstring steamUserId;
std::wstring standaloneModeGameId; /* = L"12605636929694728192"; */ std::wstring standaloneModeGameId; /* = L"12605636929694728192"; */
bool standaloneUseGamepadUI = false; bool standaloneUseGamepadUI = false;
} common; bool allowStandAlone = true;
} common;
inline std::filesystem::path settings_path_ = "";
inline const std::map<std::wstring, std::function<void()>> cmd_args = {
inline bool checkIsUwp(const std::wstring& launch_path) {L"-disableuwpoverlay", [&]() { common.no_uwp_overlay = true; }},
{ {L"-disablewatchdog", [&]() { common.disable_watchdog = true; }},
if (launch_path.find(L"://") != std::wstring::npos) { {L"-ignorelauncher", [&]() { launch.ignoreLauncher = true; }},
return false; {L"-window", [&]() { window.windowMode = true; }},
} {L"-extendedLogging", [&]() { common.extendedLogging = true; }},
std::wsmatch m; {L"-standaloneUseGamepadUI", [&]() { common.standaloneUseGamepadUI = true; }},
if (!std::regex_search(launch_path, m, std::wregex(L"^.{1,5}:"))) { {L"-disallowStandAlone", [&]() { common.allowStandAlone = false; }},
return true; };
}
return 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 #ifdef WIN32
inline bool isWin10 = false; inline bool isWin10 = false;
inline void checkWinVer() inline void checkWinVer()
{ {
auto VN = util::win::GetRealOSVersion(); auto VN = util::win::GetRealOSVersion();
isWin10 = VN.dwBuildNumber < 22000; isWin10 = VN.dwBuildNumber < 22000;
if (isWin10) { if (isWin10) {
spdlog::info("Running on Windows 10; Winver: {}.{}.{}", VN.dwMajorVersion, VN.dwMinorVersion, VN.dwBuildNumber); spdlog::info("Running on Windows 10; Winver: {}.{}.{}", VN.dwMajorVersion, VN.dwMinorVersion, VN.dwBuildNumber);
} }
else { else {
spdlog::info("Running on Windows 11; Winver: {}.{}.{}", VN.dwMajorVersion, VN.dwMinorVersion, VN.dwBuildNumber); spdlog::info("Running on Windows 11; Winver: {}.{}.{}", VN.dwMajorVersion, VN.dwMinorVersion, VN.dwBuildNumber);
} }
} }
#endif #endif
inline void Parse(const nlohmann::basic_json<>& json) inline void Parse(const nlohmann::basic_json<>& json)
{ {
constexpr auto safeParseValue = []<typename T>(const auto & object, const auto & key, T & value) { constexpr auto safeParseValue = []<typename T>(const auto & object, const auto & key, T & value) {
try { try {
if (object.is_null() || object.empty() || object.at(key).empty() || object.at(key).is_null()) { if (object.is_null() || object.empty() || object.at(key).empty() || object.at(key).is_null()) {
return; return;
} }
if constexpr (std::is_same_v<T, std::wstring>) { if constexpr (std::is_same_v<T, std::wstring>) {
value = util::string::to_wstring(object[key].get<std::string>()); value = util::string::to_wstring(object[key].get<std::string>());
} }
else { else {
value = object[key]; value = object[key];
} }
} }
catch (const nlohmann::json::exception& e) { catch (const nlohmann::json::exception& e) {
e.id == 403 if constexpr (std::is_same_v<T, std::wstring>) {
? spdlog::trace("Err parsing \"{}\"; {}", key, e.what()) e.id == 403
: spdlog::warn("Err parsing \"{}\"; {}", key, e.what()); ? spdlog::trace("Err parsing \"{}\"; {}; Using default: {}", key, e.what(), util::string::to_string(value))
} : spdlog::warn("Err parsing \"{}\"; {}", key, e.what());
catch (const std::exception& e) { }
spdlog::warn("Err parsing \"{}\"; {}", key, e.what()); else
} {
}; e.id == 403
? spdlog::trace("Err parsing \"{}\"; {}; Using default: {}", key, e.what(), value)
int version; : spdlog::warn("Err parsing \"{}\"; {}", key, e.what());
safeParseValue(json, "version", version); }
if (version != 1) { // TODO: versioning stuff }
spdlog::warn("Config version doesn't match application version."); catch (const std::exception& e) {
} spdlog::warn("Err parsing \"{}\"; {}", key, e.what());
}
// 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()) { int version;
safeParseValue(launchconf, "launch", launch.launch); safeParseValue(json, "version", version);
safeParseValue(launchconf, "launchPath", launch.launchPath); if (version != 1) { // TODO: versioning stuff
safeParseValue(launchconf, "launchAppArgs", launch.launchAppArgs); spdlog::warn("Config version doesn't match application version.");
safeParseValue(launchconf, "closeOnExit", launch.closeOnExit); }
safeParseValue(launchconf, "waitForChildProcs", launch.waitForChildProcs);
safeParseValue(launchconf, "killLauncher", launch.killLauncher); // TODO: make this as much generic as fits in about the same amount of code if one would parse every value separately.
safeParseValue(launchconf, "ignoreLauncher", launch.ignoreLauncher); try {
if (const auto launchconf = json["launch"]; !launchconf.is_null() && !launchconf.empty() && launchconf.is_object()) {
if (auto launcherProcs = launchconf["launcherProcesses"]; safeParseValue(launchconf, "launch", launch.launch);
!launcherProcs.is_null() && !launcherProcs.empty() && launcherProcs.is_array()) { safeParseValue(launchconf, "launchPath", launch.launchPath);
launch.launcherProcesses.clear(); safeParseValue(launchconf, "launchAppArgs", launch.launchAppArgs);
launch.launcherProcesses.reserve(launcherProcs.size()); safeParseValue(launchconf, "closeOnExit", launch.closeOnExit);
for (auto& proc : launcherProcs) { safeParseValue(launchconf, "waitForChildProcs", launch.waitForChildProcs);
launch.launcherProcesses.push_back(util::string::to_wstring(proc)); safeParseValue(launchconf, "killLauncher", launch.killLauncher);
} safeParseValue(launchconf, "ignoreLauncher", launch.ignoreLauncher);
}
} if (const auto launcherProcs = launchconf["launcherProcesses"];
!launcherProcs.is_null() && !launcherProcs.empty() && launcherProcs.is_array()) {
if (auto devconf = json["devices"]; !devconf.is_null() && !devconf.empty() && devconf.is_object()) { launch.launcherProcesses.clear();
safeParseValue(devconf, "hideDevices", devices.hideDevices); launch.launcherProcesses.reserve(launcherProcs.size());
safeParseValue(devconf, "realDeviceIds", devices.realDeviceIds); for (auto& proc : launcherProcs) {
} launch.launcherProcesses.push_back(util::string::to_wstring(proc));
}
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); if (const auto devconf = json["devices"]; !devconf.is_null() && !devconf.empty() && devconf.is_object()) {
safeParseValue(winconf, "disableOverlay", window.disableOverlay); safeParseValue(devconf, "hideDevices", devices.hideDevices);
safeParseValue(winconf, "hideAltTab", window.hideAltTab); safeParseValue(devconf, "realDeviceIds", devices.realDeviceIds);
safeParseValue(winconf, "disableGlosSIOverlay", window.disableGlosSIOverlay); }
}
if (const auto winconf = json["window"]; !winconf.is_null() && !winconf.empty() && winconf.is_object()) {
if (auto controllerConf = json["controller"]; !controllerConf.is_null() && !controllerConf.empty() && controllerConf.is_object()) { safeParseValue(winconf, "windowMode", window.windowMode);
safeParseValue(controllerConf, "maxControllers", controller.maxControllers); safeParseValue(winconf, "maxFps", window.maxFps);
safeParseValue(controllerConf, "allowDesktopConfig", controller.allowDesktopConfig); safeParseValue(winconf, "scale", window.scale);
safeParseValue(controllerConf, "emulateDS4", controller.emulateDS4); safeParseValue(winconf, "disableOverlay", window.disableOverlay);
} safeParseValue(winconf, "hideAltTab", window.hideAltTab);
safeParseValue(json, "extendedLogging", common.extendedLogging); safeParseValue(winconf, "disableGlosSIOverlay", window.disableGlosSIOverlay);
safeParseValue(json, "name", common.name); }
safeParseValue(json, "icon", common.icon);
safeParseValue(json, "version", common.version); if (const auto controllerConf = json["controller"]; !controllerConf.is_null() && !controllerConf.empty() && controllerConf.is_object()) {
safeParseValue(controllerConf, "maxControllers", controller.maxControllers);
safeParseValue(json, "steamPath", common.steamPath); safeParseValue(controllerConf, "allowDesktopConfig", controller.allowDesktopConfig);
safeParseValue(json, "steamUserId", common.steamUserId); safeParseValue(controllerConf, "emulateDS4", controller.emulateDS4);
}
safeParseValue(json, "standaloneModeGameId", common.standaloneModeGameId); safeParseValue(json, "extendedLogging", common.extendedLogging);
safeParseValue(json, "standaloneUseGamepadUI", common.standaloneUseGamepadUI); safeParseValue(json, "name", common.name);
} safeParseValue(json, "icon", common.icon);
catch (const nlohmann::json::exception& e) { safeParseValue(json, "version", common.version);
spdlog::warn("Err parsing config: {}", e.what());
} safeParseValue(json, "steamPath", common.steamPath);
catch (const std::exception& e) { safeParseValue(json, "steamUserId", common.steamUserId);
spdlog::warn("Err parsing config: {}", e.what());
} safeParseValue(json, "standaloneModeGameId", common.standaloneModeGameId);
if (launch.launch) { safeParseValue(json, "standaloneUseGamepadUI", common.standaloneUseGamepadUI);
launch.isUWP = checkIsUwp(launch.launchPath); }
} catch (const nlohmann::json::exception& e) {
} spdlog::warn("Err parsing config: {}", e.what());
}
inline void Parse(const std::vector<std::wstring>& args) catch (const std::exception& e) {
{ spdlog::warn("Err parsing config: {}", e.what());
std::wstring configName; }
for (const auto& arg : args) { if (launch.launch) {
if (arg.empty()) { launch.isUWP = checkIsUwp(launch.launchPath);
continue; }
} }
if (arg == L"-disableuwpoverlay") {
common.no_uwp_overlay = true; inline void Parse(const std::vector<std::wstring>& args)
} {
else if (arg == L"-disablewatchdog") { std::wstring configName;
common.disable_watchdog = true; for (const auto& arg : args) {
} if (arg.empty()) {
else if (arg == L"-ignorelauncher") { continue;
launch.ignoreLauncher = true; }
} if (cmd_args.contains(arg))
else if (arg == L"-window") { {
window.windowMode = true; cmd_args.at(arg)();
} }
else { else {
configName += L" " + std::wstring(arg.begin(), arg.end()); configName += L" " + std::wstring(arg.begin(), arg.end());
} }
} }
if (!configName.empty()) { if (!configName.empty()) {
if (configName[0] == L' ') { if (configName[0] == L' ') {
configName.erase(configName.begin()); configName.erase(configName.begin());
} }
if (!configName.ends_with(L".json")) { if (!configName.ends_with(L".json")) {
configName += L".json"; configName += L".json";
} }
} }
auto path = util::path::getDataDirPath(); auto path = util::path::getDataDirPath();
if (!configName.empty()) { if (!configName.empty()) {
path /= "Targets"; path /= "Targets";
path /= configName; path /= configName;
} }
else { else {
spdlog::info("No config file specified, using default"); spdlog::info("No config file specified, using default");
path /= "default.json"; path /= "default.json";
} }
std::ifstream json_file; std::ifstream json_file;
json_file.open(path); json_file.open(path);
if (!json_file.is_open()) { if (!json_file.is_open()) {
spdlog::error(L"Couldn't open settings file {}", path.wstring()); spdlog::error(L"Couldn't open settings file {}", path.wstring());
spdlog::debug(L"Using sane defaults..."); spdlog::debug(L"Using sane defaults...");
return; return;
} }
settings_path_ = path; settings_path_ = path;
const auto& json = nlohmann::json::parse(json_file); const auto& json = nlohmann::json::parse(json_file);
Parse(json); Parse(json);
spdlog::debug("Read config file \"{}\"; config: {}", path.string(), json.dump()); spdlog::debug("Read config file \"{}\"; config: {}", path.string(), json.dump());
json_file.close(); json_file.close();
} }
inline nlohmann::json toJson() inline nlohmann::json toJson()
{ {
nlohmann::json json; nlohmann::json json;
json["version"] = 1; json["version"] = 1;
json["launch"]["launch"] = launch.launch; json["launch"]["launch"] = launch.launch;
json["launch"]["launchPath"] = launch.launchPath; json["launch"]["launchPath"] = launch.launchPath;
json["launch"]["launchAppArgs"] = launch.launchAppArgs; json["launch"]["launchAppArgs"] = launch.launchAppArgs;
json["launch"]["closeOnExit"] = launch.closeOnExit; json["launch"]["closeOnExit"] = launch.closeOnExit;
json["launch"]["waitForChildProcs"] = launch.waitForChildProcs; json["launch"]["waitForChildProcs"] = launch.waitForChildProcs;
json["devices"]["hideDevices"] = devices.hideDevices; json["devices"]["hideDevices"] = devices.hideDevices;
json["devices"]["realDeviceIds"] = devices.realDeviceIds; json["devices"]["realDeviceIds"] = devices.realDeviceIds;
json["window"]["windowMode"] = window.windowMode; json["window"]["windowMode"] = window.windowMode;
json["window"]["maxFps"] = window.maxFps; json["window"]["maxFps"] = window.maxFps;
json["window"]["scale"] = window.scale; json["window"]["scale"] = window.scale;
json["window"]["disableOverlay"] = window.disableOverlay; json["window"]["disableOverlay"] = window.disableOverlay;
json["window"]["hideAltTab"] = window.hideAltTab; json["window"]["hideAltTab"] = window.hideAltTab;
json["controller"]["maxControllers"] = controller.maxControllers; json["controller"]["maxControllers"] = controller.maxControllers;
json["controller"]["allowDesktopConfig"] = controller.allowDesktopConfig; json["controller"]["allowDesktopConfig"] = controller.allowDesktopConfig;
json["controller"]["emulateDS4"] = controller.emulateDS4; json["controller"]["emulateDS4"] = controller.emulateDS4;
json["extendedLogging"] = common.extendedLogging; json["extendedLogging"] = common.extendedLogging;
json["name"] = common.name; json["name"] = common.name;
json["icon"] = common.icon; json["icon"] = common.icon;
json["version"] = common.version; json["version"] = common.version;
return json; return json;
} }
inline void StoreSettings() inline void StoreSettings()
{ {
const auto& json = toJson(); const auto& json = toJson();
std::ofstream json_file; std::ofstream json_file;
json_file.open(settings_path_); json_file.open(settings_path_);
if (!json_file.is_open()) { if (!json_file.is_open()) {
spdlog::error(L"Couldn't open settings file {}", settings_path_.wstring()); spdlog::error(L"Couldn't open settings file {}", settings_path_.wstring());
return; return;
} }
json_file << json.dump(4); json_file << json.dump(4);
json_file.close(); json_file.close();
} }
} // namespace Settings } // namespace Settings

@ -18,6 +18,8 @@ limitations under the License.
#include "util.h" #include "util.h"
#ifndef CONFIGAPP #ifndef CONFIGAPP
#define SPDLOG_WCHAR_TO_UTF8_SUPPORT
#define SPDLOG_WCHAR_FILENAMES
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "Settings.h" #include "Settings.h"

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.220531.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220531.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
@ -71,10 +72,10 @@
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;$(IncludePath)</IncludePath> <IncludePath>..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;..\deps\WinReg;..\deps\ValveFileVDF;$(IncludePath)</IncludePath>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;$(IncludePath)</IncludePath> <IncludePath>..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;..\deps\WinReg;..\deps\ValveFileVDF;$(IncludePath)</IncludePath>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
@ -138,6 +139,7 @@
<ClInclude Include="HidHide.h" /> <ClInclude Include="HidHide.h" />
<ClInclude Include="nlohmann_json_wstring.h" /> <ClInclude Include="nlohmann_json_wstring.h" />
<ClInclude Include="Settings.h" /> <ClInclude Include="Settings.h" />
<ClInclude Include="steam_util.h" />
<ClInclude Include="UnhookUtil.h" /> <ClInclude Include="UnhookUtil.h" />
<ClInclude Include="util.h" /> <ClInclude Include="util.h" />
</ItemGroup> </ItemGroup>
@ -147,5 +149,13 @@
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.220531.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220531.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup> </ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220531.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.220531.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220531.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.220531.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project> </Project>

@ -30,6 +30,9 @@
<ClInclude Include="HidHide.h"> <ClInclude Include="HidHide.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="steam_util.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="UnhookUtil.cpp"> <ClCompile Include="UnhookUtil.cpp">

@ -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 <spdlog/spdlog.h>
#include <WinReg/WinReg.hpp>
#include <vdf_parser.hpp>
#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<std::string> 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<tyti::vdf::basic_object<char>> 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<std::string> 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<std::string> 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<tyti::vdf::basic_object<char>> 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<std::string> 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";
}
}
}

@ -31,6 +31,8 @@ limitations under the License.
#include <filesystem> #include <filesystem>
#ifdef SPDLOG_H #ifdef SPDLOG_H
#define SPDLOG_WCHAR_TO_UTF8_SUPPORT
#define SPDLOG_WCHAR_FILENAMES
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#endif #endif
@ -158,6 +160,6 @@ namespace util {
return res; return res;
} }
} }
} }
#endif #endif
} }
Loading…
Cancel
Save