diff --git a/GlosSITarget/GlosSITarget.vcxproj b/GlosSITarget/GlosSITarget.vcxproj index 1b6fbec..e8a420f 100644 --- a/GlosSITarget/GlosSITarget.vcxproj +++ b/GlosSITarget/GlosSITarget.vcxproj @@ -127,7 +127,7 @@ stdcpp20 - Console + Windows true hid.lib;Cfgmgr32.lib;opengl32.lib;sfml-window-d.lib;sfml-system-d.lib;sfml-graphics-d.lib;dwmapi.lib;xinput9_1_0.lib;setupapi.lib;ViGEmClient.lib;%(AdditionalDependencies) @@ -143,7 +143,7 @@ stdcpp20 - Console + Windows true true true @@ -153,7 +153,6 @@ - @@ -174,6 +173,7 @@ + diff --git a/GlosSITarget/GlosSITarget.vcxproj.filters b/GlosSITarget/GlosSITarget.vcxproj.filters index f0ce82a..6a20838 100644 --- a/GlosSITarget/GlosSITarget.vcxproj.filters +++ b/GlosSITarget/GlosSITarget.vcxproj.filters @@ -72,9 +72,6 @@ Source Files\imgui-sfml - - Source Files\imgui - @@ -110,6 +107,9 @@ Header Files\imgui-sfml + + Header Files + diff --git a/GlosSITarget/InputRedirector.cpp b/GlosSITarget/InputRedirector.cpp index 0dc339a..179effe 100644 --- a/GlosSITarget/InputRedirector.cpp +++ b/GlosSITarget/InputRedirector.cpp @@ -53,6 +53,7 @@ void InputRedirector::run() void InputRedirector::stop() { run_ = false; + controller_thread_.join(); if (vigem_connected_) { for (const auto& target : vt_x360_) { vigem_target_remove(driver_, target); diff --git a/GlosSITarget/Overlay.cpp b/GlosSITarget/Overlay.cpp index 62a24fa..4f8127c 100644 --- a/GlosSITarget/Overlay.cpp +++ b/GlosSITarget/Overlay.cpp @@ -1,9 +1,8 @@ #include "Overlay.h" #define IMGUI_USER_CONFIG "imconfig.h" -#include "imgui.h" #include "imgui-SFML.h" - +#include "imgui.h" Overlay::Overlay(sf::RenderWindow& window, std::function on_close) : window_(window), on_close_(on_close) { @@ -84,6 +83,12 @@ void Overlay::setEnabled(bool enabled) enabled_ = enabled; } +bool Overlay::isEnabled() const +{ + return enabled_; +} + + bool Overlay::toggle() { enabled_ = !enabled_; @@ -94,14 +99,16 @@ void Overlay::update() { ImGui::SFML::Update(window_, update_clock_.restart()); - bool open = true; + showLogs(); + if (enabled_) { window_.clear(sf::Color(0, 0, 0, 64)); // make window slightly dim screen with overlay - ImGui::ShowDemoWindow(&open); + + if (closeButton()) { return; - } + } } ImGui::SFML::Render(window_); @@ -117,15 +124,61 @@ void Overlay::Shutdown() ImGui::SFML::Shutdown(); } -void Overlay::ShowNotification(std::string noti_text) -{} +void Overlay::ShowNotification(const spdlog::details::log_msg& msg) +{ + LOG_MSGS_.push_back({.time = msg.time, .level = msg.level, .payload = msg.payload.data()}); +} + +void Overlay::showLogs() const +{ + std::vector logs; + if (enabled_) { + logs = LOG_MSGS_; + } + else { + std::ranges::copy_if(LOG_MSGS_, + std::back_inserter(logs), + [](const auto& log) { + return log.time.time_since_epoch() + std::chrono::seconds(LOG_RETENTION_TIME_) > std::chrono::system_clock::now().time_since_epoch(); + }); + } + if (logs.empty()) + return; + if (!enabled_) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {32.f, 32.f}); + ImGui::Begin("Log", nullptr, + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar); + } + else { + ImGui::Begin("Log", nullptr); + } + std::ranges::for_each(LOG_MSGS_, [](const auto& msg) { + switch (msg.level) { + case spdlog::level::warn: + ImGui::TextColored({1.f, 0.8f, 0.f, 1.f}, msg.payload.data()); + break; + case spdlog::level::err: + ImGui::TextColored({.8f, 0.0f, 0.f, 1.f}, msg.payload.data()); + break; + case spdlog::level::debug: + ImGui::TextColored({.8f, 0.8f, 0.8f, .9f}, msg.payload.data()); + break; + default: + ImGui::Text(msg.payload.data()); + } + }); + ImGui::End(); + if (!enabled_) { + ImGui::PopStyleVar(); + } +} bool Overlay::closeButton() const { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0, 0}); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.f, 0.f, 0.0f)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.6f, 0.f, 0.f, 0.9f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered,ImVec4(1.f, 0.16f, 0.16f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.f, 0.16f, 0.16f, 1.00f)); ImGui::Begin("##CloseButton", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize); ImGui::SetWindowSize({56 + 24, 32 + 24}); ImGui::SetWindowPos({window_.getSize().x - ImGui::GetWindowWidth() + 24, -24}); diff --git a/GlosSITarget/Overlay.h b/GlosSITarget/Overlay.h index f8237ba..788f66c 100644 --- a/GlosSITarget/Overlay.h +++ b/GlosSITarget/Overlay.h @@ -3,21 +3,34 @@ #include #include +#include + class Overlay { public: Overlay(sf::RenderWindow& window, std::function on_close); void setEnabled(bool enabled); + bool isEnabled() const; bool toggle(); void update(); static void ProcessEvent(sf::Event evnt); static void Shutdown(); - static void ShowNotification(std::string noti_text); + static void ShowNotification(const spdlog::details::log_msg& msg); private: sf::RenderWindow& window_; sf::Clock update_clock_; bool enabled_ = true; std::function on_close_; + void showLogs() const; bool closeButton() const; + + struct Log { + std::chrono::system_clock::time_point time; + spdlog::level::level_enum level; + std::string payload; + }; + static inline std::vector LOG_MSGS_; + static constexpr int LOG_RETENTION_TIME_ = 5; + }; diff --git a/GlosSITarget/OverlayLogSink.h b/GlosSITarget/OverlayLogSink.h new file mode 100644 index 0000000..48c876d --- /dev/null +++ b/GlosSITarget/OverlayLogSink.h @@ -0,0 +1,40 @@ +#pragma once + + +#include "Overlay.h" + +namespace spdlog { +namespace sinks { + +template +class overlay_sink : public spdlog::sinks::base_sink { + public: + overlay_sink() = default; + + protected: + void sink_it_(const spdlog::details::log_msg& msg) override + { + Overlay::ShowNotification(msg); + } + + void flush_() override + { + // Do nothing because statement executed in sink_it_(). + } + + void set_pattern_(const std::string& pattern) override + { + // Don't format log message. + } + + void set_formatter_(std::unique_ptr sink_formatter) override + { + // Don't format log message. + } + +}; + +using overlay_sink_mt = overlay_sink; + +} // namespace sinks +} // namespace spdlog \ No newline at end of file diff --git a/GlosSITarget/SteamOverlayDetector.cpp b/GlosSITarget/SteamOverlayDetector.cpp index 336f6d1..f25acce 100644 --- a/GlosSITarget/SteamOverlayDetector.cpp +++ b/GlosSITarget/SteamOverlayDetector.cpp @@ -67,4 +67,11 @@ void SteamOverlayDetector::update() } } #endif -} \ No newline at end of file +} + +bool SteamOverlayDetector::IsSteamInjected() +{ +#ifdef _WIN32 + return GetModuleHandle(L"GameOverlayRenderer64.dll") != nullptr; +#endif +} diff --git a/GlosSITarget/SteamOverlayDetector.h b/GlosSITarget/SteamOverlayDetector.h index ff60e6c..74b305a 100644 --- a/GlosSITarget/SteamOverlayDetector.h +++ b/GlosSITarget/SteamOverlayDetector.h @@ -27,6 +27,7 @@ class SteamOverlayDetector { explicit SteamOverlayDetector( std::function overlay_changed = [](bool) {}); void update(); + static bool IsSteamInjected(); private: std::function overlay_changed_; diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp index 9af15c9..858f344 100644 --- a/GlosSITarget/SteamTarget.cpp +++ b/GlosSITarget/SteamTarget.cpp @@ -35,12 +35,16 @@ SteamTarget::SteamTarget(int argc, char* argv[]) int SteamTarget::run() { - // TODO: Hide GlosSI overlay not based on time, but on game launch. - sf::Clock mock_clock; - bool mock_clock_flag = SteamOverlayDetector::IsSteamInjected(); - if (!mock_clock_flag) { - spdlog::warn("Steam Overlay not detected. Keeping GlosSI Overlay!\n\ + if (!SteamOverlayDetector::IsSteamInjected()) { + spdlog::warn("Steam-overlay not detected. Showing GlosSI-overlay!\n\ Application will not function!"); + window_.setClickThrough(false); + overlay_.setEnabled(true); + } else { + spdlog::info("Steam-overlay detected."); + spdlog::warn("Open/Close Steam-overlay twice to show GlosSI-overlay"); // Just to color output and really get users attention + window_.setClickThrough(true); + overlay_.setEnabled(false); } run_ = true; @@ -52,11 +56,6 @@ Application will not function!"); keepControllerConfig(true); while (run_) { - if (mock_clock_flag && mock_clock.getElapsedTime().asSeconds() > 5) { - window_.setClickThrough(true); - overlay_.setEnabled(false); - mock_clock_flag = false; - } detector_.update(); window_.update(); overlayHotkeyWorkaround(); @@ -72,7 +71,6 @@ Application will not function!"); void SteamTarget::onOverlayChanged(bool overlay_open) { - window_.setClickThrough(!overlay_open); if (overlay_open) { focusWindow(target_window_handle_); } @@ -84,12 +82,22 @@ void SteamTarget::onOverlayChanged(bool overlay_open) } else { if (overlay_trigger_clock_.getElapsedTime().asSeconds() <= overlay_trigger_max_seconds_) { - window_.setClickThrough(!overlay_.toggle()); + const auto ov_opened = overlay_.toggle(); + window_.setClickThrough(!ov_opened); + if (ov_opened) { + spdlog::info("Opened GlosSI-overlay"); + focusWindow(target_window_handle_); + } else { + focusWindow(last_foreground_window_); + spdlog::info("Closed GlosSI-overlay"); + } } overlay_trigger_flag_ = false; } - - focusWindow(last_foreground_window_); + if (!overlay_.isEnabled()) { + window_.setClickThrough(!overlay_open); + focusWindow(last_foreground_window_); + } } } @@ -98,19 +106,23 @@ void SteamTarget::focusWindow(WindowHandle hndl) #ifdef _WIN32 if (hndl == target_window_handle_) { - spdlog::info("Bring own window to foreground"); + spdlog::debug("Bring own window to foreground"); } else { - spdlog::info("Bring window \"{:#x}\" to foreground", reinterpret_cast(hndl)); + spdlog::debug("Bring window \"{:#x}\" to foreground", reinterpret_cast(hndl)); } keepControllerConfig(false); // unhook GetForegroundWindow - last_foreground_window_ = GetForegroundWindow(); - const DWORD fg_thread = GetWindowThreadProcessId(last_foreground_window_, nullptr); + const auto current_fgw = GetForegroundWindow(); + if (current_fgw != target_window_handle_) { + last_foreground_window_ = current_fgw; + } + const auto fg_thread = GetWindowThreadProcessId(current_fgw, nullptr); + keepControllerConfig(true); // re-hook GetForegroundWindow // lot's of ways actually bringing our window to foreground... - const DWORD current_thread = GetCurrentThreadId(); + const auto current_thread = GetCurrentThreadId(); AttachThreadInput(current_thread, fg_thread, TRUE); SetForegroundWindow(hndl); @@ -231,14 +243,14 @@ void SteamTarget::keepControllerConfig(bool keep) { #ifdef _WIN32 if (keep && !getFgWinHook.IsInstalled()) { - spdlog::debug("Hooking GetForegroudnWindow (in own process)"); + spdlog::debug("Hooking GetForegroundWindow (in own process)"); getFgWinHook.Install(&GetForegroundWindow, &keepFgWindowHookFn, subhook::HookFlags::HookFlag64BitOffset); if (!getFgWinHook.IsInstalled()) { spdlog::error("Couldn't install GetForegroundWindow hook!"); } } else if (!keep && getFgWinHook.IsInstalled()) { - spdlog::debug("Un-Hooking GetForegroudnWindow (in own process)"); + spdlog::debug("Un-Hooking GetForegroundWindow (in own process)"); getFgWinHook.Remove(); if (getFgWinHook.IsInstalled()) { spdlog::error("Couldn't un-install GetForegroundWindow hook!"); @@ -261,7 +273,7 @@ void SteamTarget::overlayHotkeyWorkaround() [](const auto& key) { return sf::Keyboard::isKeyPressed(keymap::sfkey[key]); })) { - spdlog::debug("Detected overlay hotkey(s)"); + spdlog::trace("Detected overlay hotkey(s)"); pressed = true; std::ranges::for_each(overlay_hotkey_, [this](const auto& key) { #ifdef _WIN32 @@ -270,7 +282,7 @@ void SteamTarget::overlayHotkeyWorkaround() #endif }); - spdlog::debug("Sending Overlay KeyDown events..."); + spdlog::trace("Sending Overlay KeyDown events..."); } else if (pressed) { pressed = false; @@ -281,6 +293,6 @@ void SteamTarget::overlayHotkeyWorkaround() #endif }); - spdlog::debug("Sending Overlay KeyUp events..."); + spdlog::trace("Sending Overlay KeyUp events..."); } } diff --git a/GlosSITarget/main.cpp b/GlosSITarget/main.cpp index 8451df8..a31d386 100644 --- a/GlosSITarget/main.cpp +++ b/GlosSITarget/main.cpp @@ -23,8 +23,9 @@ limitations under the License. #include #include #include +#include "OverlayLogSink.h" + -#define CONSOLE #ifdef _WIN32 #ifdef CONSOLE int main(int argc, char* argv[]) @@ -47,7 +48,15 @@ int main(int argc, char* argv[]) auto file_sink = std::make_shared("/tmp/glossitarget.log", true); #endif file_sink->set_level(spdlog::level::trace); - std::vector sinks{file_sink, console_sink}; + + const auto overlay_sink = std::make_shared(); +#ifdef _DEBUG + overlay_sink->set_level(spdlog::level::debug); // TODO: make configurable +#else + overlay_sink->set_level(spdlog::level::info); +#endif + + std::vector sinks{file_sink, console_sink, overlay_sink}; auto logger = std::make_shared("log", sinks.begin(), sinks.end()); logger->set_level(spdlog::level::trace); logger->flush_on(spdlog::level::info);