From cb6cbdeac66965f8dbcb02ba82206d5af153600b Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Tue, 31 Jan 2023 22:02:12 +0100 Subject: [PATCH] More work on CEFInject / SteamTweaks --- CEFInjectLib/CEFInject.cpp | 339 +++++++++++++----- CEFInjectLib/CEFInject.h | 34 +- CEFInjectLib/CEFInjectLib.vcxproj | 8 +- GlosSI.sln | 5 +- GlosSIConfig/Resource.rc | 8 +- GlosSITarget/HttpServer.cpp | 6 + GlosSITarget/Resource.rc | 8 +- GlosSITarget/SteamTarget.cpp | 12 + GlosSIWatchdog/GlosSIWatchdog.vcxproj | 10 +- GlosSIWatchdog/dllmain.cpp | 7 + Installer/Installer.nsi | 2 +- SteamTweaks/rollup.config.js | 2 + SteamTweaks/src/GlosSITweaks.ts | 27 ++ .../Overlay/SharedContext/HideFPSCounter.ts | 7 +- SteamTweaks/src/common/util/util.ts | 12 + 15 files changed, 379 insertions(+), 108 deletions(-) create mode 100644 SteamTweaks/src/common/util/util.ts diff --git a/CEFInjectLib/CEFInject.cpp b/CEFInjectLib/CEFInject.cpp index 96d8267..edde29d 100644 --- a/CEFInjectLib/CEFInject.cpp +++ b/CEFInjectLib/CEFInject.cpp @@ -27,6 +27,10 @@ limitations under the License. #include #include +#include + +#include "../common/Settings.h" + namespace CEFInject { namespace internal @@ -34,7 +38,8 @@ namespace CEFInject httplib::Client GetHttpClient(uint16_t port) { httplib::Client cli("localhost", port); - cli.set_connection_timeout(1000); + cli.set_connection_timeout(0, 200000); + cli.set_read_timeout(0, 500000); return cli; } @@ -44,8 +49,6 @@ namespace CEFInject bool CEFDebugAvailable(uint16_t port) { auto cli = internal::GetHttpClient(port); - cli.set_connection_timeout(500); - cli.set_read_timeout(500); if (auto res = cli.Get("/json")) { if (res->status == 200) { return true; @@ -64,21 +67,28 @@ namespace CEFInject return tabs; } - nlohmann::json::array_t AvailableTabs(uint16_t port) + nlohmann::basic_json<> AvailableTabs(uint16_t port) { if (!CEFDebugAvailable()) { return nlohmann::json::array(); } + + //if (Settings::common.extendedLogging) + //{ + spdlog::trace("Fetching available Steam CEF tabs"); + //} + auto cli = internal::GetHttpClient(port); if (auto res = cli.Get("/json")) { if (res->status == 200) { return nlohmann::json::parse(res->body); } } + return nlohmann::json::array(); } - nlohmann::json InjectJs(std::string_view debug_url, std::wstring_view js, uint16_t port) + nlohmann::basic_json<> InjectJs(std::string_view tab_name, std::string_view debug_url, std::wstring_view js, uint16_t port) { #ifdef _WIN32 INT rc; @@ -96,43 +106,50 @@ namespace CEFInject }; if (ws) { - auto json_payload = nlohmann::json{ - {"id", internal::msg_id++}, - {"method", "Runtime.evaluate"}, - {"params", { - {"userGesture", true}, - {"expression", std::wstring{js.data()}} - //{"expression", js} - }} - }; - auto payload_string = json_payload.dump(); - ws->send(payload_string); nlohmann::json res = nullptr; - bool exit = false; - while (ws->getReadyState() != easywsclient::WebSocket::CLOSED) { - ws->poll(); - ws->dispatch([&ws, &res, &exit](const std::string& message) { - const auto msg = nlohmann::json::parse(message); - try - { - res = msg.at("result").at("result").at("value"); - } catch (...){ - // - } + try + { + auto json_payload = nlohmann::json{ + {"id", internal::msg_id++}, + {"method", "Runtime.evaluate"}, + {"params", { + {"userGesture", true}, + {"expression", std::wstring{js.data()}} + //{"expression", js} + }} + }; + auto payload_string = json_payload.dump(); + + spdlog::debug("Injecting JS into tab: {}, {}; JS: {}", tab_name, debug_url, payload_string); + + ws->send(payload_string); + bool exit = false; + while (ws->getReadyState() != easywsclient::WebSocket::CLOSED) { + ws->poll(); + ws->dispatch([&ws, &res, &exit](const std::string& message) { + const auto msg = nlohmann::json::parse(message); try { - if (res.is_null() && msg.at("result").at("result").at("type").get() != "undefined") { - res = nlohmann::json::parse(message); + if (msg.at("result").at("result").at("type").get() != "undefined") { + res = msg.at("result").at("result").at("value"); } - } catch (...) { - res = nlohmann::json::parse(message); } - exit = true; - }); - if (exit) { - ws->close(); - return res; + catch (...) { + spdlog::error("CEFInject: Error parsing injection-result value: {}", message); + res = msg; + } + exit = true; + }); + if (exit) { + ws->close(); + return res; + } } + } catch (...) { + spdlog::error( + "CEFInject: Error injecting JS into tab: {}, {}", + std::string(tab_name.data()), + std::string(debug_url.data())); } #ifdef _WIN32 WSACleanup(); @@ -145,7 +162,7 @@ namespace CEFInject return nullptr; } - nlohmann::json InjectJsByName(std::wstring_view tabname, std::wstring_view js, uint16_t port) + nlohmann::basic_json<> InjectJsByName(std::wstring_view tabname, std::wstring_view js, uint16_t port) { auto cli = internal::GetHttpClient(port); if (auto res = cli.Get("/json")) { @@ -153,7 +170,7 @@ namespace CEFInject const auto json = nlohmann::json::parse(res->body); for (const auto& tab : json) { if (tab["title"].get().starts_with(tabname)) { - return InjectJs(tab["webSocketDebuggerUrl"].get(), js, port); + return InjectJs(tab["title"].get(), tab["webSocketDebuggerUrl"].get(), js, port); } } } @@ -165,7 +182,7 @@ namespace CEFInject bool SteamTweaks::injectGlosSITweaks(std::string_view tab_name, uint16_t port) { if (tab_name.empty()) { - for (const auto& tn : AvailableTabNames()) + for (auto ts = AvailableTabNames(); const auto & tn : ts) { // meh! injectGlosSITweaks(util::string::to_string(tn), port); @@ -181,20 +198,11 @@ namespace CEFInject return false; } - auto glossi_path = util::path::getGlosSIDir(); - glossi_path /= steam_tweaks_path_; - glossi_path /= "GlosSITweaks.js"; - - if (!std::filesystem::exists(glossi_path)) + if (glossi_tweaks_js_.empty()) { - return false; - } - - std::wifstream js_file(glossi_path); - std::wstring glossitweaks_js{ (std::istreambuf_iterator(js_file)), - std::istreambuf_iterator() }; - if (glossitweaks_js.empty()) { - return false; + if (!readGlosSITweaksJs()) { + return false; + } } const auto find_tab = ( @@ -212,34 +220,34 @@ namespace CEFInject return nlohmann::json{}; }; } - if (!info.id.empty()) - { - return [&info](const nlohmann::json::array_t& tabList) - { - for (const auto& tab : tabList) { - if (tab["id"].get() == info.id) { - return tab; - } - } - return nlohmann::json{}; - }; - + if (!info.id.empty()) + { + return [&info](const nlohmann::json::array_t& tabList) + { + for (const auto& tab : tabList) { + if (tab["id"].get() == info.id) { + return tab; + } } - if (!info.webSocketDebuggerUrl.empty()) - { - return [&info](const nlohmann::json::array_t& tabList) - { - for (const auto& tab : tabList) { - if (tab["webSocketDebuggerUrl"].get() == info.webSocketDebuggerUrl) { - return tab; - } - } - return nlohmann::json{}; - }; + return nlohmann::json{}; + }; - } - return nullptr; + } + if (!info.webSocketDebuggerUrl.empty()) + { + return [&info](const nlohmann::json::array_t& tabList) + { + for (const auto& tab : tabList) { + if (tab["webSocketDebuggerUrl"].get() == info.webSocketDebuggerUrl) { + return tab; } + } + return nlohmann::json{}; + }; + + } + return nullptr; + } )(); if (find_tab == nullptr) { return false; @@ -250,9 +258,13 @@ namespace CEFInject return false; } - InjectJs(tab["webSocketDebuggerUrl"].get(), glossitweaks_js, port); - glossi_tweaks_injected_map_[tab["id"].get()] = true; - return true; + const auto res = InjectJs(tab["title"].get(), tab["webSocketDebuggerUrl"].get(), glossi_tweaks_js_, port); + if (res.is_boolean() && res.get()) { + glossi_tweaks_injected_map_[tab["id"].get()] = true; + spdlog::trace("CEFInject: GlosSITweaks injected into tab: {}", tab["title"].get()); + return true; + } + return false; } bool SteamTweaks::uninstallTweaks(bool force) @@ -260,16 +272,179 @@ namespace CEFInject if (!CEFDebugAvailable()) { return false; } + + auto_inject_ = false; + if (auto_inject_future_.valid()) { + auto_inject_future_.wait(); + } + if (glossi_tweaks_injected_map_.empty() && !force) { return false; } - for (auto& tab : AvailableTabNames()) { - InjectJsByName(tab, uninstall_glossi_tweaks_js_); + std::vector> futures; + for (auto ts = AvailableTabs(); auto & tab : ts) { + futures.push_back(std::async(std::launch::async, [this, &tab]() + { + InjectJs(tab["title"].get(), tab["webSocketDebuggerUrl"].get(), uninstall_glossi_tweaks_js_); + })); } + for (auto& f : futures) + { + if (f.valid()){ + f.wait(); + } + } glossi_tweaks_injected_map_.clear(); return true; } + void SteamTweaks::update(float elapsed_time) + { + if (!auto_inject_) { + return; + } + using namespace std::chrono_literals; + if (auto_inject_future_.valid() && auto_inject_future_.wait_for(0ms) != std::future_status::ready) { + time_since_last_update_ = 0.0f; + return; + } + + time_since_last_update_ += elapsed_time; + if (time_since_last_update_ < update_interval_) { + return; + } + time_since_last_update_ = 0.0f; + + spdlog::trace("CEFInject: Starting auto inject GlosSITweaks"); + auto_inject_future_ = std::async(std::launch::async, [this]() { + + if (js_tweaks_cache_.empty()) [[unlikely]] { + readAvailableTweaks(); + } + + if (glossi_tweaks_js_.empty()) [[unlikely]] + { + if (!readGlosSITweaksJs()) { + return; + } + } + + auto futures = std::vector>{}; + auto tabs = AvailableTabs(); + for (auto& tab : tabs) { + if (glossi_tweaks_injected_map_.contains(tab["id"].get())) { + continue; + } + glossi_tweaks_injected_map_[tab["id"].get()] = true; + + futures.push_back(std::async([this, &tab]() + { + InjectJs(tab["title"].get(), tab["webSocketDebuggerUrl"].get(), glossi_tweaks_js_); + + for (auto& [path, js] : js_tweaks_cache_) { + const auto dir_name = path.parent_path().filename(); + + if (path_tab_map_.contains(dir_name.wstring())) { + if (tab["title"].get().starts_with(path_tab_map_.at(dir_name.wstring()))) { + InjectJs(tab["title"].get(), tab["webSocketDebuggerUrl"].get(), js); + } + } + } + })); + } + for (auto& f : futures) + { + if (f.valid()) { + f.wait(); + } + } + spdlog::trace("CEFInject: Auto Inject thread done"); + }); + } + + bool SteamTweaks::isAutoInject() const + { + return auto_inject_; + } + + void SteamTweaks::setAutoInject(const bool auto_inject) + { + auto_inject_ = auto_inject; + } + + bool SteamTweaks::readGlosSITweaksJs() + { + if (glossi_tweaks_js_.empty()) + { + spdlog::trace("CEFInject: Loadings GlosSITweaks.js"); + + auto glossi_path = util::path::getGlosSIDir(); + glossi_path /= steam_tweaks_path_; + glossi_path /= "GlosSITweaks.js"; + + if (!std::filesystem::exists(glossi_path)) + { + spdlog::error("CEFInject: GlosSITweaks.js not found"); + return false; + } + + std::wifstream js_file(glossi_path); + glossi_tweaks_js_ = { (std::istreambuf_iterator(js_file)), + std::istreambuf_iterator() }; + if (glossi_tweaks_js_.empty()) { + spdlog::error("CEFInject: GlosSITweaks.js empty?"); + return false; + } + js_file.close(); + } + return true; + } + + void SteamTweaks::readAvailableTweaks(bool builtin) + { + auto tweaks_path = builtin ? util::path::getGlosSIDir() : util::path::getDataDirPath(); + spdlog::log( + builtin ? spdlog::level::trace : spdlog::level::debug, + "CEFInject: Loading {} {} {}", + builtin ? "builtin" : "user", + "tweaks from", + tweaks_path.string() + ); + tweaks_path /= steam_tweaks_path_; + if (!std::filesystem::exists(tweaks_path)) + { + return; + } + + auto find_tweak_files = [this](std::wstring_view path, auto&& recurse) -> void + { + for (const auto& dir_file : std::filesystem::directory_iterator(path)) + { + if (std::filesystem::is_directory(dir_file)) + { + recurse(dir_file.path().wstring(), recurse); + continue; + } + if (std::filesystem::is_regular_file(dir_file) && dir_file.path().extension() == ".js") + { + if (dir_file.path().filename() == "GlosSITweaks.js") { + continue; + } + std::wifstream js_file(dir_file.path()); + std::wstring tweaks_js = { (std::istreambuf_iterator(js_file)), + std::istreambuf_iterator() }; + if (tweaks_js.empty()) { + continue; + } + js_file.close(); + js_tweaks_cache_[dir_file.path().wstring()] = tweaks_js; + } + } + }; + find_tweak_files(tweaks_path.wstring(), find_tweak_files); + + + } } diff --git a/CEFInjectLib/CEFInject.h b/CEFInjectLib/CEFInject.h index 2d7b36e..2fd103d 100644 --- a/CEFInjectLib/CEFInject.h +++ b/CEFInjectLib/CEFInject.h @@ -15,6 +15,7 @@ limitations under the License. */ #pragma once +#include #include #include @@ -31,9 +32,9 @@ namespace CEFInject } bool CEFDebugAvailable(uint16_t port = internal::port_); std::vector AvailableTabNames(uint16_t port = internal::port_); - nlohmann::json::array_t AvailableTabs(uint16_t port = internal::port_); - nlohmann::json InjectJs(std::string_view debug_url, std::wstring_view js, uint16_t port = internal::port_); - nlohmann::json InjectJsByName(std::wstring_view tabname, std::wstring_view js, uint16_t port = internal::port_); + nlohmann::basic_json<> AvailableTabs(uint16_t port = internal::port_); + nlohmann::basic_json<> InjectJs(std::string_view tab_name, std::string_view debug_url, std::wstring_view js, uint16_t port = internal::port_); + nlohmann::basic_json<> InjectJsByName(std::wstring_view tabname, std::wstring_view js, uint16_t port = internal::port_); class SteamTweaks { @@ -48,17 +49,36 @@ namespace CEFInject }; bool injectGlosSITweaks(std::string_view tab_name, uint16_t port = internal::port_); bool injectGlosSITweaks(const Tab_Info& info, uint16_t port = internal::port_); - public: bool uninstallTweaks(bool force = false); - - // TODO: Provide API to auto-inject - // TODO: build system to auto inject "user plugins" + void update(float elapsed_time); + [[nodiscard]] bool isAutoInject() const; + void setAutoInject(const bool auto_inject); private: + bool readGlosSITweaksJs(); + void readAvailableTweaks(bool builtin = true); + bool auto_inject_ = false; + + static constexpr float update_interval_ = 30.f; + float time_since_last_update_ = update_interval_; using tab_id = std::string; std::map glossi_tweaks_injected_map_; + std::future auto_inject_future_; + + std::wstring glossi_tweaks_js_; + + std::map js_tweaks_cache_; + + using path_name = std::wstring; + using tab_name = std::string; + static inline const std::map path_tab_map_ = { + {L"SharedContext", "Steam Shared Context"}, + {L"Overlay", "HOW TF GET OVERLAY TAB NAME?"}, // TODO: Figure out how to get the overlay tab name + }; + + static constexpr std::string_view steam_shared_ctx_tab_name_ = "Steam Shared Context"; static constexpr std::string_view steam_tweaks_path_ = "SteamTweaks"; static constexpr std::wstring_view uninstall_glossi_tweaks_js_ = LR"( (() => { diff --git a/CEFInjectLib/CEFInjectLib.vcxproj b/CEFInjectLib/CEFInjectLib.vcxproj index 78ba19e..45991ac 100644 --- a/CEFInjectLib/CEFInjectLib.vcxproj +++ b/CEFInjectLib/CEFInjectLib.vcxproj @@ -77,10 +77,10 @@ - ..\deps\cpp-httplib;..\deps\json\include;..\deps\easywsclient;$(IncludePath) + ..\deps\cpp-httplib;..\deps\json\include;..\deps\easywsclient;..\deps\spdlog\include;$(IncludePath) - ..\deps\cpp-httplib;..\deps\json\include;..\deps\easywsclient;$(IncludePath) + ..\deps\cpp-httplib;..\deps\json\include;..\deps\easywsclient;..\deps\spdlog\include;$(IncludePath) @@ -120,7 +120,7 @@ Level3 true - _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_DEBUG;_LIB;%(PreprocessorDefinitions) + SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_WCHAR_FILENAMES;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions) true NotUsing pch.h @@ -142,7 +142,7 @@ true true true - _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;NDEBUG;_LIB;%(PreprocessorDefinitions) + SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_WCHAR_FILENAMES;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_CRT_SECURE_NO_WARNINGS;NDEBUG;_LIB;%(PreprocessorDefinitions) true NotUsing pch.h diff --git a/GlosSI.sln b/GlosSI.sln index 05714a1..7d692e5 100644 --- a/GlosSI.sln +++ b/GlosSI.sln @@ -13,6 +13,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UWPOverlayEnablerDLL", "UWPOverlayEnablerDLL\UWPOverlayEnablerDLL.vcxproj", "{50212575-87E2-40AB-87EE-EAED19C8EBB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GlosSIWatchdog", "GlosSIWatchdog\GlosSIWatchdog.vcxproj", "{BF273B90-CB69-43C8-9AF6-F3256DAFD41E}" + ProjectSection(ProjectDependencies) = postProject + {74FBA967-AB7E-43EA-B561-3F4821954B3B} = {74FBA967-AB7E-43EA-B561-3F4821954B3B} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CEFInjectLib", "CEFInjectLib\CEFInjectLib.vcxproj", "{74FBA967-AB7E-43EA-B561-3F4821954B3B}" EndProject @@ -75,7 +78,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {789386B6-7D1E-4F9C-BF2E-9B5EDC3BB7C8} Qt5Version = 6.2.2_msvc2019_64 + SolutionGuid = {789386B6-7D1E-4F9C-BF2E-9B5EDC3BB7C8} EndGlobalSection EndGlobal diff --git a/GlosSIConfig/Resource.rc b/GlosSIConfig/Resource.rc index 2d28795..276c41a 100644 --- a/GlosSIConfig/Resource.rc +++ b/GlosSIConfig/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,2,0030000050130 - PRODUCTVERSION 0,1,2,0030000050130 + FILEVERSION 0,1,2,0041001700025 + PRODUCTVERSION 0,1,2,0041001700025 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - Config" - VALUE "FileVersion", "0.1.2.0-30-geb5f13f" + VALUE "FileVersion", "0.1.2.0-41-g17b0d25" VALUE "InternalName", "GlosSIConfig" VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSIConfig.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.1.2.0-30-geb5f13f" + VALUE "ProductVersion", "0.1.2.0-41-g17b0d25" END END BLOCK "VarFileInfo" diff --git a/GlosSITarget/HttpServer.cpp b/GlosSITarget/HttpServer.cpp index b6da48b..e71c594 100644 --- a/GlosSITarget/HttpServer.cpp +++ b/GlosSITarget/HttpServer.cpp @@ -32,6 +32,12 @@ void HttpServer::run() auto setCorsHeader = [](httplib::Response& res) { res.set_header("Access-Control-Allow-Origin", "*"); }; + + server_.Get("/", [this, &setCorsHeader](const httplib::Request& req, httplib::Response& res) { + res.set_content("", "text/json"); + setCorsHeader(res); + }); + server_.Get("/launched-pids", [this, &setCorsHeader](const httplib::Request& req, httplib::Response& res) { const nlohmann::json j = app_launcher_.launchedPids(); res.set_content(j.dump(), "text/json"); diff --git a/GlosSITarget/Resource.rc b/GlosSITarget/Resource.rc index ba91c46..8284c44 100644 --- a/GlosSITarget/Resource.rc +++ b/GlosSITarget/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,2,0031000204300 - PRODUCTVERSION 0,1,2,0031000204300 + FILEVERSION 0,1,2,0041007165813 + PRODUCTVERSION 0,1,2,0041007165813 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - SteamTarget" - VALUE "FileVersion", "0.1.2.0-31-gd2b43ff" + VALUE "FileVersion", "0.1.2.0-41-g7165813" VALUE "InternalName", "GlosSITarget" VALUE "LegalCopyright", "Copyright (C) 2021-2022 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSITarget.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.1.2.0-31-gd2b43ff" + VALUE "ProductVersion", "0.1.2.0-41-g7165813" END END BLOCK "VarFileInfo" diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp index 54f97fa..a145465 100644 --- a/GlosSITarget/SteamTarget.cpp +++ b/GlosSITarget/SteamTarget.cpp @@ -58,6 +58,10 @@ int SteamTarget::run() if (Settings::common.standaloneModeGameId == L"") { spdlog::error("No game id set for standalone mode. Controller will use desktop-config!"); } + auto steam_tweaks = CEFInject::SteamTweaks(); + steam_tweaks.setAutoInject(true); + if (!overlay_.expired()) + overlay_.lock()->setEnabled(false); std::vector> end_frame_callbacks; @@ -116,6 +120,8 @@ int SteamTarget::run() server_.run(); bool delayed_full_init_1_frame = false; + sf::Clock frame_time_clock; + while (run_) { if (!fully_initialized_ && can_fully_initialize_ && delayed_full_init_1_frame) { init_FuckingRenameMe(); @@ -130,6 +136,9 @@ int SteamTarget::run() overlayHotkeyWorkaround(); window_.update(); + steam_tweaks.update(frame_time_clock.getElapsedTime().asSeconds()); + + // Wait on shutdown; User might get confused if window closes to fast if anything with launchApp get's borked. if (delayed_shutdown_) { if (delay_shutdown_clock_.getElapsedTime().asSeconds() >= 3) { @@ -145,7 +154,9 @@ int SteamTarget::run() efc(); } end_frame_callbacks.clear(); + frame_time_clock.restart(); } + steam_tweaks.uninstallTweaks(); tray->exit(); server_.stop(); @@ -156,6 +167,7 @@ int SteamTarget::run() #endif launcher_.close(); } + return 0; } diff --git a/GlosSIWatchdog/GlosSIWatchdog.vcxproj b/GlosSIWatchdog/GlosSIWatchdog.vcxproj index b756f12..1ab4186 100644 --- a/GlosSIWatchdog/GlosSIWatchdog.vcxproj +++ b/GlosSIWatchdog/GlosSIWatchdog.vcxproj @@ -71,10 +71,12 @@ - ..\deps\spdlog\include;..\deps\json\include;..\deps\cpp-httplib;$(IncludePath) + ..\deps\spdlog\include;..\deps\json\include;..\deps\cpp-httplib;..\CEFInjectLib;$(IncludePath) + ..\x64\Debug;$(LibraryPath) - ..\deps\spdlog\include;..\deps\json\include;..\deps\cpp-httplib;$(IncludePath) + ..\deps\spdlog\include;..\deps\json\include;..\deps\cpp-httplib;..\CEFInjectLib;$(IncludePath) + ..\x64\Release;$(LibraryPath) @@ -119,7 +121,7 @@ Windows true - hid.lib;Cfgmgr32.lib;setupapi.lib;%(AdditionalDependencies) + hid.lib;Cfgmgr32.lib;setupapi.lib;CefInjectLib.lib;%(AdditionalDependencies) powershell.exe $(SolutionDir)version_help.ps1 @@ -144,7 +146,7 @@ true true true - hid.lib;Cfgmgr32.lib;setupapi.lib;%(AdditionalDependencies) + hid.lib;Cfgmgr32.lib;setupapi.lib;CefInjectLib.lib;%(AdditionalDependencies) Upading version based on git;%(Outputs) diff --git a/GlosSIWatchdog/dllmain.cpp b/GlosSIWatchdog/dllmain.cpp index f885b1c..f9fac98 100644 --- a/GlosSIWatchdog/dllmain.cpp +++ b/GlosSIWatchdog/dllmain.cpp @@ -27,10 +27,13 @@ limitations under the License. #include + #include "../version.hpp" #include "../common/Settings.h" #include "../common/HidHide.h" +#include + bool IsProcessRunning(DWORD pid) { const HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid); @@ -116,6 +119,10 @@ DWORD WINAPI watchdog(HMODULE hModule) HidHide hidhide; hidhide.disableHidHide(); + spdlog::info("Uninstalling GlosSITweaks"); + auto steam_tweaks = CEFInject::SteamTweaks(); + steam_tweaks.uninstallTweaks(true); + if (Settings::launch.closeOnExit) { spdlog::info("Closing launched processes"); diff --git a/Installer/Installer.nsi b/Installer/Installer.nsi index a27ec7f..71d0dee 100644 --- a/Installer/Installer.nsi +++ b/Installer/Installer.nsi @@ -3,7 +3,7 @@ !define APP_NAME "GlosSI" !define COMP_NAME "Peter Repukat - Flatspotsoftware" !define WEB_SITE "https://glossi.flatspot.pictures/" -!define VERSION "0.1.2.0-31-gd2b43ff" +!define VERSION "0.1.2.0-41-g7165813" !define COPYRIGHT "Peter Repukat - FlatspotSoftware © 2017-2022" !define DESCRIPTION "SteamInput compatibility tool" !define INSTALLER_NAME "GlosSI-Installer.exe" diff --git a/SteamTweaks/rollup.config.js b/SteamTweaks/rollup.config.js index 3eec110..092579f 100644 --- a/SteamTweaks/rollup.config.js +++ b/SteamTweaks/rollup.config.js @@ -27,6 +27,7 @@ export default [ dir: 'dist', sourcemap: "inline", format: 'iife', + // name: 'GlosSITweaks' // don't use name; don't pollute global namespace }, plugins: [tsPluginConf], }, @@ -37,6 +38,7 @@ export default [ file: file.replace('src', 'dist').replace(/\.ts$/, '.js'), sourcemap: "inline", format: 'iife', + // name: path.basename(file).replace(/\.ts$/, '') // don't use name; don't pollute global namespace }, plugins: [tsPluginConf], } diff --git a/SteamTweaks/src/GlosSITweaks.ts b/SteamTweaks/src/GlosSITweaks.ts index 4f710af..29e5c6c 100644 --- a/SteamTweaks/src/GlosSITweaks.ts +++ b/SteamTweaks/src/GlosSITweaks.ts @@ -1,4 +1,8 @@ import type { SteamConfig } from './common/util/types'; +import { fetchWithTimeout } from './common/util/util'; + + + class SteamTargetApi { public getSteamSettings(): Promise { return fetch('http://localhost:8756/steam_settings') @@ -8,8 +12,16 @@ class SteamTargetApi { ) ); } + + public getGlosSIActive() { + return fetchWithTimeout('http://localhost:8756/', { timeout: 10000 }) + .then( + () => true + ).catch((e) => false); + } } + class GlosSIApiCtor { public readonly SteamTarget: SteamTargetApi = new SteamTargetApi(); } @@ -51,8 +63,23 @@ const installGlosSIApi = () => { } }; window.GlosSITweaks.GlosSI.install(); + + const glossiCheckInterval = setInterval(() => { + if (window.GlosSIApi) { + window.GlosSIApi.SteamTarget.getGlosSIActive().then((active) => { + if (!active) { + window?.GlosSITweaks?.GlosSI?.uninstall?.(); + } + }); + return; + } + clearTimeout(glossiCheckInterval) + }, 5000) + }; if (!window.GlosSITweaks || !window.GlosSIApi) { installGlosSIApi(); } + +export default !!window.GlosSITweaks && !!window.GlosSIApi; diff --git a/SteamTweaks/src/Tweaks/Overlay/SharedContext/HideFPSCounter.ts b/SteamTweaks/src/Tweaks/Overlay/SharedContext/HideFPSCounter.ts index bfb99d0..7bbf1bb 100644 --- a/SteamTweaks/src/Tweaks/Overlay/SharedContext/HideFPSCounter.ts +++ b/SteamTweaks/src/Tweaks/Overlay/SharedContext/HideFPSCounter.ts @@ -4,7 +4,7 @@ import { initTweak } from "../../../common/tweakApi"; const backup: { originalFpsCorner?: number } = {}; -initTweak('AnotherTweak', { +initTweak('HideFPSCounter', { install: async () => { backup.originalFpsCorner = Number( ((await GlosSIApi.SteamTarget.getSteamSettings()).system as SteamConfig) @@ -13,6 +13,11 @@ initTweak('AnotherTweak', { SteamClient.Settings.SetInGameOverlayShowFPSCorner(0); }, uninstall: () => { + console.log('uninstalling HideFPSCounter Tweak. Restoring FPS Counter corner: ', backup.originalFpsCorner); SteamClient.Settings.SetInGameOverlayShowFPSCorner((backup.originalFpsCorner ?? 0) as 0 | 1 | 2 | 3 | 4); + setTimeout(() => { + // steam might not actually register the setting?! Try again like 10 seconds later... ¯\_(ツ)_/¯ + SteamClient.Settings.SetInGameOverlayShowFPSCorner((backup.originalFpsCorner ?? 0) as 0 | 1 | 2 | 3 | 4); + }, 10 * 1000); } }); diff --git a/SteamTweaks/src/common/util/util.ts b/SteamTweaks/src/common/util/util.ts new file mode 100644 index 0000000..ac46143 --- /dev/null +++ b/SteamTweaks/src/common/util/util.ts @@ -0,0 +1,12 @@ +export const fetchWithTimeout = async (input: RequestInfo | URL, init?: RequestInit & { timeout: number }) => { + const { timeout = 8000 } = init || {}; + + const controller = new AbortController(); + const id = setTimeout(() => controller.abort(), timeout); + const response = await fetch(input, { + ...(init ||{}), + signal: controller.signal + }); + clearTimeout(id); + return response; + } \ No newline at end of file