2021-10-15 15:10:57 +00:00
|
|
|
/*
|
|
|
|
Copyright 2021 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.
|
|
|
|
*/
|
2021-10-14 18:54:29 +00:00
|
|
|
#include "SteamTarget.h"
|
|
|
|
|
2021-10-17 16:20:16 +00:00
|
|
|
#include "steam_sf_keymap.h"
|
|
|
|
|
|
|
|
#include <SFML/Window/Keyboard.hpp>
|
2021-10-17 01:47:20 +00:00
|
|
|
#include <WinReg/WinReg.hpp>
|
2021-10-17 16:20:16 +00:00
|
|
|
#include <numeric>
|
|
|
|
#include <regex>
|
|
|
|
#include <spdlog/spdlog.h>
|
2021-10-17 01:47:20 +00:00
|
|
|
#include <vdf_parser.hpp>
|
|
|
|
|
2021-10-17 19:04:41 +00:00
|
|
|
#include <subhook.h>
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
subhook::Hook getFgWinHook;
|
|
|
|
static HWND target_hwnd = nullptr;
|
|
|
|
|
|
|
|
HWND keepForegroundWindow()
|
|
|
|
{
|
|
|
|
return target_hwnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2021-10-17 01:46:18 +00:00
|
|
|
SteamTarget::SteamTarget(int argc, char *argv[])
|
2021-10-17 19:04:41 +00:00
|
|
|
: window_([this] { run_ = false; }, getScreenshotHotkey()),
|
2021-10-17 01:46:18 +00:00
|
|
|
detector_([this](bool overlay_open) { onOverlayChanged(overlay_open); }), target_window_handle_(window_.getSystemHandle())
|
2021-10-15 15:10:57 +00:00
|
|
|
{
|
2021-10-17 19:04:41 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
target_hwnd = target_window_handle_;
|
|
|
|
#endif
|
2021-10-14 18:54:29 +00:00
|
|
|
}
|
|
|
|
|
2021-10-15 15:10:57 +00:00
|
|
|
int SteamTarget::run()
|
|
|
|
{
|
2021-10-15 13:02:36 +00:00
|
|
|
run_ = true;
|
2021-10-17 19:04:41 +00:00
|
|
|
keepControllerConfig(true);
|
2021-10-17 21:41:15 +00:00
|
|
|
input_redirector_.run();
|
2021-10-15 13:02:36 +00:00
|
|
|
while (run_) {
|
2021-10-16 20:36:30 +00:00
|
|
|
detector_.update();
|
2021-10-15 13:02:36 +00:00
|
|
|
window_.update();
|
2021-10-17 16:20:16 +00:00
|
|
|
overlayHotkeyWorkaround();
|
2021-10-15 13:02:36 +00:00
|
|
|
}
|
2021-10-17 21:41:15 +00:00
|
|
|
input_redirector_.stop();
|
2021-10-14 18:54:29 +00:00
|
|
|
return 1;
|
2021-10-15 13:02:36 +00:00
|
|
|
}
|
2021-10-17 01:46:18 +00:00
|
|
|
|
|
|
|
void SteamTarget::onOverlayChanged(bool overlay_open)
|
|
|
|
{
|
|
|
|
window_.setClickThrough(!overlay_open);
|
2021-10-17 01:48:47 +00:00
|
|
|
if (overlay_open) {
|
|
|
|
focusWindow(target_window_handle_);
|
2021-10-17 16:20:16 +00:00
|
|
|
}
|
|
|
|
else {
|
2021-10-17 01:48:47 +00:00
|
|
|
focusWindow(last_foreground_window_);
|
|
|
|
}
|
2021-10-17 01:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SteamTarget::focusWindow(WindowHandle hndl)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
2021-10-17 19:04:41 +00:00
|
|
|
if (hndl == target_window_handle_) {
|
|
|
|
spdlog::info("Bring own window to foreground");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
spdlog::info("Bring window \"{:#x}\" to foreground", reinterpret_cast<uint64_t>(hndl));
|
|
|
|
}
|
|
|
|
|
|
|
|
keepControllerConfig(false); // unhook GetForegroundWindow
|
2021-10-17 01:46:18 +00:00
|
|
|
last_foreground_window_ = GetForegroundWindow();
|
|
|
|
const DWORD fg_thread = GetWindowThreadProcessId(last_foreground_window_, nullptr);
|
2021-10-17 19:04:41 +00:00
|
|
|
keepControllerConfig(true); // re-hook GetForegroundWindow
|
2021-10-17 01:46:18 +00:00
|
|
|
|
|
|
|
// lot's of ways actually bringing our window to foreground...
|
|
|
|
const DWORD current_thread = GetCurrentThreadId();
|
|
|
|
AttachThreadInput(current_thread, fg_thread, TRUE);
|
|
|
|
|
|
|
|
SetForegroundWindow(hndl);
|
|
|
|
SetCapture(hndl);
|
|
|
|
SetFocus(hndl);
|
|
|
|
SetActiveWindow(hndl);
|
|
|
|
EnableWindow(hndl, TRUE);
|
|
|
|
|
|
|
|
AttachThreadInput(current_thread, fg_thread, FALSE);
|
|
|
|
|
|
|
|
//try to forcefully set foreground window at least a few times
|
|
|
|
sf::Clock clock;
|
2021-10-17 16:20:16 +00:00
|
|
|
while (!SetForegroundWindow(hndl) && clock.getElapsedTime().asMilliseconds() < 20) {
|
2021-10-17 01:46:18 +00:00
|
|
|
SetActiveWindow(hndl);
|
|
|
|
Sleep(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
2021-10-17 01:47:20 +00:00
|
|
|
|
|
|
|
std::wstring SteamTarget::getSteamPath()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
// TODO: check if keys/value exist
|
|
|
|
// steam should always be open and have written reg values...
|
|
|
|
winreg::RegKey key{HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam"};
|
2021-10-17 19:04:41 +00:00
|
|
|
const auto res = key.GetStringValue(L"SteamPath");
|
|
|
|
spdlog::info(L"Detected Steam Path: {}", res);
|
|
|
|
return res;
|
2021-10-17 01:47:20 +00:00
|
|
|
#else
|
|
|
|
return L""; // TODO
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
std::wstring SteamTarget::getSteamUserId()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
// TODO: check if keys/value exist
|
|
|
|
// steam should always be open and have written reg values...
|
|
|
|
winreg::RegKey key{HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam\\ActiveProcess"};
|
2021-10-17 19:04:41 +00:00
|
|
|
const auto res = std::to_wstring(key.GetDwordValue(L"ActiveUser"));
|
|
|
|
spdlog::info(L"Detected Steam UserId: {}", res);
|
|
|
|
return res;
|
2021-10-17 01:47:20 +00:00
|
|
|
#else
|
|
|
|
return L""; // TODO
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> SteamTarget::getOverlayHotkey()
|
|
|
|
{
|
2021-10-17 19:04:41 +00:00
|
|
|
const auto config_path = steam_path_ + std::wstring(user_data_path_) + steam_user_id_ + std::wstring(config_file_name_);
|
2021-10-17 01:47:20 +00:00
|
|
|
std::ifstream config_file(config_path);
|
|
|
|
// TODO: check if file exists
|
|
|
|
auto root = tyti::vdf::read(config_file);
|
|
|
|
|
|
|
|
auto children = root.childs["system"];
|
|
|
|
auto hotkeys = children->attribs.at("InGameOverlayShortcutKey");
|
|
|
|
|
|
|
|
// has anyone more than 4 keys to open overlay?!
|
|
|
|
std::smatch m;
|
2021-10-17 16:20:16 +00:00
|
|
|
if (!std::regex_match(hotkeys, m, std::regex(R"((\w*)\s*(\w*)\s*(\w*)\s*(\w*))"))) {
|
2021-10-17 19:04:41 +00:00
|
|
|
spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab");
|
|
|
|
return {"Shift", "KEY_TAB"}; // default
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> res;
|
|
|
|
for (auto i = 1; i < m.size(); i++) {
|
|
|
|
const auto s = std::string(m[i]);
|
|
|
|
if (!s.empty()) {
|
|
|
|
res.push_back(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (res.empty()) {
|
|
|
|
spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab");
|
|
|
|
return {"Shift", "KEY_TAB"}; // default
|
|
|
|
}
|
|
|
|
spdlog::info("Detected Overlay hotkey(s): {}", std::accumulate(
|
|
|
|
res.begin() + 1, res.end(), res[0],
|
|
|
|
[](auto acc, const auto curr) { return acc += "+" + curr; }));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> SteamTarget::getScreenshotHotkey()
|
|
|
|
{
|
|
|
|
const auto config_path = steam_path_ + std::wstring(user_data_path_) + steam_user_id_ + std::wstring(config_file_name_);
|
|
|
|
std::ifstream config_file(config_path);
|
|
|
|
// TODO: check if file exists
|
|
|
|
auto root = tyti::vdf::read(config_file);
|
|
|
|
|
|
|
|
auto children = root.childs["system"];
|
|
|
|
auto hotkeys = children->attribs.at("InGameOverlayScreenshotHotKey");
|
|
|
|
|
|
|
|
// has anyone more than 4 keys to screenshot?!
|
|
|
|
std::smatch m;
|
|
|
|
if (!std::regex_match(hotkeys, m, std::regex(R"((\w*)\s*(\w*)\s*(\w*)\s*(\w*))"))) {
|
|
|
|
spdlog::warn("Couldn't detect overlay hotkey, using default: F12");
|
|
|
|
return {"KEY_F12"}; //default
|
2021-10-17 01:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> res;
|
|
|
|
for (auto i = 1; i < m.size(); i++) {
|
2021-10-17 16:20:16 +00:00
|
|
|
const auto s = std::string(m[i]);
|
|
|
|
if (!s.empty()) {
|
|
|
|
res.push_back(s);
|
|
|
|
}
|
2021-10-17 01:47:20 +00:00
|
|
|
}
|
2021-10-17 19:04:41 +00:00
|
|
|
if (res.empty()) {
|
|
|
|
spdlog::warn("Couldn't detect overlay hotkey, using default: F12");
|
|
|
|
return {"KEY_F12"}; //default
|
|
|
|
}
|
|
|
|
spdlog::info("Detected screenshot hotkey(s): {}", std::accumulate(
|
|
|
|
res.begin() + 1, res.end(), res[0],
|
|
|
|
[](auto acc, const auto curr) { return acc += "+" + curr; }));
|
2021-10-17 01:47:20 +00:00
|
|
|
return res;
|
|
|
|
}
|
2021-10-17 16:20:16 +00:00
|
|
|
|
2021-10-17 19:04:41 +00:00
|
|
|
void SteamTarget::keepControllerConfig(bool keep)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (keep && !getFgWinHook.IsInstalled()) {
|
|
|
|
spdlog::debug("Hooking GetForegroudnWindow (in own process)");
|
|
|
|
getFgWinHook.Install(&GetForegroundWindow, &keepForegroundWindow, 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)");
|
|
|
|
getFgWinHook.Remove();
|
|
|
|
if (getFgWinHook.IsInstalled()) {
|
|
|
|
spdlog::error("Couldn't un-install GetForegroundWindow hook!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-10-17 16:20:16 +00:00
|
|
|
void SteamTarget::overlayHotkeyWorkaround()
|
|
|
|
{
|
|
|
|
static bool pressed = false;
|
2021-10-17 19:04:41 +00:00
|
|
|
if (std::ranges::all_of(overlay_hotkey_,
|
|
|
|
[](const auto &key) {
|
|
|
|
return sf::Keyboard::isKeyPressed(keymap::sfkey[key]);
|
|
|
|
})) {
|
|
|
|
spdlog::debug("Detected overlay hotkey(s)");
|
2021-10-17 16:20:16 +00:00
|
|
|
pressed = true;
|
2021-10-17 19:04:41 +00:00
|
|
|
std::ranges::for_each(overlay_hotkey_, [this](const auto &key) {
|
2021-10-17 16:20:16 +00:00
|
|
|
#ifdef _WIN32
|
2021-10-17 19:04:41 +00:00
|
|
|
PostMessage(target_window_handle_, WM_KEYDOWN, keymap::winkey[key], 0);
|
2021-10-17 16:20:16 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
#endif
|
2021-10-17 19:04:41 +00:00
|
|
|
});
|
2021-10-17 16:20:16 +00:00
|
|
|
spdlog::debug("Sending Overlay KeyDown events...");
|
2021-10-17 19:04:41 +00:00
|
|
|
}
|
|
|
|
else if (pressed) {
|
2021-10-17 16:20:16 +00:00
|
|
|
pressed = false;
|
2021-10-17 19:04:41 +00:00
|
|
|
std::ranges::for_each(overlay_hotkey_, [this](const auto &key) {
|
2021-10-17 16:20:16 +00:00
|
|
|
#ifdef _WIN32
|
2021-10-17 19:04:41 +00:00
|
|
|
PostMessage(target_window_handle_, WM_KEYUP, keymap::winkey[key], 0);
|
2021-10-17 16:20:16 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
#endif
|
2021-10-17 19:04:41 +00:00
|
|
|
});
|
2021-10-17 16:20:16 +00:00
|
|
|
spdlog::debug("Sending Overlay KeyUp events...");
|
|
|
|
}
|
|
|
|
}
|