From 738803fa2efcbca1cbda21655e937a52a0695e57 Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Sun, 29 Jan 2023 16:00:06 +0100 Subject: [PATCH] Cleanup: consolidate utils and common code --- CEFInjectLib/CEFInject.cpp | 16 +- CEFInjectLib/CEFInject.h | 12 +- GlosSI.sln | 10 + GlosSIConfig/ExeImageProvider.h | 1 + GlosSIConfig/GlosSIConfig.vcxproj | 2 +- GlosSIConfig/GlosSIConfig.vcxproj.filters | 2 +- GlosSIConfig/Resource.rc | 24 +- GlosSIConfig/UIModel.cpp | 41 +-- GlosSIConfig/main.cpp | 31 +- GlosSITarget/AppLauncher.cpp | 24 +- GlosSITarget/DllInjector.h | 6 +- GlosSITarget/GlosSITarget.vcxproj | 8 +- GlosSITarget/GlosSITarget.vcxproj.filters | 22 +- GlosSITarget/HttpServer.cpp | 2 +- GlosSITarget/InputRedirector.cpp | 2 +- GlosSITarget/Overlay.cpp | 20 +- GlosSITarget/Resource.rc | 128 ++++++- GlosSITarget/Settings.h | 336 ------------------ GlosSITarget/SteamOverlayDetector.cpp | 2 +- GlosSITarget/SteamTarget.cpp | 3 +- GlosSITarget/SteamTarget.h | 2 +- GlosSITarget/TargetWindow.cpp | 2 +- GlosSITarget/UWPOverlayEnabler.h | 1 - GlosSITarget/UnhookUtil.h | 66 ---- GlosSITarget/main.cpp | 30 +- GlosSITarget/util.h | 76 ---- GlosSIWatchdog/GlosSIWatchdog.vcxproj | 4 +- GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters | 4 +- GlosSIWatchdog/dllmain.cpp | 29 +- Installer/Installer.nsi | 41 ++- UWPOverlayEnablerDLL/dllmain.cpp | 20 +- {GlosSITarget => common}/HidHide.cpp | 197 +++++----- {GlosSITarget => common}/HidHide.h | 10 +- common/Settings.h | 300 ++++++++++++++++ {GlosSITarget => common}/UnhookUtil.cpp | 19 +- common/UnhookUtil.h | 66 ++++ common/common.vcxproj | 151 ++++++++ common/common.vcxproj.filters | 42 +++ common/nlohmann_json_wstring.h | 36 ++ common/util.h | 163 +++++++++ 40 files changed, 1134 insertions(+), 817 deletions(-) delete mode 100644 GlosSITarget/Settings.h delete mode 100644 GlosSITarget/UnhookUtil.h delete mode 100644 GlosSITarget/util.h rename {GlosSITarget => common}/HidHide.cpp (78%) rename {GlosSITarget => common}/HidHide.h (97%) create mode 100644 common/Settings.h rename {GlosSITarget => common}/UnhookUtil.cpp (88%) create mode 100644 common/UnhookUtil.h create mode 100644 common/common.vcxproj create mode 100644 common/common.vcxproj.filters create mode 100644 common/nlohmann_json_wstring.h create mode 100644 common/util.h diff --git a/CEFInjectLib/CEFInject.cpp b/CEFInjectLib/CEFInject.cpp index c31d926..4270031 100644 --- a/CEFInjectLib/CEFInject.cpp +++ b/CEFInjectLib/CEFInject.cpp @@ -22,21 +22,7 @@ limitations under the License. #define _SSIZE_T_DEFINED #include // seems like a hack to me, but eh -#include -#include - -namespace nlohmann { - template <> - struct adl_serializer { - static void to_json(json& j, const std::wstring& str) { - j = std::wstring_convert>().to_bytes(str); - } - - static void from_json(const json& j, std::wstring& str) { - str = std::wstring_convert>().from_bytes(j.get()); - } - }; -} +#include "../common/nlohmann_json_wstring.h" namespace CEFInject { diff --git a/CEFInjectLib/CEFInject.h b/CEFInjectLib/CEFInject.h index 223fb65..fc077f6 100644 --- a/CEFInjectLib/CEFInject.h +++ b/CEFInjectLib/CEFInject.h @@ -23,10 +23,14 @@ namespace CEFInject { namespace internal { httplib::Client GetHttpClient(uint16_t port); + static inline uint16_t port_ = 8080; } - - bool CEFDebugAvailable(uint16_t port = 8080); - std::vector AvailableTabs(uint16_t port = 8080); - nlohmann::json InjectJs(const std::wstring& tabname, const std::wstring& js, uint16_t port = 8080); + inline void setPort(uint16_t port) + { + internal::port_ = port; + } + bool CEFDebugAvailable(uint16_t port = internal::port_); + std::vector AvailableTabs(uint16_t port = internal::port_); + nlohmann::json InjectJs(const std::wstring& tabname, const std::wstring& js, uint16_t port = internal::port_); } \ No newline at end of file diff --git a/GlosSI.sln b/GlosSI.sln index 8102453..736ba44 100644 --- a/GlosSI.sln +++ b/GlosSI.sln @@ -16,6 +16,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GlosSIWatchdog", "GlosSIWat EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CEFInjectLib", "CEFInjectLib\CEFInjectLib.vcxproj", "{74FBA967-AB7E-43EA-B561-3F4821954B3B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxproj", "{DFED4B7E-D04C-442B-BB48-5B6068A6B31B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -62,6 +64,14 @@ Global {74FBA967-AB7E-43EA-B561-3F4821954B3B}.Release|x64.Build.0 = Release|x64 {74FBA967-AB7E-43EA-B561-3F4821954B3B}.Release|x86.ActiveCfg = Release|Win32 {74FBA967-AB7E-43EA-B561-3F4821954B3B}.Release|x86.Build.0 = Release|Win32 + {DFED4B7E-D04C-442B-BB48-5B6068A6B31B}.Debug|x64.ActiveCfg = Debug|x64 + {DFED4B7E-D04C-442B-BB48-5B6068A6B31B}.Debug|x64.Build.0 = Debug|x64 + {DFED4B7E-D04C-442B-BB48-5B6068A6B31B}.Debug|x86.ActiveCfg = Debug|Win32 + {DFED4B7E-D04C-442B-BB48-5B6068A6B31B}.Debug|x86.Build.0 = Debug|Win32 + {DFED4B7E-D04C-442B-BB48-5B6068A6B31B}.Release|x64.ActiveCfg = Release|x64 + {DFED4B7E-D04C-442B-BB48-5B6068A6B31B}.Release|x64.Build.0 = Release|x64 + {DFED4B7E-D04C-442B-BB48-5B6068A6B31B}.Release|x86.ActiveCfg = Release|Win32 + {DFED4B7E-D04C-442B-BB48-5B6068A6B31B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GlosSIConfig/ExeImageProvider.h b/GlosSIConfig/ExeImageProvider.h index f712896..de8d0bf 100644 --- a/GlosSIConfig/ExeImageProvider.h +++ b/GlosSIConfig/ExeImageProvider.h @@ -2,6 +2,7 @@ #include #include #include +#include class ExeImageProvider : public QQuickImageProvider { public: ExeImageProvider() diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj index 55a1b71..4fab583 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj +++ b/GlosSIConfig/GlosSIConfig.vcxproj @@ -136,7 +136,7 @@ - + diff --git a/GlosSIConfig/GlosSIConfig.vcxproj.filters b/GlosSIConfig/GlosSIConfig.vcxproj.filters index fc4e559..17fbafe 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj.filters +++ b/GlosSIConfig/GlosSIConfig.vcxproj.filters @@ -37,7 +37,7 @@ Source Files - + Source Files diff --git a/GlosSIConfig/Resource.rc b/GlosSIConfig/Resource.rc index 9062346..b01172c 100644 --- a/GlosSIConfig/Resource.rc +++ b/GlosSIConfig/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,1,2012005004400 - PRODUCTVERSION 0,1,1,2012005004400 + FILEVERSION 0,1,2,0010004309958 + PRODUCTVERSION 0,1,2,0010004309958 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.1.2-12-g5fe44d0" + VALUE "FileVersion", "0.1.2.0-10-g43c9958" VALUE "InternalName", "GlosSIConfig" VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSIConfig.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.1.1.2-12-g5fe44d0" + VALUE "ProductVersion", "0.1.2.0-10-g43c9958" END END BLOCK "VarFileInfo" @@ -1503,6 +1503,22 @@ IDI_ICON1 ICON "..\GlosSI_Icon.ico" + + + + + + + + + + + + + + + + diff --git a/GlosSIConfig/UIModel.cpp b/GlosSIConfig/UIModel.cpp index 61edb12..62c86aa 100644 --- a/GlosSIConfig/UIModel.cpp +++ b/GlosSIConfig/UIModel.cpp @@ -32,30 +32,18 @@ limitations under the License. #ifdef _WIN32 #include "UWPFetch.h" #include -#include #endif #include "ExeImageProvider.h" #include "../version.hpp" -#include "../../GlosSITarget/UnhookUtil.h" +#include "../common/UnhookUtil.h" +#include "../common/util.h" UIModel::UIModel() : QObject(nullptr) { - wchar_t* localAppDataFolder; - std::filesystem::path path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - path = std::filesystem::path(localAppDataFolder).parent_path(); - } - - path /= "Roaming"; - path /= "GlosSI"; - if (!std::filesystem::exists(path)) - std::filesystem::create_directories(path); + auto path = util::path::getDataDirPath(); qDebug() << "Version: " << getVersionString(); @@ -395,17 +383,8 @@ void UIModel::updateCheck() QVariantMap UIModel::getDefaultConf() const { - wchar_t* localAppDataFolder; - std::filesystem::path path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - path = std::filesystem::path(localAppDataFolder).parent_path(); - } + auto path = util::path::getDataDirPath(); - path /= "Roaming"; - path /= "GlosSI"; path /= "default.json"; QJsonObject defaults = { @@ -481,16 +460,8 @@ QVariantMap UIModel::getDefaultConf() const void UIModel::saveDefaultConf(QVariantMap conf) const { - wchar_t* localAppDataFolder; - std::filesystem::path path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - path = std::filesystem::path(localAppDataFolder).parent_path(); - } - path /= "Roaming"; - path /= "GlosSI"; + auto path = util::path::getDataDirPath(); + path /= "default.json"; QFile file(path); diff --git a/GlosSIConfig/main.cpp b/GlosSIConfig/main.cpp index ba303d3..1ef2e1b 100644 --- a/GlosSIConfig/main.cpp +++ b/GlosSIConfig/main.cpp @@ -22,15 +22,17 @@ limitations under the License. #include #include +#include "../common/util.h" + #ifdef _WIN32 #include #include #include -#include #pragma comment(lib, "Dwmapi.lib") #include "ExeImageProvider.h" #endif + #include "UIModel.h" #include "WinEventFilter.h" @@ -90,19 +92,7 @@ void myMessageHandler(QtMsgType type, const QMessageLogContext&, const QString& break; } - wchar_t* localAppDataFolder; - std::filesystem::path path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - path = std::filesystem::path(localAppDataFolder).parent_path(); - } - - path /= "Roaming"; - path /= "GlosSI"; - if (!std::filesystem::exists(path)) - std::filesystem::create_directories(path); + auto path = util::path::getDataDirPath(); QFile outFile(QString::fromStdWString(path) + "/glossiconfig.log"); outFile.open(QIODevice::WriteOnly | QIODevice::Append); @@ -120,18 +110,7 @@ int main(int argc, char* argv[]) #endif if (argc < 3) { - wchar_t* localAppDataFolder; - std::filesystem::path path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - path = std::filesystem::path(localAppDataFolder).parent_path(); - } - path /= "Roaming"; - path /= "GlosSI"; - if (!std::filesystem::exists(path)) - std::filesystem::create_directories(path); + auto path = util::path::getDataDirPath(); QFile outFile(QString::fromStdWString(path) + "/glossiconfig.log"); outFile.open(QIODevice::WriteOnly); diff --git a/GlosSITarget/AppLauncher.cpp b/GlosSITarget/AppLauncher.cpp index 140a28d..30f5fc1 100644 --- a/GlosSITarget/AppLauncher.cpp +++ b/GlosSITarget/AppLauncher.cpp @@ -27,13 +27,13 @@ limitations under the License. #pragma comment(lib, "Shell32.lib") #endif -#include "Settings.h" +#include "..\common\Settings.h" #include #include "Overlay.h" -#include "UnhookUtil.h" -#include "util.h" +#include "../common/UnhookUtil.h" +#include "../common/util.h" AppLauncher::AppLauncher( std::vector& process_hwnds, @@ -75,10 +75,10 @@ void AppLauncher::launchApp(const std::wstring& path, const std::wstring& args) if (ImGui::Begin("Launched Processes")) { ImGui::BeginChild("Inner##LaunchedProcs", {0.f, ImGui::GetItemRectSize().y - 64}, true); std::ranges::for_each(pids_, [](DWORD pid) { - ImGui::Text("%s | %d", std::wstring_convert>().to_bytes(glossi_util::GetProcName(pid)).c_str(), pid); + ImGui::Text("%s | %d", util::string::to_string(util::win::process::GetProcName(pid)).c_str(), pid); ImGui::SameLine(); if (ImGui::Button((" Kill ##" + std::to_string(pid)).c_str())) { - glossi_util::KillProcess(pid); + util::win::process::KillProcess(pid); } }); ImGui::EndChild(); @@ -101,7 +101,7 @@ void AppLauncher::update() getChildPids(pids_[0]); } if (!IsProcessRunning(pids_[0])) { - spdlog::info(L"Launched App \"{}\" with PID \"{}\" died", glossi_util::GetProcName(pids_[0]), pids_[0]); + spdlog::info(L"Launched App \"{}\" with PID \"{}\" died", util::win::process::GetProcName(pids_[0]), pids_[0]); if (Settings::launch.closeOnExit && !Settings::launch.waitForChildProcs && Settings::launch.launch) { spdlog::info("Configured to close on exit. Shutting down..."); shutdown_(); @@ -117,12 +117,12 @@ void AppLauncher::update() } const auto running = IsProcessRunning(pid); if (!running) - spdlog::trace(L"Child process \"{}\" with PID \"{}\" died", glossi_util::GetProcName(pid), pid); + spdlog::trace(L"Child process \"{}\" with PID \"{}\" died", util::win::process::GetProcName(pid), pid); return !running; }); auto filtered_pids = pids_ | std::ranges::views::filter([](DWORD pid) { - return std::ranges::find(Settings::launch.launcherProcesses, glossi_util::GetProcName(pid)) == Settings::launch.launcherProcesses.end(); + return std::ranges::find(Settings::launch.launcherProcesses, util::win::process::GetProcName(pid)) == Settings::launch.launcherProcesses.end(); }); if (has_extra_launchers_ && !filtered_pids.empty()) { launcher_has_launched_game_ = true; @@ -169,7 +169,7 @@ std::vector AppLauncher::launchedPids() [](DWORD pid) { return std::ranges::find( Settings::launch.launcherProcesses, - glossi_util::GetProcName(pid)) == Settings::launch.launcherProcesses.end(); + util::win::process::GetProcName(pid)) == Settings::launch.launcherProcesses.end(); })) { res.push_back(pid); } @@ -217,7 +217,7 @@ void AppLauncher::getChildPids(DWORD parent_pid) if (pe.th32ParentProcessID == parent_pid) { if (std::ranges::find(pids_, pe.th32ProcessID) == pids_.end()) { if (Settings::common.extendedLogging) { - spdlog::info(L"Found new child process \"{}\" with PID \"{}\"", glossi_util::GetProcName(pe.th32ProcessID), pe.th32ProcessID); + spdlog::info(L"Found new child process \"{}\" with PID \"{}\"", util::win::process::GetProcName(pe.th32ProcessID), pe.th32ProcessID); } pids_.push_back(pe.th32ProcessID); getChildPids(pe.th32ProcessID); @@ -263,7 +263,7 @@ void AppLauncher::getProcessHwnds() #ifdef _WIN32 bool AppLauncher::findLauncherPids() { - if (const auto pid = glossi_util::PidByName(L"EpicGamesLauncher.exe")) { + if (const auto pid = util::win::process::PidByName(L"EpicGamesLauncher.exe")) { spdlog::debug("Found EGS-Launcher running"); pids_.push_back(pid); return true; @@ -417,7 +417,7 @@ void AppLauncher::launchURL(const std::wstring& url, const std::wstring& args, c spdlog::debug("Epic Games launch; Couldn't find egs launcher PID"); pid_mutex_.lock(); - const auto pid = glossi_util::PidByName(L"EpicGamesLauncher.exe"); + const auto pid = util::win::process::PidByName(L"EpicGamesLauncher.exe"); if (!findLauncherPids()) { spdlog::debug("Did not find EGS-Launcher not running, retrying later..."); } diff --git a/GlosSITarget/DllInjector.h b/GlosSITarget/DllInjector.h index 09e4b50..764d181 100644 --- a/GlosSITarget/DllInjector.h +++ b/GlosSITarget/DllInjector.h @@ -1,10 +1,8 @@ #pragma once -#include -#include #include -#include "util.h" +#include "../common/util.h" namespace DllInjector { @@ -112,7 +110,7 @@ inline bool findModule(DWORD pid, std::wstring& lib_path, HMODULE& hMod) inline void injectDllInto(std::filesystem::path dllPath, const std::wstring& processName) { if (std::filesystem::exists(dllPath)) { - const auto explorer_pid = glossi_util::PidByName(processName); + const auto explorer_pid = util::win::process::PidByName(processName); if (explorer_pid != 0) { if (DllInjector::TakeDebugPrivilege()) { // No need to eject, as the dll is self-ejecting. diff --git a/GlosSITarget/GlosSITarget.vcxproj b/GlosSITarget/GlosSITarget.vcxproj index 4970649..a11bfc3 100644 --- a/GlosSITarget/GlosSITarget.vcxproj +++ b/GlosSITarget/GlosSITarget.vcxproj @@ -168,6 +168,8 @@ + + @@ -187,7 +189,6 @@ - @@ -195,7 +196,6 @@ - @@ -204,7 +204,6 @@ - @@ -213,13 +212,10 @@ - - - diff --git a/GlosSITarget/GlosSITarget.vcxproj.filters b/GlosSITarget/GlosSITarget.vcxproj.filters index b2bcd12..ddb734e 100644 --- a/GlosSITarget/GlosSITarget.vcxproj.filters +++ b/GlosSITarget/GlosSITarget.vcxproj.filters @@ -51,9 +51,6 @@ Source Files - - Source Files - Source Files @@ -114,10 +111,13 @@ Source Files\tray - + Source Files - + + Source Files + + Source Files @@ -137,9 +137,6 @@ Header Files - - Header Files - Header Files @@ -161,9 +158,6 @@ Header Files - - Header Files - Header Files @@ -182,12 +176,6 @@ Header Files - - Header Files - - - Header Files - Header Files diff --git a/GlosSITarget/HttpServer.cpp b/GlosSITarget/HttpServer.cpp index 790e2a3..37798e7 100644 --- a/GlosSITarget/HttpServer.cpp +++ b/GlosSITarget/HttpServer.cpp @@ -19,7 +19,7 @@ limitations under the License. #include #include "AppLauncher.h" -#include "Settings.h" +#include "..\common\Settings.h" HttpServer::HttpServer(AppLauncher& app_launcher, std::function close) : app_launcher_(app_launcher), close_(close) { diff --git a/GlosSITarget/InputRedirector.cpp b/GlosSITarget/InputRedirector.cpp index 20efb5b..7a8dc3d 100644 --- a/GlosSITarget/InputRedirector.cpp +++ b/GlosSITarget/InputRedirector.cpp @@ -20,7 +20,7 @@ limitations under the License. #include #include "Overlay.h" -#include "Settings.h" +#include "..\common\Settings.h" InputRedirector::InputRedirector() { diff --git a/GlosSITarget/Overlay.cpp b/GlosSITarget/Overlay.cpp index 5fbe97a..44e0581 100644 --- a/GlosSITarget/Overlay.cpp +++ b/GlosSITarget/Overlay.cpp @@ -17,13 +17,11 @@ limitations under the License. #include #include -#include -#include #include #include #include "Roboto.h" -#include "Settings.h" +#include "..\common\Settings.h" #include "GlosSI_logo.h" #include "../version.hpp" @@ -52,23 +50,11 @@ Overlay::Overlay( ImGui::SFML::UpdateFontTexture(); #ifdef _WIN32 - wchar_t* localAppDataFolder; - std::filesystem::path config_path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - config_path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - config_path = std::filesystem::path(localAppDataFolder).parent_path(); - } - - config_path /= "Roaming"; - config_path /= "GlosSI"; - if (!std::filesystem::exists(config_path)) - std::filesystem::create_directories(config_path); + auto config_path = util::path::getDataDirPath(); config_path /= "imgui.ini"; // This assumes that char is utf8 and wchar_t is utf16, which is guaranteed on Windows. - config_file_name_ = std::wstring_convert>().to_bytes(config_path.wstring()); + config_file_name_ = util::string::to_string(config_path.wstring()); io.IniFilename = config_file_name_.data(); #endif diff --git a/GlosSITarget/Resource.rc b/GlosSITarget/Resource.rc index edcf04e..29f06bd 100644 --- a/GlosSITarget/Resource.rc +++ b/GlosSITarget/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,0,2045006300001 - PRODUCTVERSION 0,1,0,2045006300001 + FILEVERSION 0,1,2,0010004309958 + PRODUCTVERSION 0,1,2,0010004309958 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.0.2-45-g63fdab1" + VALUE "FileVersion", "0.1.2.0-10-g43c9958" VALUE "InternalName", "GlosSITarget" VALUE "LegalCopyright", "Copyright (C) 2021-2022 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSITarget.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.1.0.2-45-g63fdab1" + VALUE "ProductVersion", "0.1.2.0-10-g43c9958" END END BLOCK "VarFileInfo" @@ -220,6 +220,126 @@ IDI_ICON1 ICON "..\\GlosSI_Icon.ico" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GlosSITarget/Settings.h b/GlosSITarget/Settings.h deleted file mode 100644 index 896eae9..0000000 --- a/GlosSITarget/Settings.h +++ /dev/null @@ -1,336 +0,0 @@ -/* -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 - -#include -#include -#include -#include -#include -#include -#include - -#ifdef WIN32 -#define NOMINMAX -#include -#include -#include -#endif - -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; -} - -#ifdef WIN32 -inline bool isWin10 = false; - -typedef LONG NTSTATUS, *PNTSTATUS; -#define STATUS_SUCCESS (0x00000000) - -typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); - -inline RTL_OSVERSIONINFOW GetRealOSVersion() -{ - HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); - if (hMod) { - RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); - if (fxPtr != nullptr) { - RTL_OSVERSIONINFOW rovi = {0}; - rovi.dwOSVersionInfoSize = sizeof(rovi); - if (STATUS_SUCCESS == fxPtr(&rovi)) { - return rovi; - } - } - } - RTL_OSVERSIONINFOW rovi = {0}; - return rovi; -} - -inline void checkWinVer() -{ - auto VN = 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) -{ - auto safeParseValue = [](const auto& object, const auto& key, auto& value) { - try { - if (object.is_null() || object.empty() || object.at(key).empty() || object.at(key).is_null()) { - return; - } - 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()); - } - }; - - auto safeWStringParse = [&safeParseValue](const auto& object, const auto& key, std::wstring& value) { - std::string meh; - safeParseValue(object, key, meh); - if (!meh.empty()) { - // This assumes that char is utf8 and wchar_t is utf16, which is guaranteed on Windows. - value = std::wstring_convert>().from_bytes(meh); - } - }; - - 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); - safeWStringParse(launchconf, "launchPath", launch.launchPath); - safeWStringParse(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(std::wstring_convert>().from_bytes(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); - safeWStringParse(json, "name", common.name); - safeWStringParse(json, "icon", common.icon); - safeParseValue(json, "version", common.version); - - safeWStringParse(json, "steamPath", common.steamPath); - safeWStringParse(json, "steamUserId", common.steamUserId); - - safeWStringParse(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"; - } - } - wchar_t* localAppDataFolder; - std::filesystem::path path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - path = std::filesystem::path(localAppDataFolder).parent_path(); - } - - path /= "Roaming"; - path /= "GlosSI"; - 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"] = std::wstring_convert>().to_bytes(launch.launchPath); - json["launch"]["launchAppArgs"] = std::wstring_convert>().to_bytes(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"] = std::wstring_convert>().to_bytes(common.name); - json["icon"] = std::wstring_convert>().to_bytes(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/GlosSITarget/SteamOverlayDetector.cpp b/GlosSITarget/SteamOverlayDetector.cpp index 0b25c61..72ffd87 100644 --- a/GlosSITarget/SteamOverlayDetector.cpp +++ b/GlosSITarget/SteamOverlayDetector.cpp @@ -17,7 +17,7 @@ limitations under the License. #include -#include "Settings.h" +#include "..\common\Settings.h" #ifdef _WIN32 #define NOMINMAX diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp index 2e86a40..2c4f338 100644 --- a/GlosSITarget/SteamTarget.cpp +++ b/GlosSITarget/SteamTarget.cpp @@ -15,7 +15,7 @@ limitations under the License. */ #include "SteamTarget.h" -#include "Settings.h" +#include "..\common\Settings.h" #include "steam_sf_keymap.h" #include @@ -65,6 +65,7 @@ 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!"); diff --git a/GlosSITarget/SteamTarget.h b/GlosSITarget/SteamTarget.h index 735a547..c4220b9 100644 --- a/GlosSITarget/SteamTarget.h +++ b/GlosSITarget/SteamTarget.h @@ -21,7 +21,7 @@ limitations under the License. #include "TargetWindow.h" #ifdef _WIN32 -#include "HidHide.h" +#include "../common/HidHide.h" #include "InputRedirector.h" #include #endif diff --git a/GlosSITarget/TargetWindow.cpp b/GlosSITarget/TargetWindow.cpp index 53ebe65..71e4295 100644 --- a/GlosSITarget/TargetWindow.cpp +++ b/GlosSITarget/TargetWindow.cpp @@ -30,7 +30,7 @@ limitations under the License. #include "ProcessPriority.h" -#include "Settings.h" +#include "..\common\Settings.h" #if !defined(WM_DPICHANGED) #define WM_DPICHANGED 0x02E0 diff --git a/GlosSITarget/UWPOverlayEnabler.h b/GlosSITarget/UWPOverlayEnabler.h index 1aab02d..c580ba6 100644 --- a/GlosSITarget/UWPOverlayEnabler.h +++ b/GlosSITarget/UWPOverlayEnabler.h @@ -5,7 +5,6 @@ #include "DllInjector.h" #include "Overlay.h" -#include "util.h" namespace UWPOverlayEnabler { diff --git a/GlosSITarget/UnhookUtil.h b/GlosSITarget/UnhookUtil.h deleted file mode 100644 index 04f2b33..0000000 --- a/GlosSITarget/UnhookUtil.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -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 NOMINMAX -#include -#include - -#include -#include - -namespace UnhookUtil { -void UnPatchHook(const std::string& name, HMODULE module); - -std::string ReadOriginalBytes(const std::string& name, const std::wstring& moduleName); - -static inline const std::vector JUMP_INSTR_OPCODES = { - 0xE9, - 0xE8, - 0xEB, - 0xEA, - 0xFF}; - -// Valve Hooks various functions and hides Gaming devices like this. -// To be able to query them, unpatch the hook with the original bytes... - -// Bytes here are just fallbacks; originalbytes will get read from GlosSIConfig and stored in %APPDATA%\GlosSI\unhook_bytes - -// 22000 ^= Windows build number -static inline const std::map UNHOOK_BYTES_ORIGINAL_22000 = { - {"SetupDiEnumDeviceInfo", "\x48\x89\x5C\x24\x08"}, - {"SetupDiGetClassDevsW", "\x48\x89\x5C\x24\x08"}, - {"HidD_GetPreparsedData", "\x48\x89\x5C\x24\x18"}, - {"HidP_GetCaps", "\x4C\x8B\xD1\x48\x85\xC9"}, - {"HidD_GetAttributes", "\x40\x53\x48\x83\xEC"}, - {"HidD_GetProductString", "\x48\x83\xEC\x48\x48"}, - {"HidP_GetUsages", "\x4C\x89\x4C\x24\x20"}, - {"HidP_GetData", "\x4C\x89\x44\x24\x18"}, - {"HidP_GetValueCaps", "\x48\x83\xEC\x48\x49"}, - {"HidP_GetUsageValue", "\x40\x53\x55\x56\x48"}, - {"HidP_GetButtonCaps", "\x48\x83\xEC\x48\x49"}, - // Valve hooks "CreateProcess" to detect child-processes - {"CreateProcessW", "\x4C\x8B\xDC\x48\x83"}, -}; - -// SetupApi.dll is different on Win10 than on Win11 -static inline const std::map UNHOOK_BYTES_ORIGINAL_WIN10 = { - {"SetupDiEnumDeviceInfo", "\x40\x53\x56\x57\x41\x54\x41\x55"}, - {"SetupDiGetClassDevsW", "\x48\x8B\xC4\x48\x89\x58\x08"}, -}; - - -} // namespace UnhookUtil diff --git a/GlosSITarget/main.cpp b/GlosSITarget/main.cpp index 71e609f..ef40546 100644 --- a/GlosSITarget/main.cpp +++ b/GlosSITarget/main.cpp @@ -30,7 +30,7 @@ limitations under the License. #include "SteamTarget.h" #include "OverlayLogSink.h" -#include "Settings.h" +#include "..\common\Settings.h" #include #include "../version.hpp" @@ -71,19 +71,7 @@ LONG Win32FaultHandler(struct _EXCEPTION_POINTERS* ExInfo) MINIDUMP_EXCEPTION_INFORMATION M; HANDLE hDump_File; - wchar_t* localAppDataFolder; - std::filesystem::path path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - path = std::filesystem::path(localAppDataFolder).parent_path(); - } - - path /= "Roaming"; - path /= "GlosSI"; - if (!std::filesystem::exists(path)) - std::filesystem::create_directories(path); + auto path = util::path::getDataDirPath(); path /= "glossitarget.dmp"; M.ThreadId = GetCurrentThreadId(); @@ -127,19 +115,7 @@ int main(int argc, char* argv[]) const auto console_sink = std::make_shared(); console_sink->set_level(spdlog::level::trace); #ifdef _WIN32 - wchar_t* localAppDataFolder; - std::filesystem::path path; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - path = std::filesystem::path(localAppDataFolder).parent_path(); - } - - path /= "Roaming"; - path /= "GlosSI"; - if (!std::filesystem::exists(path)) - std::filesystem::create_directories(path); + auto path = util::path::getDataDirPath(); path /= "glossitarget.log"; // For "path.wstring()" to be usable here, SPDLOG_WCHAR_FILENAMES must be defined. const auto file_sink = std::make_shared(path.wstring(), true); diff --git a/GlosSITarget/util.h b/GlosSITarget/util.h deleted file mode 100644 index 1644f8b..0000000 --- a/GlosSITarget/util.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -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 WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#include - -namespace glossi_util { - -inline DWORD PidByName(const std::wstring& name) -{ - PROCESSENTRY32 entry; - entry.dwSize = sizeof(PROCESSENTRY32); - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); - if (Process32First(snapshot, &entry) == TRUE) { - while (Process32Next(snapshot, &entry) == TRUE) { - if (std::wstring(entry.szExeFile).find(name) != std::string::npos) { - return entry.th32ProcessID; - } - } - } - CloseHandle(snapshot); - return 0; -} - -inline std::wstring GetProcName(DWORD pid) -{ - PROCESSENTRY32 processInfo; - processInfo.dwSize = sizeof(processInfo); - const HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); - if (processesSnapshot == INVALID_HANDLE_VALUE) { - spdlog::trace("util::GetProcName: can't get a process snapshot"); - return L""; - } - - for (BOOL bok = Process32First(processesSnapshot, &processInfo); - bok; - bok = Process32Next(processesSnapshot, &processInfo)) { - if (pid == processInfo.th32ProcessID) { - CloseHandle(processesSnapshot); - return processInfo.szExeFile; - } - } - CloseHandle(processesSnapshot); - return L""; -} - -inline bool KillProcess(DWORD pid) -{ - auto res = true; - if (const auto proc = OpenProcess(PROCESS_TERMINATE, FALSE, pid)) { - spdlog::debug("Terminating process: {}", pid); - res = TerminateProcess(proc, 0); - if (!res) { - spdlog::error("Failed to terminate process: {}", pid); - } - CloseHandle(proc); - } - return res; -} - -} // namespace glossi_util diff --git a/GlosSIWatchdog/GlosSIWatchdog.vcxproj b/GlosSIWatchdog/GlosSIWatchdog.vcxproj index 01a1dbb..8e27f62 100644 --- a/GlosSIWatchdog/GlosSIWatchdog.vcxproj +++ b/GlosSIWatchdog/GlosSIWatchdog.vcxproj @@ -145,8 +145,8 @@ - - + + diff --git a/GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters b/GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters index 367978c..9e476d6 100644 --- a/GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters +++ b/GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters @@ -18,10 +18,10 @@ Source Files - + Source Files - + Source Files diff --git a/GlosSIWatchdog/dllmain.cpp b/GlosSIWatchdog/dllmain.cpp index d154509..f885b1c 100644 --- a/GlosSIWatchdog/dllmain.cpp +++ b/GlosSIWatchdog/dllmain.cpp @@ -15,10 +15,9 @@ limitations under the License. */ #include -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#include + +#include "../common/util.h" + #include @@ -29,9 +28,8 @@ limitations under the License. #include #include "../version.hpp" -#include "../GlosSITarget/Settings.h" -#include "../GlosSITarget/HidHide.h" -#include "../GlosSITarget/util.h" +#include "../common/Settings.h" +#include "../common/HidHide.h" bool IsProcessRunning(DWORD pid) { @@ -66,20 +64,7 @@ void fetchSettings(httplib::Client& http_client, int retried_count = 0) { DWORD WINAPI watchdog(HMODULE hModule) { - wchar_t* localAppDataFolder; - std::filesystem::path configDirPath; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - configDirPath = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - configDirPath = std::filesystem::path(localAppDataFolder).parent_path(); - } - - configDirPath /= "Roaming"; - configDirPath /= "GlosSI"; - if (!std::filesystem::exists(configDirPath)) - std::filesystem::create_directories(configDirPath); - + auto configDirPath = util::path::getDataDirPath(); auto logPath = configDirPath; logPath /= "GlosSIWatchdog.log"; const auto file_sink = std::make_shared(logPath.wstring(), true); @@ -143,7 +128,7 @@ DWORD WINAPI watchdog(HMODULE hModule) } if (IsProcessRunning(pid)) { - glossi_util::KillProcess(pid); + util::win::process::KillProcess(pid); } else { diff --git a/Installer/Installer.nsi b/Installer/Installer.nsi index c0a11bb..65c96aa 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.0.9.1-48-geb4ae9c" +!define VERSION "0.1.2.0-10-g43c9958" !define COPYRIGHT "Peter Repukat - FlatspotSoftware © 2017-2022" !define DESCRIPTION "SteamInput compatibility tool" !define INSTALLER_NAME "GlosSI-Installer.exe" @@ -193,3 +193,42 @@ SectionEnd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UWPOverlayEnablerDLL/dllmain.cpp b/UWPOverlayEnablerDLL/dllmain.cpp index 497ff4a..9ee6065 100644 --- a/UWPOverlayEnablerDLL/dllmain.cpp +++ b/UWPOverlayEnablerDLL/dllmain.cpp @@ -44,7 +44,8 @@ There are two (known to me, at time of writing) ways to get a working overlay fo #define WIN32_LEAN_AND_MEAN #include -#include + +#include "../common/util.h" #define SUBHOOK_STATIC #include @@ -141,22 +142,7 @@ BOOL APIENTRY DllMain( HMODULE hModule, { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { - wchar_t* localAppDataFolder; - std::filesystem::path configDirPath; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - configDirPath = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - configDirPath = std::filesystem::path(localAppDataFolder).parent_path(); - } - - configDirPath /= "Roaming"; - configDirPath /= "GlosSI"; - if (!std::filesystem::exists(configDirPath)) - std::filesystem::create_directories(configDirPath); - - - + auto configDirPath = util::path::getDataDirPath(); auto logPath = configDirPath; logPath /= "UWPOverlayEnabler.log"; const auto file_sink = std::make_shared(logPath.string(), true); diff --git a/GlosSITarget/HidHide.cpp b/common/HidHide.cpp similarity index 78% rename from GlosSITarget/HidHide.cpp rename to common/HidHide.cpp index 4b9cbb3..a901932 100644 --- a/GlosSITarget/HidHide.cpp +++ b/common/HidHide.cpp @@ -21,6 +21,8 @@ limitations under the License. #include "HidHide.h" #include +#define SPDLOG_WCHAR_TO_UTF8_SUPPORT +#define SPDLOG_WCHAR_FILENAMES #include #include @@ -29,7 +31,7 @@ limitations under the License. #include #ifndef WATCHDOG -#include "Overlay.h" +#include "../GlosSITarget/Overlay.h" #endif #include "Settings.h" @@ -41,7 +43,7 @@ limitations under the License. #include -#include "UnhookUtil.h" +#include "../common/UnhookUtil.h" #pragma comment(lib, "Setupapi.lib") @@ -52,7 +54,7 @@ DEFINE_GUID(GUID_DEVINTERFACE_XUSB, 0xEC87F1E3, 0xC13B, 0x4100, 0xB5, 0xF7, 0x8B // {00000000-0000-0000-FFFF-FFFFFFFFFFFF} the system container id DEFINE_GUID(GUID_CONTAINER_ID_SYSTEM, 0x00000000, 0x0000, 0x0000, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); -HidHide::HidHide(){}; +HidHide::HidHide() {}; void HidHide::openCtrlDevice() { @@ -85,7 +87,7 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path) spdlog::info("Hiding devices is disabled; Not un-patching valve hooks, not looking for HidHide"); return; } - + spdlog::debug("Setting up device hiding..."); UnPatchValveHooks(); @@ -112,12 +114,12 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path) for (const auto& exe : whitelist_executeables_) { auto path = std::regex_replace(steam_path_string, std::wregex(L"(.:)(\\/|\\\\)"), dos_device + L"\\"); - path = std::regex_replace(path, std::wregex(L"\\/"), L"\\") + L"\\" + std::wstring{exe}; + path = std::regex_replace(path, std::wregex(L"\\/"), L"\\") + L"\\" + std::wstring{ exe }; if (std::ranges::none_of(whitelist, [&path](auto ep) { // make copy! - auto p = path; // non-const(!) copy of path - std::ranges::transform(path, p.begin(), tolower); - std::ranges::transform(ep, ep.begin(), tolower); - return p == ep; + auto p = path; // non-const(!) copy of path + std::ranges::transform(path, p.begin(), tolower); + std::ranges::transform(ep, ep.begin(), tolower); + return p == ep; })) { whitelist.push_back(path); } @@ -125,7 +127,7 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path) if (Settings::common.extendedLogging) { std::ranges::for_each(whitelist, [](const auto& exe) { spdlog::trace(L"Whitelisted executable: {}", exe); - }); + }); } setAppWhiteList(whitelist); @@ -133,13 +135,13 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path) if (Settings::common.extendedLogging) { std::ranges::for_each(avail_devices_, [](const auto& dev) { spdlog::trace(L"AvailDevice device: {}", dev.name); - }); + }); } blacklisted_devices_ = getBlackListDevices(); for (const auto& dev : avail_devices_) { if (std::ranges::none_of(blacklisted_devices_, [&dev](const auto& blackdev) { - return blackdev == dev.device_instance_path || blackdev == dev.base_container_device_instance_path; + return blackdev == dev.device_instance_path || blackdev == dev.base_container_device_instance_path; })) { // Valve emulated gamepad PID/VID; mirrord by ViGEm if (!(dev.vendor_id == 0x28de && (dev.product_id == 0x11FF || dev.product_id == 0x028E))) { @@ -160,7 +162,7 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path) if (Settings::common.extendedLogging) { std::ranges::for_each(blacklisted_devices_, [](const auto& dev) { spdlog::trace(L"Blacklisted device: {}", dev); - }); + }); } } closeCtrlDevice(); @@ -199,80 +201,81 @@ void HidHide::enableOverlayElement() { Overlay::AddOverlayElem([this](bool window_has_focus, ImGuiID dockspace_id) { ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver); - if (ImGui::Begin("Hidden Devices")) { - if (device_hiding_setup_) { - if (window_has_focus && (overlay_elem_clock_.getElapsedTime().asSeconds() > OVERLAY_ELEM_REFRESH_INTERVAL_S_)) { - // UnPatchValveHooks(); - openCtrlDevice(); - bool hidehide_state_store = hidhide_active_; - if (Settings::common.extendedLogging) { - spdlog::debug("Refreshing HID devices"); - } - if (hidhide_active_) { - setActive(false); - } - avail_devices_ = GetHidDeviceList(); - if (Settings::common.extendedLogging) { - std::ranges::for_each(avail_devices_, [](const auto& dev) { - spdlog::trace(L"AvailDevice device: {}", dev.name); + if (ImGui::Begin("Hidden Devices")) { + if (device_hiding_setup_) { + if (window_has_focus && (overlay_elem_clock_.getElapsedTime().asSeconds() > OVERLAY_ELEM_REFRESH_INTERVAL_S_)) { + // UnPatchValveHooks(); + openCtrlDevice(); + bool hidehide_state_store = hidhide_active_; + if (Settings::common.extendedLogging) { + spdlog::debug("Refreshing HID devices"); + } + if (hidhide_active_) { + setActive(false); + } + avail_devices_ = GetHidDeviceList(); + if (Settings::common.extendedLogging) { + std::ranges::for_each(avail_devices_, [](const auto& dev) { + spdlog::trace(L"AvailDevice device: {}", dev.name); }); - } - blacklisted_devices_ = getBlackListDevices(); - if (hidehide_state_store && Settings::devices.hideDevices) { - setActive(true); - } - closeCtrlDevice(); - overlay_elem_clock_.restart(); } - ImGui::BeginChild("Inner", {0.f, ImGui::GetItemRectSize().y - 64}, true); - std::ranges::for_each(avail_devices_, [this](const auto& device) { - std::string label = (std::string(device.name.begin(), std::ranges::find(device.name, L'\0')) + "##" + std::string(device.device_instance_path.begin(), device.device_instance_path.end())); - const auto findDeviceFn = [&device](const auto& blackdev) { - return device.device_instance_path == blackdev || device.base_container_device_instance_path == blackdev; - }; - bool hidden = std::ranges::find_if(blacklisted_devices_, findDeviceFn) != blacklisted_devices_.end(); - if (ImGui::Checkbox(label.data(), &hidden)) { - openCtrlDevice(); - if (hidden) { - if (std::ranges::none_of(blacklisted_devices_, findDeviceFn)) { - if (!device.device_instance_path.empty()) { - blacklisted_devices_.push_back(device.device_instance_path); - } - if (!device.device_instance_path.empty()) { - blacklisted_devices_.push_back(device.base_container_device_instance_path); - } - } - } - else { - blacklisted_devices_.erase(std::ranges::remove_if(blacklisted_devices_, findDeviceFn).begin(), - blacklisted_devices_.end()); + blacklisted_devices_ = getBlackListDevices(); + if (hidehide_state_store && Settings::devices.hideDevices) { + setActive(true); + } + closeCtrlDevice(); + overlay_elem_clock_.restart(); + } + ImGui::BeginChild("Inner", { 0.f, ImGui::GetItemRectSize().y - 64 }, true); + std::ranges::for_each(avail_devices_, [this](const auto& device) { + std::string label = (std::string(device.name.begin(), std::ranges::find(device.name, L'\0')) + "##" + std::string(device.device_instance_path.begin(), device.device_instance_path.end())); + const auto findDeviceFn = [&device](const auto& blackdev) { + return device.device_instance_path == blackdev || device.base_container_device_instance_path == blackdev; + }; + bool hidden = std::ranges::find_if(blacklisted_devices_, findDeviceFn) != blacklisted_devices_.end(); + if (ImGui::Checkbox(label.data(), &hidden)) { + openCtrlDevice(); + if (hidden) { + if (std::ranges::none_of(blacklisted_devices_, findDeviceFn)) { + if (!device.device_instance_path.empty()) { + blacklisted_devices_.push_back(device.device_instance_path); } - setBlacklistDevices(blacklisted_devices_); - if (Settings::common.extendedLogging) { - std::ranges::for_each(blacklisted_devices_, [](const auto& dev) { - spdlog::trace(L"Blacklisted device: {}", dev); - }); + if (!device.device_instance_path.empty()) { + blacklisted_devices_.push_back(device.base_container_device_instance_path); } - closeCtrlDevice(); } - }); - ImGui::EndChild(); - } else { - ImGui::Text("Enable \"Hide Devices\" to see a list of gaming-devices"); - } - if (ImGui::Checkbox("Hide devices", &Settings::devices.hideDevices)) { - if (!device_hiding_setup_) { - hideDevices(steam_path_); } - if (hidhide_active_ != Settings::devices.hideDevices) { - openCtrlDevice(); - setActive(Settings::devices.hideDevices); - closeCtrlDevice(); + else { + blacklisted_devices_.erase(std::ranges::remove_if(blacklisted_devices_, findDeviceFn).begin(), + blacklisted_devices_.end()); } + setBlacklistDevices(blacklisted_devices_); + if (Settings::common.extendedLogging) { + std::ranges::for_each(blacklisted_devices_, [](const auto& dev) { + spdlog::trace(L"Blacklisted device: {}", dev); + }); + } + closeCtrlDevice(); + } + }); + ImGui::EndChild(); + } + else { + ImGui::Text("Enable \"Hide Devices\" to see a list of gaming-devices"); + } + if (ImGui::Checkbox("Hide devices", &Settings::devices.hideDevices)) { + if (!device_hiding_setup_) { + hideDevices(steam_path_); + } + if (hidhide_active_ != Settings::devices.hideDevices) { + openCtrlDevice(); + setActive(Settings::devices.hideDevices); + closeCtrlDevice(); } } - ImGui::End(); - }); + } + ImGui::End(); + }); } #endif @@ -280,7 +283,7 @@ std::wstring HidHide::DosDeviceForVolume(const std::wstring& volume) { std::vector buffer(UNICODE_STRING_MAX_CHARS); QueryDosDeviceW(volume.c_str(), buffer.data(), static_cast(buffer.size())); - return {buffer.data()}; + return { buffer.data() }; } std::vector HidHide::getAppWhiteList() const @@ -291,7 +294,7 @@ std::vector HidHide::getAppWhiteList() const } std::vector buffer(bytes_needed); if (!DeviceIoControl( - hidhide_handle, static_cast(IOCTL_TYPE::GET_WHITELIST), nullptr, 0, buffer.data(), static_cast(buffer.size() * sizeof(WCHAR)), &bytes_needed, nullptr)) { + hidhide_handle, static_cast(IOCTL_TYPE::GET_WHITELIST), nullptr, 0, buffer.data(), static_cast(buffer.size() * sizeof(WCHAR)), &bytes_needed, nullptr)) { spdlog::error("Couldn't retrieve HidHide Whitelist"); return std::vector{}; } @@ -306,7 +309,7 @@ std::vector HidHide::getBlackListDevices() const } std::vector buffer(bytes_needed); if (!DeviceIoControl( - hidhide_handle, static_cast(IOCTL_TYPE::GET_BLACKLIST), nullptr, 0, buffer.data(), static_cast(buffer.size() * sizeof(WCHAR)), &bytes_needed, nullptr)) { + hidhide_handle, static_cast(IOCTL_TYPE::GET_BLACKLIST), nullptr, 0, buffer.data(), static_cast(buffer.size() * sizeof(WCHAR)), &bytes_needed, nullptr)) { spdlog::error("Couldn't retrieve HidHide Blacklist"); return std::vector{}; } @@ -318,7 +321,7 @@ bool HidHide::getActive() DWORD bytes_needed; BOOLEAN res; if (!DeviceIoControl( - hidhide_handle, static_cast(IOCTL_TYPE::GET_ACTIVE), nullptr, 0, &res, sizeof(BOOLEAN), &bytes_needed, nullptr)) { + hidhide_handle, static_cast(IOCTL_TYPE::GET_ACTIVE), nullptr, 0, &res, sizeof(BOOLEAN), &bytes_needed, nullptr)) { spdlog::error("Couldn't retrieve HidHide State"); return false; } @@ -331,7 +334,7 @@ void HidHide::setAppWhiteList(const std::vector& whitelist) const DWORD bytes_needed; auto buffer = StringListToMultiString(whitelist); if (!DeviceIoControl( - hidhide_handle, static_cast(IOCTL_TYPE::SET_WHITELIST), buffer.data(), static_cast(buffer.size() * sizeof(WCHAR)), nullptr, 0, &bytes_needed, nullptr)) { + hidhide_handle, static_cast(IOCTL_TYPE::SET_WHITELIST), buffer.data(), static_cast(buffer.size() * sizeof(WCHAR)), nullptr, 0, &bytes_needed, nullptr)) { spdlog::error("Couldn't set HidHide WhiteList"); } } @@ -341,7 +344,7 @@ void HidHide::setBlacklistDevices(const std::vector& blacklist) co DWORD bytes_needed; auto buffer = StringListToMultiString(blacklist); if (!DeviceIoControl( - hidhide_handle, static_cast(IOCTL_TYPE::SET_BLACKLIST), buffer.data(), static_cast(buffer.size() * sizeof(WCHAR)), nullptr, 0, &bytes_needed, nullptr)) { + hidhide_handle, static_cast(IOCTL_TYPE::SET_BLACKLIST), buffer.data(), static_cast(buffer.size() * sizeof(WCHAR)), nullptr, 0, &bytes_needed, nullptr)) { spdlog::error("Couldn't set HidHide BlackList"); } } @@ -350,7 +353,7 @@ void HidHide::setActive(bool active) { DWORD bytes_needed; if (!DeviceIoControl( - hidhide_handle, static_cast(IOCTL_TYPE::SET_ACTIVE), &active, sizeof(BOOLEAN), nullptr, 0, &bytes_needed, nullptr)) { + hidhide_handle, static_cast(IOCTL_TYPE::SET_ACTIVE), &active, sizeof(BOOLEAN), nullptr, 0, &bytes_needed, nullptr)) { spdlog::error("Couldn't set HidHide State"); return; } @@ -394,9 +397,9 @@ std::vector HidHide::StringListToMultiString(const std::vector{}, [](auto acc, const auto& curr) { acc.insert(acc.end(), curr.begin(), curr.end()); - acc.push_back(L'\0'); - return acc; - }); + acc.push_back(L'\0'); + return acc; + }); res.push_back(L'\0'); return res; } @@ -426,7 +429,7 @@ std::vector HidHide::GetHidDeviceList() std::ranges::remove_if( device_instance_paths, [](const auto& dev) { return !DevicePresent(dev); }) - .begin(), + .begin(), device_instance_paths.end()); GUID hid_device_interface_guid{}; @@ -443,7 +446,7 @@ std::vector HidHide::GetHidDeviceList() std::ranges::remove_if( res, [](const auto& dev) { return !dev.gaming_device; }) - .begin(), + .begin(), res.end()); return res; @@ -504,8 +507,8 @@ HidHide::SmallHidInfo HidHide::GetDeviceInfo(const DeviceInstancePath& instance_ std::wstring buffer; buffer.resize(127 * sizeof WCHAR); res.name = (HidD_GetProductString(device_object.get(), buffer.data(), static_cast(sizeof(WCHAR) * buffer.size())) - ? buffer - : L""); + ? buffer + : L""); for (size_t i = 0; i < res.name.size(); ++i) { if (res.name[i] == L'\0') { res.name.resize(i + 1); @@ -566,13 +569,13 @@ std::filesystem::path HidHide::SymbolicLink(GUID const& interface_guid, DeviceIn std::vector buffer(needed); // Acquire the detailed data containing the symbolic link (aka. device path) - auto& [cbSize, DevicePath]{*reinterpret_cast(buffer.data())}; + auto& [cbSize, DevicePath] {*reinterpret_cast(buffer.data())}; cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); if (!SetupDiGetDeviceInterfaceDetailW(handle.get(), &device_interface_data, reinterpret_cast(buffer.data()), static_cast(buffer.size()), nullptr, nullptr)) { spdlog::error(L"Couldn't get Device interface details; device: {}", instance_path); return {}; } - return {std::wstring(DevicePath)}; + return { std::wstring(DevicePath) }; } HidHide::DeviceInstancePath HidHide::BaseContainerDeviceInstancePath(DeviceInstancePath const& device_instance_path) @@ -580,7 +583,7 @@ HidHide::DeviceInstancePath HidHide::BaseContainerDeviceInstancePath(DeviceInsta const GUID base_container_id(BaseContainerId(device_instance_path)); if ((GUID_NULL == base_container_id) || (GUID_CONTAINER_ID_SYSTEM == base_container_id)) return (std::wstring{}); - for (auto it{device_instance_path};;) { + for (auto it{ device_instance_path };;) { if (const auto device_instance_path_parent = DeviceInstancePathParent(it); (base_container_id == BaseContainerId(device_instance_path_parent))) it = device_instance_path_parent; else @@ -597,7 +600,7 @@ GUID HidHide::BaseContainerId(DeviceInstancePath const& device_instance_path) DEVINST devInst{}; DEVPROPTYPE devPropType{}; GUID buffer{}; - ULONG needed{sizeof(buffer)}; + ULONG needed{ sizeof(buffer) }; if (const auto result = CM_Locate_DevNodeW(&devInst, const_cast(device_instance_path.c_str()), CM_LOCATE_DEVNODE_PHANTOM); (CR_SUCCESS != result)) { spdlog::error(L"Couldn't locate device DevNode; Device {}; Code: {}", device_instance_path, result); return {}; @@ -624,7 +627,7 @@ HidHide::DeviceInstancePath HidHide::DeviceInstancePathParent(DeviceInstancePath DEVINST dev_inst_parent{}; std::wstring res; res.resize(UNICODE_STRING_MAX_CHARS); - ULONG needed{static_cast(res.size())}; + ULONG needed{ static_cast(res.size()) }; if (const auto result = CM_Locate_DevNodeW(&dev_inst, const_cast(device_instance_path.c_str()), CM_LOCATE_DEVNODE_PHANTOM); (CR_SUCCESS != result)) { spdlog::error(L"Couldn't locate device DevNode; Device {}; Code: {}", device_instance_path, result); return {}; diff --git a/GlosSITarget/HidHide.h b/common/HidHide.h similarity index 97% rename from GlosSITarget/HidHide.h rename to common/HidHide.h index 20689f9..e42a331 100644 --- a/GlosSITarget/HidHide.h +++ b/common/HidHide.h @@ -34,7 +34,7 @@ limitations under the License. #endif class HidHide { - private: +private: using DeviceInstancePath = std::wstring; using SetupDiDestroyDeviceInfoListPtr = std::unique_ptr, decltype(&SetupDiDestroyDeviceInfoList)>; using CloseHandlePtr = std::unique_ptr, decltype(&CloseHandle)>; @@ -62,7 +62,7 @@ class HidHide { bool gaming_device = false; }; - public: +public: HidHide(); void openCtrlDevice(); @@ -72,7 +72,7 @@ class HidHide { void disableHidHide(); // TODO: MAYBE: restore hidhide state/lists when app closes. not only disable device_hiding - private: +private: HANDLE hidhide_handle = nullptr; std::filesystem::path steam_path_; @@ -89,12 +89,12 @@ class HidHide { std::vector blacklisted_devices_; std::vector avail_devices_; bool hidhide_active_ = false; - static constexpr int OVERLAY_ELEM_REFRESH_INTERVAL_S_ = 5; + static constexpr int OVERLAY_ELEM_REFRESH_INTERVAL_S_ = 5; static inline constexpr std::array whitelist_executeables_{ L"GameOverlayUI.exe", L"steam.exe", - L"streaming_client.exe"}; + L"streaming_client.exe" }; static [[nodiscard]] std::wstring DosDeviceForVolume(const std::wstring& volume); diff --git a/common/Settings.h b/common/Settings.h new file mode 100644 index 0000000..09bbe0c --- /dev/null +++ b/common/Settings.h @@ -0,0 +1,300 @@ +/* +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 + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#define NOMINMAX +#include +#endif + +#include "../common/nlohmann_json_wstring.h" +#include "../common/util.h" + + +namespace Settings { + + inline struct Launch { + bool launch = false; + std::wstring launchPath; + std::wstring launchAppArgs; + bool closeOnExit = true; + bool waitForChildProcs = true; + bool isUWP = false; + bool ignoreLauncher = true; + bool killLauncher = false; + std::vector launcherProcesses{}; + } launch; + + inline struct Devices { + bool hideDevices = true; + bool realDeviceIds = false; + } devices; + + inline struct Window { + bool windowMode = false; + int maxFps = 0; + float scale = 0.f; + bool disableOverlay = false; + bool hideAltTab = true; + bool disableGlosSIOverlay = false; + } window; + + inline struct Controller { + int maxControllers = 1; + bool allowDesktopConfig = false; + bool emulateDS4 = false; + } controller; + + inline struct Common { + bool no_uwp_overlay = false; + bool disable_watchdog = false; + bool extendedLogging = false; + std::wstring name; + std::wstring icon; + int version; + std::wstring steamPath; + std::wstring steamUserId; + std::wstring standaloneModeGameId; /* = L"12605636929694728192"; */ + bool standaloneUseGamepadUI = false; + } 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; + } + +#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); + } + } +#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(); + } + +} // namespace Settings diff --git a/GlosSITarget/UnhookUtil.cpp b/common/UnhookUtil.cpp similarity index 88% rename from GlosSITarget/UnhookUtil.cpp rename to common/UnhookUtil.cpp index e300a0c..f5d04d4 100644 --- a/GlosSITarget/UnhookUtil.cpp +++ b/common/UnhookUtil.cpp @@ -13,7 +13,9 @@ 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. */ -#include "UnhookUtil.h" +#include "../common/UnhookUtil.h" + +#include "util.h" #ifndef CONFIGAPP #include @@ -28,17 +30,7 @@ void UnhookUtil::UnPatchHook(const std::string& name, HMODULE module) std::map original_bytes_from_file; - wchar_t* localAppDataFolder; - std::filesystem::path configDirPath; - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { - configDirPath = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); - } - else { - configDirPath = std::filesystem::path(localAppDataFolder).parent_path(); - } - - configDirPath /= "Roaming"; - configDirPath /= "GlosSI"; + auto configDirPath = util::path::getDataDirPath(); if (std::filesystem::exists(configDirPath)) { auto unhook_file_path = configDirPath / "unhook_bytes"; if (std::filesystem::exists(unhook_file_path)) { @@ -56,7 +48,8 @@ void UnhookUtil::UnPatchHook(const std::string& name, HMODULE module) ifile.read(&buff, sizeof(char)); if (buff != ':') { funcName.push_back(buff); - } else { + } + else { char bytes[8]; ifile.read(bytes, sizeof(char) * 8); ifile.read(&buff, sizeof(char)); // newline diff --git a/common/UnhookUtil.h b/common/UnhookUtil.h new file mode 100644 index 0000000..6ed996c --- /dev/null +++ b/common/UnhookUtil.h @@ -0,0 +1,66 @@ +/* +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 NOMINMAX +#include +#include + +#include +#include + +namespace UnhookUtil { + void UnPatchHook(const std::string& name, HMODULE module); + + std::string ReadOriginalBytes(const std::string& name, const std::wstring& moduleName); + + static inline const std::vector JUMP_INSTR_OPCODES = { + 0xE9, + 0xE8, + 0xEB, + 0xEA, + 0xFF }; + + // Valve Hooks various functions and hides Gaming devices like this. + // To be able to query them, unpatch the hook with the original bytes... + + // Bytes here are just fallbacks; originalbytes will get read from GlosSIConfig and stored in %APPDATA%\GlosSI\unhook_bytes + + // 22000 ^= Windows build number + static inline const std::map UNHOOK_BYTES_ORIGINAL_22000 = { + {"SetupDiEnumDeviceInfo", "\x48\x89\x5C\x24\x08"}, + {"SetupDiGetClassDevsW", "\x48\x89\x5C\x24\x08"}, + {"HidD_GetPreparsedData", "\x48\x89\x5C\x24\x18"}, + {"HidP_GetCaps", "\x4C\x8B\xD1\x48\x85\xC9"}, + {"HidD_GetAttributes", "\x40\x53\x48\x83\xEC"}, + {"HidD_GetProductString", "\x48\x83\xEC\x48\x48"}, + {"HidP_GetUsages", "\x4C\x89\x4C\x24\x20"}, + {"HidP_GetData", "\x4C\x89\x44\x24\x18"}, + {"HidP_GetValueCaps", "\x48\x83\xEC\x48\x49"}, + {"HidP_GetUsageValue", "\x40\x53\x55\x56\x48"}, + {"HidP_GetButtonCaps", "\x48\x83\xEC\x48\x49"}, + // Valve hooks "CreateProcess" to detect child-processes + {"CreateProcessW", "\x4C\x8B\xDC\x48\x83"}, + }; + + // SetupApi.dll is different on Win10 than on Win11 + static inline const std::map UNHOOK_BYTES_ORIGINAL_WIN10 = { + {"SetupDiEnumDeviceInfo", "\x40\x53\x56\x57\x41\x54\x41\x55"}, + {"SetupDiGetClassDevsW", "\x48\x8B\xC4\x48\x89\x58\x08"}, + }; + + +} // namespace UnhookUtil diff --git a/common/common.vcxproj b/common/common.vcxproj new file mode 100644 index 0000000..5e38350 --- /dev/null +++ b/common/common.vcxproj @@ -0,0 +1,151 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {dfed4b7e-d04c-442b-bb48-5b6068a6b31b} + common + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Utility + true + v143 + Unicode + + + Utility + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + ..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;$(IncludePath) + + + ..\deps\json\include;..\deps\spdlog\include;..\deps\SFML\include;..\deps\imgui;$(IncludePath) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters new file mode 100644 index 0000000..cd5e20b --- /dev/null +++ b/common/common.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/common/nlohmann_json_wstring.h b/common/nlohmann_json_wstring.h new file mode 100644 index 0000000..5fa1f82 --- /dev/null +++ b/common/nlohmann_json_wstring.h @@ -0,0 +1,36 @@ +/* +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 + + +#include + +#include "util.h" + + +namespace nlohmann { + template <> + struct adl_serializer { + static void to_json(json& j, const std::wstring& str) { + j = util::string::to_string(str); + } + + static void from_json(const json& j, std::wstring& str) { + str = util::string::to_wstring(j.get()); + } + }; +} diff --git a/common/util.h b/common/util.h new file mode 100644 index 0000000..52cadc6 --- /dev/null +++ b/common/util.h @@ -0,0 +1,163 @@ +/* +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 + +#include +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#include +#include +#include +#endif + +#include + +#ifdef SPDLOG_H +#include +#endif + +namespace util { + namespace string + { + template + inline std::wstring to_wstring(const T& t) + { + std::wstring_convert> converter; + return converter.from_bytes(t); + } + + template + inline std::string to_string(const T& t) + { + std::wstring_convert> converter; + return converter.to_bytes(t); + } + } + + namespace path + { + inline std::filesystem::path getDataDirPath() + { + wchar_t* localAppDataFolder; + std::filesystem::path path; + if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &localAppDataFolder) != S_OK) { + path = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); + } + else { + path = std::filesystem::path(localAppDataFolder).parent_path(); + } + + path /= "Roaming"; + path /= "GlosSI"; + if (!std::filesystem::exists(path)) + std::filesystem::create_directories(path); + return path; + } + } + +#ifdef _WIN32 + namespace win + { + + typedef LONG NTSTATUS, * PNTSTATUS; +#define STATUS_SUCCESS (0x00000000) + + typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + + inline RTL_OSVERSIONINFOW GetRealOSVersion() + { + HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); + if (hMod) { + RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); + if (fxPtr != nullptr) { + RTL_OSVERSIONINFOW rovi = { 0 }; + rovi.dwOSVersionInfoSize = sizeof(rovi); + if (STATUS_SUCCESS == fxPtr(&rovi)) { + return rovi; + } + } + } + RTL_OSVERSIONINFOW rovi = { 0 }; + return rovi; + } + namespace process + { + inline DWORD PidByName(const std::wstring& name) + { + PROCESSENTRY32 entry; + entry.dwSize = sizeof(PROCESSENTRY32); + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + if (Process32First(snapshot, &entry) == TRUE) { + while (Process32Next(snapshot, &entry) == TRUE) { + if (std::wstring(entry.szExeFile).find(name) != std::string::npos) { + return entry.th32ProcessID; + } + } + } + CloseHandle(snapshot); + return 0; + } + + inline std::wstring GetProcName(DWORD pid) + { + PROCESSENTRY32 processInfo; + processInfo.dwSize = sizeof(processInfo); + const HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + if (processesSnapshot == INVALID_HANDLE_VALUE) { +#ifdef SPDLOG_H + spdlog::trace("util::GetProcName: can't get a process snapshot"); +#endif + return L""; + } + + for (BOOL bok = Process32First(processesSnapshot, &processInfo); + bok; + bok = Process32Next(processesSnapshot, &processInfo)) { + if (pid == processInfo.th32ProcessID) { + CloseHandle(processesSnapshot); + return processInfo.szExeFile; + } + } + CloseHandle(processesSnapshot); + return L""; + } + + inline bool KillProcess(DWORD pid) + { + auto res = true; + if (const auto proc = OpenProcess(PROCESS_TERMINATE, FALSE, pid)) { +#ifdef SPDLOG_H + spdlog::debug("Terminating process: {}", pid); +#endif + res = TerminateProcess(proc, 0); + if (!res) { +#ifdef SPDLOG_H + spdlog::error("Failed to terminate process: {}", pid); +#endif + } + CloseHandle(proc); + } + return res; + } + } + } +#endif + } \ No newline at end of file