2
0
mirror of https://github.com/Alia5/GlosSI.git synced 2024-11-15 00:12:51 +00:00
GlosSI/GlosSITarget/SteamTarget.cpp

394 lines
13 KiB
C++
Raw Normal View History

2021-10-15 15:10:57 +00:00
/*
Copyright 2021-2022 Peter Repukat - FlatspotSoftware
2021-10-15 15:10:57 +00:00
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-23 14:03:18 +00:00
#include "Settings.h"
#include "steam_sf_keymap.h"
#include <SFML/Window/Keyboard.hpp>
2021-10-17 01:47:20 +00:00
#include <WinReg/WinReg.hpp>
#include <numeric>
#include <regex>
#include <spdlog/spdlog.h>
2021-10-17 01:47:20 +00:00
#include <vdf_parser.hpp>
#ifdef _WIN32
#include "UWPOverlayEnabler.h"
#endif
2021-10-20 19:47:24 +00:00
SteamTarget::SteamTarget(int argc, char* argv[])
: window_(
[this] { run_ = false; },
2022-01-07 00:36:21 +00:00
[this] { toggleGlossiOverlay(); },
getScreenshotHotkey(),
[this]() {
target_window_handle_ = window_.getSystemHandle();
overlay_ = window_.getOverlay();
}),
2021-10-22 16:07:08 +00:00
overlay_(window_.getOverlay()),
2021-10-23 11:33:01 +00:00
detector_([this](bool overlay_open) { onOverlayChanged(overlay_open); }),
2021-10-23 14:03:18 +00:00
launcher_([this] {
delayed_shutdown_ = true;
delay_shutdown_clock_.restart();
})
2021-10-15 15:10:57 +00:00
{
2021-10-21 17:54:41 +00:00
target_window_handle_ = window_.getSystemHandle();
#ifdef _WIN32
if (Settings::launch.isUWP) {
UWPOverlayEnabler::EnableUwpOverlay();
} else {
UWPOverlayEnabler::AddUwpOverlayOvWidget();
}
#endif
2021-10-14 18:54:29 +00:00
}
2021-10-15 15:10:57 +00:00
int SteamTarget::run()
{
if (!SteamOverlayDetector::IsSteamInjected()) {
spdlog::warn("Steam-overlay not detected. Showing GlosSI-overlay!\n\
2021-10-22 10:17:46 +00:00
Application will not function!");
window_.setClickThrough(false);
if (!overlay_.expired())
overlay_.lock()->setEnabled(true);
2021-10-22 16:07:08 +00:00
steam_overlay_present_ = false;
}
else {
spdlog::info("Steam-overlay detected.");
spdlog::warn("Double press Steam- overlay key(s)/Controller button to show GlosSI-overlay"); // Just to color output and really get users attention
window_.setClickThrough(true);
if (!overlay_.expired())
overlay_.lock()->setEnabled(false);
2021-10-22 16:07:08 +00:00
steam_overlay_present_ = true;
2021-10-22 10:17:46 +00:00
}
2021-10-23 00:27:31 +00:00
getXBCRebindingEnabled();
2021-10-22 10:17:46 +00:00
2021-10-15 13:02:36 +00:00
run_ = true;
2021-10-22 10:17:46 +00:00
#ifdef _WIN32
hidhide_.hideDevices(steam_path_);
input_redirector_.run();
#endif
2021-10-22 10:17:46 +00:00
2021-10-23 14:03:18 +00:00
if (Settings::launch.launch) {
launcher_.launchApp(Settings::launch.launchPath, Settings::launch.launchAppArgs);
}
2021-10-23 11:33:01 +00:00
keepControllerConfig(true);
2021-10-15 13:02:36 +00:00
while (run_) {
2021-10-16 20:36:30 +00:00
detector_.update();
overlayHotkeyWorkaround();
window_.update();
2021-10-23 14:03:18 +00:00
// 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) {
run_ = false;
}
}
else {
2021-10-23 14:03:18 +00:00
launcher_.update();
}
2021-10-15 13:02:36 +00:00
}
2021-10-22 10:17:46 +00:00
#ifdef _WIN32
input_redirector_.stop();
hidhide_.disableHidHide();
#endif
2021-10-23 11:33:01 +00:00
launcher_.close();
2021-10-23 11:33:45 +00:00
return 0;
2021-10-15 13:02:36 +00:00
}
2021-10-17 01:46:18 +00:00
void SteamTarget::onOverlayChanged(bool overlay_open)
{
if (overlay_open) {
focusWindow(target_window_handle_);
2021-10-23 00:27:31 +00:00
window_.setClickThrough(!overlay_open);
2022-01-07 00:36:21 +00:00
} else {
if (!(overlay_.expired() ? false : overlay_.lock()->isEnabled())) {
window_.setClickThrough(!overlay_open);
focusWindow(last_foreground_window_);
}
}
if (!overlay_trigger_flag_) {
overlay_trigger_flag_ = true;
overlay_trigger_clock_.restart();
}
else {
if (overlay_trigger_clock_.getElapsedTime().asSeconds() <= overlay_trigger_max_seconds_) {
2022-01-07 00:36:21 +00:00
toggleGlossiOverlay();
}
overlay_trigger_flag_ = false;
}
2022-01-07 00:36:21 +00:00
}
void SteamTarget::toggleGlossiOverlay()
{
if (overlay_.expired()) {
return;
}
const auto ov_opened = overlay_.lock()->toggle();
window_.setClickThrough(!ov_opened);
if (ov_opened) {
spdlog::info("Opened GlosSI-overlay");
focusWindow(target_window_handle_);
}
else {
focusWindow(last_foreground_window_);
2022-01-07 00:36:21 +00:00
spdlog::info("Closed GlosSI-overlay");
}
2021-10-17 01:46:18 +00:00
}
void SteamTarget::focusWindow(WindowHandle hndl)
{
#ifdef _WIN32
if (hndl == target_window_handle_) {
spdlog::debug("Bring own window to foreground");
}
else {
spdlog::debug("Bring window \"{:#x}\" to foreground", reinterpret_cast<uint64_t>(hndl));
}
keepControllerConfig(false); // unhook GetForegroundWindow
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
2021-10-17 01:46:18 +00:00
// lot's of ways actually bringing our window to foreground...
const auto current_thread = GetCurrentThreadId();
2021-10-17 01:46:18 +00:00
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;
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::filesystem::path SteamTarget::getSteamPath() const
2021-10-17 01:47:20 +00:00
{
#ifdef _WIN32
2021-11-04 21:11:57 +00:00
try {
// 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"};
const auto res = key.GetStringValue(L"SteamPath");
spdlog::info(L"Detected Steam Path: {}", res);
return res;
2021-11-12 12:34:45 +00:00
} catch (const winreg::RegException& e) {
2021-11-04 21:11:57 +00:00
spdlog::error("Couldn't get Steam path from Registry; {}", e.what());
}
return L"";
2021-10-17 01:47:20 +00:00
#else
return L""; // TODO
#endif
}
std::wstring SteamTarget::getSteamUserId() const
2021-10-17 01:47:20 +00:00
{
#ifdef _WIN32
2021-11-04 21:11:57 +00:00
try {
// 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"};
const auto res = std::to_wstring(key.GetDwordValue(L"ActiveUser"));
spdlog::info(L"Detected Steam UserId: {}", res);
return res;
}
2021-11-12 12:34:45 +00:00
catch (const winreg::RegException& e) {
2021-11-04 21:11:57 +00:00
spdlog::error("Couldn't get Steam path from Registry; {}", e.what());
}
return L"";
2021-10-17 01:47:20 +00:00
#else
return L""; // TODO
#endif
}
std::vector<std::string> SteamTarget::getOverlayHotkey()
{
const auto config_path = std::wstring(steam_path_) + std::wstring(user_data_path_) + steam_user_id_ + std::wstring(config_file_name_);
2021-11-04 15:38:05 +00:00
if (!std::filesystem::exists(config_path)) {
spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path);
return {"Shift", "KEY_TAB"}; // default
}
2021-10-17 01:47:20 +00:00
std::ifstream config_file(config_path);
auto root = tyti::vdf::read(config_file);
auto children = root.childs["system"];
2021-11-04 21:11:57 +00:00
if (children->attribs.find("InGameOverlayShortcutKey") == children->attribs.end()) {
spdlog::warn("Couldn't detect overlay hotkey, using default: Shift+Tab");
return {"Shift", "KEY_TAB"}; // default
}
2021-10-17 01:47:20 +00:00
auto hotkeys = children->attribs.at("InGameOverlayShortcutKey");
// has anyone more than 4 keys to open overlay?!
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: 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 = std::wstring(steam_path_) + std::wstring(user_data_path_) + steam_user_id_ + std::wstring(config_file_name_);
2021-11-04 15:38:05 +00:00
if (!std::filesystem::exists(config_path)) {
spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path);
return {"KEY_F12"}; //default
}
std::ifstream config_file(config_path);
auto root = tyti::vdf::read(config_file);
auto children = root.childs["system"];
2021-11-04 21:11:57 +00:00
if (children->attribs.find("InGameOverlayScreenshotHotKey") == children->attribs.end()) {
spdlog::warn("Couldn't detect overlay hotkey, using default: F12");
return {"KEY_F12"}; //default
}
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++) {
const auto s = std::string(m[i]);
if (!s.empty()) {
res.push_back(s);
}
2021-10-17 01:47:20 +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-23 00:27:31 +00:00
bool SteamTarget::getXBCRebindingEnabled()
{
const auto config_path = std::wstring(steam_path_) + std::wstring(user_data_path_) + steam_user_id_ + std::wstring(config_file_name_);
2021-11-04 15:38:05 +00:00
if (!std::filesystem::exists(config_path)) {
spdlog::warn(L"Couldn't read Steam config file: \"{}\"", config_path);
return false;
}
2021-10-23 00:27:31 +00:00
std::ifstream config_file(config_path);
auto root = tyti::vdf::read(config_file);
2021-11-04 21:11:57 +00:00
if (root.attribs.find("SteamController_XBoxSupport") == root.attribs.end()) {
spdlog::warn("\"Xbox Configuration Support\" is disabled in Steam. This may cause doubled Inputs!");
return false;
}
2021-10-23 00:27:31 +00:00
auto xbsup = root.attribs.at("SteamController_XBoxSupport");
if (xbsup != "1") {
spdlog::warn("\"Xbox Configuration Support\" is disabled in Steam. This may cause doubled Inputs!");
}
return xbsup == "1";
}
void SteamTarget::keepControllerConfig(bool keep)
{
#ifdef _WIN32
if (keep && !getFgWinHook.IsInstalled()) {
spdlog::debug("Hooking GetForegroundWindow (in own process)");
2021-10-21 17:54:41 +00:00
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 GetForegroundWindow (in own process)");
getFgWinHook.Remove();
if (getFgWinHook.IsInstalled()) {
spdlog::error("Couldn't un-install GetForegroundWindow hook!");
}
}
#endif
}
2021-10-21 17:54:41 +00:00
#ifdef _WIN32
HWND SteamTarget::keepFgWindowHookFn()
{
return target_window_handle_;
}
#endif
void SteamTarget::overlayHotkeyWorkaround()
{
static bool pressed = false;
if (std::ranges::all_of(overlay_hotkey_,
2021-10-20 19:47:24 +00:00
[](const auto& key) {
return sf::Keyboard::isKeyPressed(keymap::sfkey[key]);
})) {
spdlog::trace("Detected overlay hotkey(s)");
pressed = true;
2021-10-20 19:47:24 +00:00
std::ranges::for_each(overlay_hotkey_, [this](const auto& key) {
#ifdef _WIN32
PostMessage(target_window_handle_, WM_KEYDOWN, keymap::winkey[key], 0);
#else
#endif
});
spdlog::trace("Sending Overlay KeyDown events...");
}
else if (pressed) {
pressed = false;
2021-10-20 19:47:24 +00:00
std::ranges::for_each(overlay_hotkey_, [this](const auto& key) {
#ifdef _WIN32
PostMessage(target_window_handle_, WM_KEYUP, keymap::winkey[key], 0);
#else
#endif
});
spdlog::trace("Sending Overlay KeyUp events...");
}
}