From c467e5aa9bb13b16727461ec9af53d44829fd9a4 Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Sun, 11 Mar 2018 23:10:41 +0100 Subject: [PATCH] cleanup --- SteamTarget/SteamTargetRenderer.cpp | 543 ---------------------------- SteamTarget/SteamTargetRenderer.h | 128 ------- 2 files changed, 671 deletions(-) delete mode 100644 SteamTarget/SteamTargetRenderer.cpp delete mode 100644 SteamTarget/SteamTargetRenderer.h diff --git a/SteamTarget/SteamTargetRenderer.cpp b/SteamTarget/SteamTargetRenderer.cpp deleted file mode 100644 index 81d8310..0000000 --- a/SteamTarget/SteamTargetRenderer.cpp +++ /dev/null @@ -1,543 +0,0 @@ -/* -Copyright 2018 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. -*/ -#include "SteamTargetRenderer.h" - -std::atomic SteamTargetRenderer::overlayOpen = false; -HHOOK SteamTargetRenderer::hook = nullptr; -std::atomic SteamTargetRenderer::bHookSteam = false; - - -SteamTargetRenderer::SteamTargetRenderer(int& argc, char** argv) : QApplication(argc, argv) -{ - getSteamOverlay(); - loadLogo(); - - SetConsoleCtrlHandler(reinterpret_cast(ConsoleCtrlCallback), true); - if (this->arguments().size() == 1) - { - std::cerr << "Target configuration file must be specified!" << std::endl; - MessageBoxW(NULL, L"Target configuration file must be specified!", L"GloSC-SteamTarget", MB_OK); - - QTimer::singleShot(0, this, []() - { - QApplication::exit(1); - }); //call after ctor - - } else { - QSettings settings(this->arguments().at(1), QSettings::IniFormat); - settings.beginGroup("BaseConf"); - const QStringList childKeys = settings.childKeys(); - for (auto &childkey : childKeys) - { - if (childkey == "bDrawDebugEdges") - { - bDrawDebugEdges = settings.value(childkey).toBool(); - } - else if (childkey == "bEnableOverlay") { - bDrawOverlay = settings.value(childkey).toBool(); - } - else if (childkey == "bEnableControllers") { - bEnableControllers = settings.value(childkey).toBool(); - } - else if (childkey == "bHookSteam") { - bHookSteam = settings.value(childkey).toBool(); - } - else if (childkey == "bUseDesktopConfig") { - bUseDesktopConfig = settings.value(childkey).toBool(); - } - } - settings.endGroup(); - -#ifndef NDEBUG - bDrawDebugEdges = true; -#endif // NDEBUG - sfCshape = sf::CircleShape(100.f); - sfCshape.setFillColor(sf::Color(128, 128, 128, 128)); - sfCshape.setOrigin(sf::Vector2f(100, 100)); - sf::VideoMode mode = sf::VideoMode::getDesktopMode(); - sfWindow.create(sf::VideoMode(mode.width - 16, mode.height - 32), "GloSC_OverlayWindow"); //Window is too large ; always 16 and 32 pixels? - sf::Style::None breaks transparency! - sfWindow.setFramerateLimit(iRefreshRate); - sfWindow.setPosition(sf::Vector2i(0, 0)); - makeSfWindowTransparent(sfWindow); - - sfWindow.setActive(false); - consoleHwnd = GetConsoleWindow(); //We need a console for a dirty hack to make sure we stay in game bindings - //QT Windows cause trouble with the overlay, so we cannot use them -#ifdef NDEBUG - ShowWindow(consoleHwnd, SW_HIDE); -#endif // NDEBUG - - - if (bEnableControllers) - controllerThread.run(); - - QTimer::singleShot(2000, this, &SteamTargetRenderer::launchApp); // lets steam do its thing - - if (hmodGameOverlayRenderer != nullptr) - { - //Hook MessageQueue to detect if overlay gets opened / closed - //Steam Posts a Message with 0x14FA / 0x14F7 when the overlay gets opened / closed - hook = SetWindowsHookEx(WH_GETMESSAGE, HookCallback, nullptr, GetCurrentThreadId()); - } - - - if (bUseDesktopConfig) - { - bHookSteam = false; - QTimer::singleShot(1000, this, []() - { - HWND taskbar = FindWindow(L"Shell_TrayWnd", nullptr); - SetFocus(taskbar); - SetForegroundWindow(taskbar); - }); - } - } - -} - -SteamTargetRenderer::~SteamTargetRenderer() -{ - - if (hmodGameOverlayRenderer != nullptr) - { - UnhookWindowsHookEx(hook); - } - - renderThread.join(); - if (controllerThread.isRunning()) - controllerThread.stop(); -} - -void SteamTargetRenderer::run() -{ - renderThread = std::thread(&SteamTargetRenderer::RunSfWindowLoop, this); -} - -void SteamTargetRenderer::stop() -{ - bRunLoop = false; - unhookBindings(); - QApplication::exit(0); -} - - -void SteamTargetRenderer::RunSfWindowLoop() -{ - if (!bRunLoop) - return; - sfWindow.setActive(true); - - bool hasJustLaunched = true; - - if (bDrawOverlay) - SetWindowPos(sfWindow.getSystemHandle(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_ASYNCWINDOWPOS); - else - { - ShowWindow(sfWindow.getSystemHandle(), SW_HIDE); - sfWindow.setFramerateLimit(1); //Window is not shown anyway, - ShowWindow(consoleHwnd, SW_SHOW); //Show the console window so the user sees SOMETHING - } - - - while (sfWindow.isOpen() && bRunLoop) - { - - sf::Event event; - while (sfWindow.pollEvent(event)) - { - if (event.type == sf::Event::Closed) - sfWindow.close(); - } - - sfWindow.clear(sf::Color::Transparent); - - if (bDrawDebugEdges) - drawDebugEdges(); - - //we inject and hook here to spare IPC and let the dll grab the steam appID of the launched process when the config switches (config switches w/ focus) - if (hasJustLaunched) - { - if (bHookSteam) - hookBindings(); //cleanup - unhooking / unloading of dll is managed by the GloSC gamelauncher rather than here - hasJustLaunched = false; - } - - - //Window focus trickery - if (hmodGameOverlayRenderer != nullptr) - { - if (overlayOpen) - { - if (!bNeedFocusSwitch) - { - bNeedFocusSwitch = true; - - hwForeGroundWindow = GetForegroundWindow(); - - std::cout << "Saving current ForegorundWindow HWND: " << hwForeGroundWindow << std::endl; - std::cout << "Activating OverlayWindow" << std::endl; - - SetWindowLong(sfWindow.getSystemHandle(), GWL_EXSTYLE, WS_EX_LAYERED); //make overlay window clickable - - //Actually activate the overlaywindow - stealFocus(sfWindow.getSystemHandle()); - - //Move the mouse cursor inside the overlaywindow - //this is neccessary because steam doesn't want to switch to big picture bindings if mouse isn't inside - moveMouseIntoOverlay(); - } - sfWindow.draw(backgroundSprite); - } else { - if (bNeedFocusSwitch) - { - std::cout << "Deactivating OverlayWindow" << std::endl; - - //make overlaywindow clickthrough - WS_EX_TRANSPARENT - again - SetWindowLong(sfWindow.getSystemHandle(), GWL_EXSTYLE, WS_EX_LAYERED | WS_EX_TRANSPARENT); - - std::cout << "Switching to previously focused window" << std::endl; - - //switch back the the previosly focused window - stealFocus(hwForeGroundWindow); - bNeedFocusSwitch = false; - } - } - } - sfWindow.display(); - } - stop(); -} - -void SteamTargetRenderer::getSteamOverlay() -{ - hmodGameOverlayRenderer = GetModuleHandle(overlayModuleName); - - if (hmodGameOverlayRenderer != nullptr) - { - std::cout << overlayModuleName << " found; Module at: 0x" << hmodGameOverlayRenderer << std::endl; - } -} - - -void SteamTargetRenderer::makeSfWindowTransparent(sf::RenderWindow & window) -{ - HWND hwnd = window.getSystemHandle(); - SetWindowLong(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP &~WS_CAPTION); - SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST); - - MARGINS margins; - margins.cxLeftWidth = -1; - - DwmExtendFrameIntoClientArea(hwnd, &margins); - SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); - - - window.clear(sf::Color::Transparent); - window.display(); -} - -void SteamTargetRenderer::drawDebugEdges() -{ - sfCshape.setPosition(sf::Vector2f(-25, -25)); - sfWindow.draw(sfCshape); - sfCshape.setPosition(sf::Vector2f(sfWindow.getSize().x + 25, -25)); - sfWindow.draw(sfCshape); - sfCshape.setPosition(sf::Vector2f(-25, sfWindow.getSize().y)); - sfWindow.draw(sfCshape); - sfCshape.setPosition(sf::Vector2f(sfWindow.getSize().x, sfWindow.getSize().y)); - sfWindow.draw(sfCshape); - -} - -void SteamTargetRenderer::hookBindings() const -{ - std::cout << "Hooking Steam..." << std::endl; - - QString dir = QDir::toNativeSeparators(QCoreApplication::applicationDirPath()); - dir = dir.mid(0, dir.lastIndexOf("\\")); - - QProcess proc; - proc.setNativeArguments(" --inject "); - proc.setWorkingDirectory(dir); - proc.start("./Injector.exe", QIODevice::ReadOnly); - proc.waitForStarted(); - proc.waitForFinished(); - - if (QString::fromStdString(proc.readAll().toStdString()).contains("Inject success!")) //if we have injected (and patched the function) - { - std::cout << "Successfully hooked Steam!" << std::endl; - - //tell the GloSC_GameLauncher that we have hooked steam - //it will deal with checking if the target is still alive and unload the dll / unhook then - // - ensures unloading / unhooking even if this process crashes or gets unexpectedly killed - QSharedMemory sharedMemInstance("GloSC_GameLauncher"); - if (!sharedMemInstance.create(1024) && sharedMemInstance.error() == QSharedMemory::AlreadyExists) - { - QBuffer buffer; - QDataStream dataStream(&buffer); - QStringList stringList; - - sharedMemInstance.attach(); - sharedMemInstance.lock(); - - buffer.setData(static_cast(sharedMemInstance.constData()), sharedMemInstance.size()); - buffer.open(QBuffer::ReadOnly); - dataStream >> stringList; - buffer.close(); - - int i = stringList.indexOf(IsSteamHooked) + 1; - stringList.replace(i, "1"); - - - buffer.open(QBuffer::ReadWrite); - QDataStream out(&buffer); - out << stringList; - int size = buffer.size(); - char *to = static_cast(sharedMemInstance.data()); - const char *from = buffer.data().data(); - memcpy(to, from, qMin(sharedMemInstance.size(), size)); - buffer.close(); - - sharedMemInstance.unlock(); - sharedMemInstance.detach(); - } - } else { - std::cout << "Hooking Steam failed!" << std::endl; - - MessageBoxW(NULL, L"Hooking Steam failed!", L"GloSC-SteamTarget", MB_OK); - } -} - -void SteamTargetRenderer::loadLogo() -{ - HRSRC rsrcData = FindResource(NULL, L"ICOPNG", RT_RCDATA); - DWORD rsrcDataSize = SizeofResource(NULL, rsrcData); - HGLOBAL grsrcData = LoadResource(NULL, rsrcData); - LPVOID firstByte = LockResource(grsrcData); - spriteTexture = std::make_unique(); - spriteTexture->loadFromMemory(firstByte, rsrcDataSize); - backgroundSprite.setTexture(*spriteTexture); - backgroundSprite.setOrigin(sf::Vector2f(spriteTexture->getSize().x / 2.f, spriteTexture->getSize().y / 2)); - sf::VideoMode winSize = sf::VideoMode::getDesktopMode(); - backgroundSprite.setPosition(sf::Vector2f(winSize.width / 2.f, winSize.height / 2.f)); -} - -void SteamTargetRenderer::moveMouseIntoOverlay() -{ - RECT rect = { 0 }; - if (GetWindowRect(sfWindow.getSystemHandle(), &rect)) - { - POINT cursorPos = { 0 }; - GetCursorPos(&cursorPos); - if (PtInRect(&rect, cursorPos)) - { - SetCursorPos(cursorPos.x+1, cursorPos.y); - } - else - { - SetCursorPos(rect.left + 16, rect.top + 16); - } - } - - - -} - -//WinHook Callback to check if the overlay is opened/closed -LRESULT WINAPI SteamTargetRenderer::HookCallback(int nCode, WPARAM wParam, LPARAM lParam) -{ - if (nCode >= 0) - { - PMSG msg = reinterpret_cast(lParam); - std::cout << "DEBUG: " << "message: " << msg->message << std::endl; - if (msg->message == 0x14FA || msg->message == 0x14FF) //Posted when the overlay gets opened - { - overlayOpen = true; - std::cout << "Overlay Opened!\n"; - } - else if (msg->message == 0x14F7 || msg->message == 0x14FD || msg->message == 512 || msg->message == 0x2a3) - { - overlayOpen = false; - std::cout << "Overlay closed!\n"; - } - } - return CallNextHookEx(hook, nCode, wParam, lParam); -} - -void SteamTargetRenderer::unhookBindings() -{ - if (bHookSteam) - { - QString dir = QDir::toNativeSeparators(QCoreApplication::applicationDirPath()); - dir = dir.mid(0, dir.lastIndexOf("\\")); - - QProcess proc; - proc.setNativeArguments(" --eject "); - proc.setWorkingDirectory(dir); - proc.start("./Injector.exe", QIODevice::ReadOnly); - proc.waitForStarted(); - proc.waitForFinished(); - } -} - -BOOL SteamTargetRenderer::ConsoleCtrlCallback(DWORD dwCtrlType) -{ - if (dwCtrlType == CTRL_CLOSE_EVENT || dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_C_EVENT) - { - unhookBindings(); - return true; - } - - return false; -} - -void SteamTargetRenderer::stealFocus(HWND hwnd) -{ - DWORD dwCurrentThread = GetCurrentThreadId(); - DWORD dwFGThread = GetWindowThreadProcessId(GetForegroundWindow(), nullptr); - - AttachThreadInput(dwCurrentThread, dwFGThread, TRUE); - - // Possible actions you may wan to bring the window into focus. - SetForegroundWindow(hwnd); - SetCapture(hwnd); - SetFocus(hwnd); - SetActiveWindow(hwnd); - EnableWindow(hwnd, TRUE); - - AttachThreadInput(dwCurrentThread, dwFGThread, FALSE); - - - sf::Clock clock; - while (!SetForegroundWindow(hwnd) && clock.getElapsedTime().asMilliseconds() < 1000) //try to forcefully set foreground window - { - Sleep(1); - } - -} - -void SteamTargetRenderer::launchApp() -{ - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); - - bool launchGame = false; - bool closeWhenDone = false; - QString type = "Win32"; - QString path = ""; - QString args; - QSettings settings(this->arguments().at(1), QSettings::IniFormat); - settings.beginGroup("LaunchGame"); - const QStringList childKeys = settings.childKeys(); - for (auto &childkey : childKeys) - { - if (childkey == "bLaunchGame") - launchGame = settings.value(childkey).toBool(); - else if (childkey == "Type") - type = settings.value(childkey).toString(); - else if (childkey == "Path") - path = settings.value(childkey).toString(); - else if (childkey == "Args") - args = settings.value(childkey).toString(); - else if (childkey == "bCloseWhenDone") - closeWhenDone = settings.value("bCloseWhenDone").toBool(); - } - settings.endGroup(); - - if (launchGame) - { - QSharedMemory sharedMemInstance("GloSC_GameLauncher"); - if (!sharedMemInstance.create(1024) && sharedMemInstance.error() == QSharedMemory::AlreadyExists) - { - - if (type == "UWP") - { - HWND hwnd = sfWindow.getSystemHandle(); - SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_ASYNCWINDOWPOS); - QTimer::singleShot(5000, [hwnd]() - { - SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_ASYNCWINDOWPOS); - }); - } - - QBuffer buffer; - QDataStream dataStream(&buffer); - QStringList stringList; - - sharedMemInstance.attach(); - sharedMemInstance.lock(); - - buffer.setData(static_cast(sharedMemInstance.constData()), sharedMemInstance.size()); - buffer.open(QBuffer::ReadOnly); - dataStream >> stringList; - buffer.close(); - - - - int lgt_index = stringList.indexOf(LaunchGame); - stringList.replace(lgt_index + 1, type); - stringList.replace(lgt_index + 2, path); - stringList.replace(lgt_index + 3, args); - - - buffer.open(QBuffer::ReadWrite); - QDataStream out(&buffer); - out << stringList; - int size = buffer.size(); - char *to = static_cast(sharedMemInstance.data()); - const char *from = buffer.data().data(); - memcpy(to, from, qMin(sharedMemInstance.size(), size)); - buffer.close(); - - sharedMemInstance.unlock(); - sharedMemInstance.detach(); - - if (closeWhenDone) - { - updateTimer.setInterval(1111); - connect(&updateTimer, SIGNAL(timeout()), this, SLOT(checkSharedMem())); - updateTimer.start(); - } - } - } -} - -void SteamTargetRenderer::checkSharedMem() -{ - QSharedMemory sharedMemInstance("GloSC_GameLauncher"); - if (!sharedMemInstance.create(1024) && sharedMemInstance.error() == QSharedMemory::AlreadyExists) - { - QBuffer buffer; - QDataStream in(&buffer); - QStringList stringList; - - sharedMemInstance.attach(); - sharedMemInstance.lock(); - buffer.setData(static_cast(sharedMemInstance.constData()), sharedMemInstance.size()); - buffer.open(QBuffer::ReadOnly); - in >> stringList; - buffer.close(); - sharedMemInstance.unlock(); - sharedMemInstance.detach(); - - int close_index = stringList.indexOf(LaunchedProcessFinished) + 1; - - if (close_index > 0 && stringList.at(close_index).toInt() == 1) - bRunLoop = false; - } - - -} - diff --git a/SteamTarget/SteamTargetRenderer.h b/SteamTarget/SteamTargetRenderer.h deleted file mode 100644 index f5d67c9..0000000 --- a/SteamTarget/SteamTargetRenderer.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -Copyright 2018 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "VirtualControllerThread.h" -#include - -class SteamTargetRenderer : public QApplication -{ - Q_OBJECT - -public: - SteamTargetRenderer(int& argc, char** argv); - ~SteamTargetRenderer(); - - void run(); - - - - -private: - void stop(); - void getSteamOverlay(); - void RunSfWindowLoop(); - static void makeSfWindowTransparent(sf::RenderWindow& window); - void drawDebugEdges(); - void hookBindings() const; - - void loadLogo(); - - void moveMouseIntoOverlay(); - - static LRESULT WINAPI HookCallback(int nCode, WPARAM wParam, LPARAM lParam); - - static void unhookBindings(); - - static BOOL WINAPI ConsoleCtrlCallback(_In_ DWORD dwCtrlType); - - static void stealFocus(HWND hwnd); - - std::atomic bRunLoop = true; - - bool bUseDesktopConfig = false; - bool bDrawDebugEdges = false; - bool bDrawOverlay = true; - bool bVsync = false; - int iRefreshRate = 30; - sf::CircleShape sfCshape; - sf::RenderWindow sfWindow; - - std::thread renderThread; - - HWND consoleHwnd; - - HMODULE hmodGameOverlayRenderer = nullptr; -#ifdef _AMD64_ - WCHAR* overlayModuleName = L"GameOverlayRenderer64.dll"; -#else - WCHAR* overlayModuleName = L"GameOverlayRenderer.dll"; -#endif - static std::atomic overlayOpen; - static HHOOK hook; - - - HWND hwForeGroundWindow = nullptr; - bool bNeedFocusSwitch = false; - - VirtualControllerThread controllerThread; - - bool bEnableControllers = true; - - static std::atomic bHookSteam; - - QTimer updateTimer; - - std::unique_ptr spriteTexture; - sf::Sprite backgroundSprite; - - const QString LaunchGame = "LaunchGame"; - const QString LaunchedProcessFinished = "LaunchedProcessFinished"; - const QString IsSteamHooked = "IsSteamHooked"; - const QStringList defaultSharedMemData = QStringList() - << LaunchGame - << "" - << "" - << LaunchedProcessFinished - << "0" - << IsSteamHooked - << "-1"; - -private slots: - void launchApp(); - void checkSharedMem(); -}; -