diff --git a/GlosSITarget/GlosSITarget.vcxproj b/GlosSITarget/GlosSITarget.vcxproj index e8a420f..ff5cb3a 100644 --- a/GlosSITarget/GlosSITarget.vcxproj +++ b/GlosSITarget/GlosSITarget.vcxproj @@ -153,6 +153,7 @@ + diff --git a/GlosSITarget/GlosSITarget.vcxproj.filters b/GlosSITarget/GlosSITarget.vcxproj.filters index 6a20838..958a665 100644 --- a/GlosSITarget/GlosSITarget.vcxproj.filters +++ b/GlosSITarget/GlosSITarget.vcxproj.filters @@ -72,6 +72,9 @@ Source Files\imgui-sfml + + Source Files\imgui + diff --git a/GlosSITarget/HidHide.cpp b/GlosSITarget/HidHide.cpp index e012593..1791e07 100644 --- a/GlosSITarget/HidHide.cpp +++ b/GlosSITarget/HidHide.cpp @@ -30,6 +30,8 @@ limitations under the License. #include // +#include "Overlay.h" + #include #include #include @@ -90,7 +92,7 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path) 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}; if (std::ranges::none_of(whitelist, [&path](auto ep) { // make copy! - auto p = path; // non-const(!) copy of path + 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; @@ -100,25 +102,26 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path) } setAppWhiteList(whitelist); - const auto device_list = GetHidDeviceList(); - auto blacklist = getBlackListDevices(); + avail_devices_ = GetHidDeviceList(); + blacklisted_devices_ = getBlackListDevices(); - for (const auto& dev : device_list) { - if (std::ranges::none_of(blacklist, [&dev](const auto& blackdev) { + 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; - })) { + })) { if (!dev.device_instance_path.empty()) { - blacklist.push_back(dev.device_instance_path); + blacklisted_devices_.push_back(dev.device_instance_path); } if (!dev.device_instance_path.empty()) { - blacklist.push_back(dev.base_container_device_instance_path); + blacklisted_devices_.push_back(dev.base_container_device_instance_path); } } } - setBlacklistDevices(blacklist); + setBlacklistDevices(blacklisted_devices_); setActive(true); closeCtrlDevice(); - spdlog::info("Hid Gaming Devices"); // TODO: add list of blacklisted devices + spdlog::info("Hid Gaming Devices; Enabling Overlay element..."); + enableOverlayElement(); } void HidHide::disableHidHide() @@ -126,7 +129,62 @@ void HidHide::disableHidHide() openCtrlDevice(); setActive(false); closeCtrlDevice(); - spdlog::info("Un-hid Gaming Devices"); // TODO: add list of blacklisted devices + spdlog::info("Un-hid Gaming Devices"); +} + +void HidHide::enableOverlayElement() +{ + Overlay::AddOverlayElem([this]() { + if (overlay_elem_clock_.getElapsedTime().asSeconds() > OVERLAY_ELEM_REFRESH_INTERVAL_S_) { + openCtrlDevice(); + bool hidehide_state_store = hidhide_active_; + if (hidhide_active_) { + setActive(false); + } + avail_devices_ = GetHidDeviceList(); + blacklisted_devices_ = getBlackListDevices(); + if (hidehide_state_store) { + setActive(true); + } + closeCtrlDevice(); + overlay_elem_clock_.restart(); + } + ImGui::Begin("Hidden Devices"); + ImGui::BeginChild("Inner", {0.f, ImGui::GetItemRectSize().y - 48}, 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()); + } + setBlacklistDevices(blacklisted_devices_); + closeCtrlDevice(); + } + }); + ImGui::EndChild(); + if (ImGui::Checkbox("Devices Hidden", &hidhide_active_)) { + openCtrlDevice(); + setActive(hidhide_active_); + closeCtrlDevice(); + } + ImGui::End(); + }); } std::wstring HidHide::DosDeviceForVolume(const std::wstring& volume) @@ -166,7 +224,7 @@ std::vector HidHide::getBlackListDevices() const return BufferToStringVec(buffer); } -bool HidHide::getActive() const +bool HidHide::getActive() { DWORD bytes_needed; BOOLEAN res; @@ -175,6 +233,7 @@ bool HidHide::getActive() const spdlog::error("Couldn't retrieve HidHide State"); return false; } + hidhide_active_ = res; return res; } @@ -198,13 +257,15 @@ void HidHide::setBlacklistDevices(const std::vector& blacklist) co } } -void HidHide::setActive(bool active) const +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)) { spdlog::error("Couldn't set HidHide State"); + return; } + hidhide_active_ = active; } DWORD HidHide::getRequiredOutputBufferSize(IOCTL_TYPE type) const @@ -352,6 +413,10 @@ HidHide::SmallHidInfo HidHide::GetDeviceInfo(const DeviceInstancePath& instance_ res.name = (HidD_GetProductString(device_object.get(), buffer.data(), static_cast(sizeof(WCHAR) * buffer.size())) ? buffer : L""); + // Valve emulated gamepad PID/VID; mirrord by ViGEm + if (attributes.VendorID == 0x28de && attributes.ProductID == 0x11FF) { + res.name = std::wstring(L"ViGEm Emulated: ") + res.name; + } res.base_container_device_instance_path = BaseContainerDeviceInstancePath(instance_path); res.gaming_device = IsGamingDevice(attributes, capabilities); diff --git a/GlosSITarget/HidHide.h b/GlosSITarget/HidHide.h index bd46a65..ee90d5a 100644 --- a/GlosSITarget/HidHide.h +++ b/GlosSITarget/HidHide.h @@ -24,6 +24,7 @@ limitations under the License. #include #include #include +#include class HidHide { private: @@ -65,6 +66,14 @@ class HidHide { private: HANDLE hidhide_handle = nullptr; + void enableOverlayElement(); + sf::Clock overlay_elem_clock_; + + std::vector blacklisted_devices_; + std::vector avail_devices_; + bool hidhide_active_ = false; + static constexpr int OVERLAY_ELEM_REFRESH_INTERVAL_S_ = 5; + static inline constexpr std::array whitelist_executeables_{ L"GameOverlayUI.exe", L"steam.exe", @@ -74,10 +83,10 @@ class HidHide { [[nodiscard]] std::vector getAppWhiteList() const; [[nodiscard]] std::vector getBlackListDevices() const; - [[nodiscard]] bool getActive() const; + [[nodiscard]] bool getActive(); void setAppWhiteList(const std::vector& whitelist) const; void setBlacklistDevices(const std::vector& blacklist) const; - void setActive(bool active) const; + void setActive(bool active); [[nodiscard]] DWORD getRequiredOutputBufferSize(IOCTL_TYPE type) const; diff --git a/GlosSITarget/Overlay.cpp b/GlosSITarget/Overlay.cpp index 8a1558a..a35c03c 100644 --- a/GlosSITarget/Overlay.cpp +++ b/GlosSITarget/Overlay.cpp @@ -1,11 +1,5 @@ #include "Overlay.h" -#include - -#define IMGUI_USER_CONFIG "imconfig.h" -#include "imgui-SFML.h" -#include "imgui.h" - Overlay::Overlay(sf::RenderWindow& window, const std::function& on_close) : window_(window), on_close_(on_close) { ImGui::SFML::Init(window_); @@ -24,14 +18,14 @@ Overlay::Overlay(sf::RenderWindow& window, const std::function& on_close style.ScrollbarRounding = 12; style.GrabRounding = 5; - ImVec4* colors = ImGui::GetStyle().Colors; +ImVec4* colors = ImGui::GetStyle().Colors; colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f); colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f); colors[ImGuiCol_WindowBg] = ImVec4(0.10f, 0.13f, 0.14f, 0.95f); colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f); colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); - colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f); - colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 0.05f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.24f); colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); colors[ImGuiCol_FrameBgHovered] = ImVec4(0.12f, 0.20f, 0.28f, 1.00f); colors[ImGuiCol_FrameBgActive] = ImVec4(0.09f, 0.12f, 0.14f, 1.00f); @@ -108,6 +102,8 @@ void Overlay::update() std::ranges::for_each(OVERLAY_ELEMS_, [](const auto& fn) { fn(); }); + ImGui::ShowDemoWindow(); + if (closeButton()) { return; } diff --git a/GlosSITarget/Overlay.h b/GlosSITarget/Overlay.h index 44778e2..33127ae 100644 --- a/GlosSITarget/Overlay.h +++ b/GlosSITarget/Overlay.h @@ -5,6 +5,10 @@ #include +#define IMGUI_USER_CONFIG "imconfig.h" +#include "imgui-SFML.h" +#include "imgui.h" + class Overlay { public: Overlay(sf::RenderWindow& window, const std::function& on_close); diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp index 858f344..efeb833 100644 --- a/GlosSITarget/SteamTarget.cpp +++ b/GlosSITarget/SteamTarget.cpp @@ -27,8 +27,8 @@ limitations under the License. SteamTarget::SteamTarget(int argc, char* argv[]) : window_([this] { run_ = false; }, getScreenshotHotkey()), - detector_([this](bool overlay_open) { onOverlayChanged(overlay_open); }), - overlay_(window_.getOverlay()) + overlay_(window_.getOverlay()), + detector_([this](bool overlay_open) { onOverlayChanged(overlay_open); }) { target_window_handle_ = window_.getSystemHandle(); } @@ -40,18 +40,20 @@ int SteamTarget::run() Application will not function!"); window_.setClickThrough(false); overlay_.setEnabled(true); + steam_overlay_present_ = false; } 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); + steam_overlay_present_ = true; } run_ = true; #ifdef _WIN32 hidhide_.hideDevices(steam_path_); - input_redirector_.run(); + input_redirector_.run(); #endif keepControllerConfig(true); diff --git a/GlosSITarget/SteamTarget.h b/GlosSITarget/SteamTarget.h index bfd6014..8580a38 100644 --- a/GlosSITarget/SteamTarget.h +++ b/GlosSITarget/SteamTarget.h @@ -46,6 +46,8 @@ class SteamTarget { std::vector getOverlayHotkey(); std::vector getScreenshotHotkey(); + bool steam_overlay_present_ = false; + // Keep controllerConfig even is window is switched. // On Windoze hooking "GetForeGroundWindow" is enough; void keepControllerConfig(bool keep);