Compare commits
6 Commits
b72b4da8fb
...
0800649d8f
Author | SHA1 | Date |
---|---|---|
Mr_Goldberg | 0800649d8f | |
Mr_Goldberg | 63128907fd | |
Mr_Goldberg | a4ef72cb3c | |
Mr_Goldberg | 0082242a6f | |
Mr_Goldberg | 0a80b60b6c | |
Mr_Goldberg | 743a810463 |
|
@ -44,6 +44,10 @@ If the DLC file is present, the emulator will only unlock the DLCs in that file.
|
|||
The contents of this file are: appid=DLC name
|
||||
See the steam_settings.EXAMPLE folder for an example.
|
||||
|
||||
Languages:
|
||||
You can include a steam_settings\supported_languages.txt file with a list of languages that the game supports. If the global emu language setting is not in this list of languages the emu will default to the first language in the list.
|
||||
See the steam_settings.EXAMPLE folder for an example.
|
||||
|
||||
Depots:
|
||||
This is pretty rare but some games might use depot ids to see if dlcs are installed. You can provide a list of installed depots to the game with a steam_settings\depots.txt file.
|
||||
See the steam_settings.EXAMPLE folder for an example.
|
||||
|
|
40
dll/base.cpp
40
dll/base.cpp
|
@ -563,6 +563,23 @@ static bool is_whitelist_ip(unsigned char *ip)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool is_lan_ipv4(unsigned char *ip)
|
||||
{
|
||||
PRINT_DEBUG("CHECK LAN IP %hhu.%hhu.%hhu.%hhu\n", ip[0], ip[1], ip[2], ip[3]);
|
||||
if (is_whitelist_ip(ip)) return true;
|
||||
if (ip[0] == 127) return true;
|
||||
if (ip[0] == 10) return true;
|
||||
if (ip[0] == 192 && ip[1] == 168) return true;
|
||||
if (ip[0] == 169 && ip[1] == 254 && ip[2] != 0) return true;
|
||||
if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) return true;
|
||||
if ((ip[0] == 100) && ((ip[1] & 0xC0) == 0x40)) return true;
|
||||
if (ip[0] == 239) return true; //multicast
|
||||
if (ip[0] == 0) return true; //Current network
|
||||
if (ip[0] == 192 && (ip[1] == 18 || ip[1] == 19)) return true; //Used for benchmark testing of inter-network communications between two separate subnets.
|
||||
if (ip[0] >= 224) return true; //ip multicast (224 - 239) future use (240.0.0.0 - 255.255.255.254) broadcast (255.255.255.255)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_lan_ip(const sockaddr *addr, int namelen)
|
||||
{
|
||||
if (!namelen) return false;
|
||||
|
@ -571,24 +588,13 @@ static bool is_lan_ip(const sockaddr *addr, int namelen)
|
|||
struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
|
||||
unsigned char ip[4];
|
||||
memcpy(ip, &addr_in->sin_addr, sizeof(ip));
|
||||
PRINT_DEBUG("CHECK LAN IP %hhu.%hhu.%hhu.%hhu:%u\n", ip[0], ip[1], ip[2], ip[3], ntohs(addr_in->sin_port));
|
||||
if (is_whitelist_ip(ip)) return true;
|
||||
if (ip[0] == 127) return true;
|
||||
if (ip[0] == 10) return true;
|
||||
if (ip[0] == 192 && ip[1] == 168) return true;
|
||||
if (ip[0] == 169 && ip[1] == 254 && ip[2] != 0) return true;
|
||||
if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) return true;
|
||||
if ((ip[0] == 100) && ((ip[1] & 0xC0) == 0x40)) return true;
|
||||
if (ip[0] == 239) return true; //multicast
|
||||
if (ip[0] == 0) return true; //Current network
|
||||
if (ip[0] == 192 && (ip[1] == 18 || ip[1] == 19)) return true; //Used for benchmark testing of inter-network communications between two separate subnets.
|
||||
if (ip[0] >= 224) return true; //ip multicast (224 - 239) future use (240.0.0.0–255.255.255.254) broadcast (255.255.255.255)
|
||||
if (is_lan_ipv4(ip)) return true;
|
||||
} else if (addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
|
||||
unsigned char ip[16];
|
||||
unsigned char zeroes[16] = {};
|
||||
memcpy(ip, &addr_in6->sin6_addr, sizeof(ip));
|
||||
PRINT_DEBUG("CHECK LAN IP6 %hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu...%hhu\n", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[15]);
|
||||
PRINT_DEBUG("CHECK LAN IP6 %hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu\n", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]);
|
||||
if (((ip[0] == 0xFF) && (ip[1] < 3) && (ip[15] == 1)) ||
|
||||
((ip[0] == 0xFE) && ((ip[1] & 0xC0) == 0x80))) return true;
|
||||
if (memcmp(zeroes, ip, sizeof(ip)) == 0) return true;
|
||||
|
@ -596,7 +602,13 @@ static bool is_lan_ip(const sockaddr *addr, int namelen)
|
|||
if (ip[0] == 0xff) return true; //multicast
|
||||
if (ip[0] == 0xfc) return true; //unique local
|
||||
if (ip[0] == 0xfd) return true; //unique local
|
||||
//TODO: ipv4 mapped?
|
||||
|
||||
unsigned char ipv4_mapped[12] = {};
|
||||
ipv4_mapped[10] = 0xFF;
|
||||
ipv4_mapped[11] = 0xFF;
|
||||
if (memcmp(ipv4_mapped, ip, sizeof(ipv4_mapped)) == 0) {
|
||||
if (is_lan_ipv4(ip + 12)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_DEBUG("NOT LAN IP\n");
|
||||
|
|
16
dll/dll.cpp
16
dll/dll.cpp
|
@ -129,23 +129,23 @@ STEAMAPI_API ISteamClient *g_pSteamClientGameServer;
|
|||
ISteamClient *g_pSteamClientGameServer;
|
||||
#endif
|
||||
|
||||
static Steam_Client *client;
|
||||
static Steam_Client *steamclient_instance;
|
||||
Steam_Client *get_steam_client()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (!client) {
|
||||
client = new Steam_Client();
|
||||
if (!steamclient_instance) {
|
||||
steamclient_instance = new Steam_Client();
|
||||
}
|
||||
|
||||
return client;
|
||||
return steamclient_instance;
|
||||
}
|
||||
|
||||
void destroy_client()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (client) {
|
||||
delete client;
|
||||
client = NULL;
|
||||
if (steamclient_instance) {
|
||||
delete steamclient_instance;
|
||||
steamclient_instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,6 +416,7 @@ STEAMAPI_API void S_CALLTYPE SteamAPI_UnregisterCallback( class CCallbackBase *p
|
|||
{
|
||||
PRINT_DEBUG("SteamAPI_UnregisterCallback %p\n", pCallback);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (!steamclient_instance) return;
|
||||
get_steam_client()->UnregisterCallback(pCallback);
|
||||
}
|
||||
|
||||
|
@ -435,6 +436,7 @@ STEAMAPI_API void S_CALLTYPE SteamAPI_UnregisterCallResult( class CCallbackBase
|
|||
if (!hAPICall)
|
||||
return;
|
||||
|
||||
if (!steamclient_instance) return;
|
||||
get_steam_client()->UnregisterCallResult(pCallback, hAPICall);
|
||||
}
|
||||
|
||||
|
|
|
@ -156,6 +156,9 @@ public:
|
|||
//app build id
|
||||
int build_id = 10;
|
||||
|
||||
//supported languages
|
||||
std::set<std::string> supported_languages;
|
||||
|
||||
//make lobby creation fail in the matchmaking interface
|
||||
bool disable_lobby_creation = false;
|
||||
|
||||
|
|
|
@ -260,6 +260,41 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
|
|||
local_storage->store_data_settings("user_steam_id.txt", temp_text, strlen(temp_text));
|
||||
}
|
||||
|
||||
std::set<std::string> supported_languages;
|
||||
|
||||
{
|
||||
std::string lang_config_path = Local_Storage::get_game_settings_path() + "supported_languages.txt";
|
||||
std::ifstream input( utf8_decode(lang_config_path) );
|
||||
|
||||
std::string first_language;
|
||||
if (input.is_open()) {
|
||||
consume_bom(input);
|
||||
for( std::string line; getline( input, line ); ) {
|
||||
if (!line.empty() && line[line.length()-1] == '\n') {
|
||||
line.pop_back();
|
||||
}
|
||||
|
||||
if (!line.empty() && line[line.length()-1] == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
|
||||
try {
|
||||
std::string lang = line;
|
||||
if (!first_language.size()) first_language = lang;
|
||||
supported_languages.insert(lang);
|
||||
PRINT_DEBUG("Added supported_language %s\n", lang.c_str());
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (!supported_languages.count(language)) {
|
||||
if (first_language.size()) {
|
||||
memset(language, 0, sizeof(language));
|
||||
first_language.copy(language, sizeof(language) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool steam_offline_mode = false;
|
||||
bool disable_networking = false;
|
||||
bool disable_overlay = false;
|
||||
|
@ -336,6 +371,8 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
|
|||
settings_server->warn_forced = warn_forced;
|
||||
settings_client->warn_local_save = local_save;
|
||||
settings_server->warn_local_save = local_save;
|
||||
settings_client->supported_languages = supported_languages;
|
||||
settings_server->supported_languages = supported_languages;
|
||||
|
||||
{
|
||||
std::string dlc_config_path = Local_Storage::get_game_settings_path() + "DLC.txt";
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
english
|
||||
german
|
||||
french
|
||||
spanish
|
||||
schinese
|
||||
russian
|
||||
japanese
|
||||
latam
|
|
@ -134,7 +134,7 @@ private:
|
|||
bool vulkan_hooked;
|
||||
|
||||
Base_Hook detection_hooks;
|
||||
Renderer_Hook* renderer_hook;
|
||||
ingame_overlay::Renderer_Hook* renderer_hook;
|
||||
DX12_Hook* dx12_hook;
|
||||
DX11_Hook* dx11_hook;
|
||||
DX10_Hook* dx10_hook;
|
||||
|
@ -238,7 +238,7 @@ private:
|
|||
void HookDetected(T*& detected_renderer)
|
||||
{
|
||||
detection_hooks.UnhookAll();
|
||||
renderer_hook = static_cast<Renderer_Hook*>(detected_renderer);
|
||||
renderer_hook = static_cast<ingame_overlay::Renderer_Hook*>(detected_renderer);
|
||||
detected_renderer = nullptr;
|
||||
detection_done = true;
|
||||
DestroyHWND();
|
||||
|
@ -1032,7 +1032,7 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
|
||||
ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
|
||||
{
|
||||
std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock);
|
||||
|
||||
|
@ -1173,7 +1173,7 @@ private:
|
|||
bool openglx_hooked;
|
||||
//bool vulkan_hooked;
|
||||
|
||||
Renderer_Hook* renderer_hook;
|
||||
ingame_overlay::Renderer_Hook* renderer_hook;
|
||||
OpenGLX_Hook* openglx_hook;
|
||||
|
||||
bool detection_done;
|
||||
|
@ -1191,7 +1191,7 @@ private:
|
|||
if (gladLoaderLoadGL() >= GLAD_MAKE_VERSION(3, 1))
|
||||
{
|
||||
inst->detection_hooks.UnhookAll();
|
||||
inst->renderer_hook = static_cast<Renderer_Hook*>(Inst()->openglx_hook);
|
||||
inst->renderer_hook = static_cast<ingame_overlay::Renderer_Hook*>(Inst()->openglx_hook);
|
||||
inst->openglx_hook = nullptr;
|
||||
inst->detection_done = true;
|
||||
}
|
||||
|
@ -1238,7 +1238,7 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
|
||||
ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
|
||||
{
|
||||
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)> libraries[]{
|
||||
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)>{OpenGLX_Hook::DLL_NAME, &Renderer_Detector::hook_openglx},
|
||||
|
@ -1352,7 +1352,7 @@ private:
|
|||
|
||||
bool opengl_hooked;
|
||||
|
||||
Renderer_Hook* renderer_hook;
|
||||
ingame_overlay::Renderer_Hook* renderer_hook;
|
||||
OpenGL_Hook* opengl_hook;
|
||||
|
||||
bool detection_done;
|
||||
|
@ -1368,7 +1368,7 @@ private:
|
|||
if (gladLoaderLoadGL() >= GLAD_MAKE_VERSION(2, 0))
|
||||
{
|
||||
inst->detection_hooks.UnhookAll();
|
||||
inst->renderer_hook = static_cast<Renderer_Hook*>(Inst()->opengl_hook);
|
||||
inst->renderer_hook = static_cast<ingame_overlay::Renderer_Hook*>(Inst()->opengl_hook);
|
||||
inst->opengl_hook = nullptr;
|
||||
inst->detection_done = true;
|
||||
}
|
||||
|
@ -1417,7 +1417,7 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
|
||||
ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
|
||||
{
|
||||
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)> libraries[]{
|
||||
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)>{OpenGL_Hook::DLL_NAME, &Renderer_Detector::hook_opengl}
|
||||
|
@ -1495,7 +1495,7 @@ Renderer_Detector* Renderer_Detector::instance = nullptr;
|
|||
|
||||
namespace ingame_overlay {
|
||||
|
||||
std::future<Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout)
|
||||
std::future<ingame_overlay::Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout)
|
||||
{
|
||||
return std::async(std::launch::async, &Renderer_Detector::detect_renderer, Renderer_Detector::Inst(), timeout);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,16 @@
|
|||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
|
||||
namespace ingame_overlay {
|
||||
|
||||
enum class ToggleKey
|
||||
{
|
||||
SHIFT, CTRL, ALT,
|
||||
TAB,
|
||||
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||||
};
|
||||
|
||||
class Renderer_Hook
|
||||
{
|
||||
|
@ -37,7 +47,7 @@ public:
|
|||
std::function<void()> OverlayProc;
|
||||
std::function<void(bool)> OverlayHookReady;
|
||||
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback) = 0;
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ToggleKey> toggle_keys) = 0;
|
||||
virtual bool IsStarted() = 0;
|
||||
// Returns a Handle to the renderer image ressource or nullptr if it failed to create the resource, the handle can be used in ImGui's Image calls, image_buffer must be RGBA ordered
|
||||
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height) = 0;
|
||||
|
@ -45,3 +55,5 @@ public:
|
|||
|
||||
virtual std::string GetLibraryName() const = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -29,7 +29,7 @@ OpenGLX_Hook* OpenGLX_Hook::_inst = nullptr;
|
|||
|
||||
constexpr decltype(OpenGLX_Hook::DLL_NAME) OpenGLX_Hook::DLL_NAME;
|
||||
|
||||
bool OpenGLX_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||
bool OpenGLX_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
|
||||
{
|
||||
if (!_Hooked)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ bool OpenGLX_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!X11_Hook::Inst()->StartHook(key_combination_callback))
|
||||
if (!X11_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
|
||||
return false;
|
||||
|
||||
_X11Hooked = true;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <GL/glx.h>
|
||||
|
||||
class OpenGLX_Hook :
|
||||
public Renderer_Hook,
|
||||
public ingame_overlay::Renderer_Hook,
|
||||
public Base_Hook
|
||||
{
|
||||
public:
|
||||
|
@ -59,7 +59,7 @@ public:
|
|||
|
||||
virtual ~OpenGLX_Hook();
|
||||
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
|
||||
virtual bool IsStarted();
|
||||
static OpenGLX_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
|
|
|
@ -29,10 +29,62 @@ constexpr decltype(X11_Hook::DLL_NAME) X11_Hook::DLL_NAME;
|
|||
|
||||
X11_Hook* X11_Hook::_inst = nullptr;
|
||||
|
||||
bool X11_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback)
|
||||
uint32_t ToggleKeyToNativeKey(ingame_overlay::ToggleKey k)
|
||||
{
|
||||
struct {
|
||||
ingame_overlay::ToggleKey lib_key;
|
||||
uint32_t native_key;
|
||||
} mapping[] = {
|
||||
{ ingame_overlay::ToggleKey::ALT , XK_Alt_L },
|
||||
{ ingame_overlay::ToggleKey::CTRL , XK_Control_L },
|
||||
{ ingame_overlay::ToggleKey::SHIFT, XK_Shift_L },
|
||||
{ ingame_overlay::ToggleKey::TAB , XK_Tab },
|
||||
{ ingame_overlay::ToggleKey::F1 , XK_F1 },
|
||||
{ ingame_overlay::ToggleKey::F2 , XK_F2 },
|
||||
{ ingame_overlay::ToggleKey::F3 , XK_F3 },
|
||||
{ ingame_overlay::ToggleKey::F4 , XK_F4 },
|
||||
{ ingame_overlay::ToggleKey::F5 , XK_F5 },
|
||||
{ ingame_overlay::ToggleKey::F6 , XK_F6 },
|
||||
{ ingame_overlay::ToggleKey::F7 , XK_F7 },
|
||||
{ ingame_overlay::ToggleKey::F8 , XK_F8 },
|
||||
{ ingame_overlay::ToggleKey::F9 , XK_F9 },
|
||||
{ ingame_overlay::ToggleKey::F10 , XK_F10 },
|
||||
{ ingame_overlay::ToggleKey::F11 , XK_F11 },
|
||||
{ ingame_overlay::ToggleKey::F12 , XK_F12 },
|
||||
};
|
||||
|
||||
for (auto const& item : mapping)
|
||||
{
|
||||
if (item.lib_key == k)
|
||||
return item.native_key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool GetKeyState(Display* d, KeySym keySym, char szKey[32])
|
||||
{
|
||||
int iKeyCodeToFind = XKeysymToKeycode(d, keySym);
|
||||
|
||||
return szKey[iKeyCodeToFind / 8] & (1 << (iKeyCodeToFind % 8));
|
||||
}
|
||||
|
||||
bool X11_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback, std::set<ingame_overlay::ToggleKey> const& toggle_keys)
|
||||
{
|
||||
if (!_Hooked)
|
||||
{
|
||||
if (!_key_combination_callback)
|
||||
{
|
||||
SPDLOG_ERROR("Failed to hook X11: No key combination callback.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (toggle_keys.empty())
|
||||
{
|
||||
SPDLOG_ERROR("Failed to hook X11: No key combination.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void* hX11 = System::Library::GetLibraryHandle(DLL_NAME);
|
||||
if (hX11 == nullptr)
|
||||
{
|
||||
|
@ -60,6 +112,16 @@ bool X11_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback)
|
|||
SPDLOG_INFO("Hooked X11");
|
||||
|
||||
_KeyCombinationCallback = std::move(_key_combination_callback);
|
||||
|
||||
for (auto& key : toggle_keys)
|
||||
{
|
||||
uint32_t k = ToggleKeyToNativeKey(key);
|
||||
if (k != 0)
|
||||
{
|
||||
_NativeKeyCombination.insert(k);
|
||||
}
|
||||
}
|
||||
|
||||
_Hooked = true;
|
||||
|
||||
UnhookAll();
|
||||
|
@ -140,33 +202,47 @@ int X11_Hook::_CheckForOverlay(Display *d, int num_events)
|
|||
static Time prev_time = {};
|
||||
X11_Hook* inst = Inst();
|
||||
|
||||
if( inst->_Initialized )
|
||||
char szKey[32];
|
||||
|
||||
if( _Initialized )
|
||||
{
|
||||
XEvent event;
|
||||
while(num_events)
|
||||
{
|
||||
bool skip_input = inst->_KeyCombinationCallback(false);
|
||||
bool skip_input = _KeyCombinationCallback(false);
|
||||
|
||||
XPeekEvent(d, &event);
|
||||
ImGui_ImplX11_EventHandler(event);
|
||||
|
||||
// Is the event is a key press
|
||||
if (event.type == KeyPress)
|
||||
if (event.type == KeyPress || event.type == KeyRelease)
|
||||
{
|
||||
// Tab is pressed and was not pressed before
|
||||
if (event.xkey.keycode == XKeysymToKeycode(d, XK_Tab) && event.xkey.state & ShiftMask)
|
||||
XQueryKeymap(d, szKey);
|
||||
int key_count = 0;
|
||||
for (auto const& key : inst->_NativeKeyCombination)
|
||||
{
|
||||
// if key TAB is held, don't make the overlay flicker :p
|
||||
if (event.xkey.time != prev_time)
|
||||
if (GetKeyState(d, key, szKey))
|
||||
++key_count;
|
||||
}
|
||||
|
||||
if (key_count == inst->_NativeKeyCombination.size())
|
||||
{// All shortcut keys are pressed
|
||||
if (!inst->_KeyCombinationPushed)
|
||||
{
|
||||
skip_input = true;
|
||||
inst->_KeyCombinationCallback(true);
|
||||
if (inst->_KeyCombinationCallback(true))
|
||||
{
|
||||
skip_input = true;
|
||||
// Save the last known cursor pos when opening the overlay
|
||||
// so we can spoof the GetCursorPos return value.
|
||||
//inst->GetCursorPos(&inst->_SavedCursorPos);
|
||||
}
|
||||
inst->_KeyCombinationPushed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(event.type == KeyRelease && event.xkey.keycode == XKeysymToKeycode(d, XK_Tab))
|
||||
{
|
||||
prev_time = event.xkey.time;
|
||||
else
|
||||
{
|
||||
inst->_KeyCombinationPushed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip_input || !IgnoreEvent(event))
|
||||
|
@ -215,6 +291,7 @@ X11_Hook::X11_Hook() :
|
|||
_Initialized(false),
|
||||
_Hooked(false),
|
||||
_GameWnd(0),
|
||||
_KeyCombinationPushed(false),
|
||||
XEventsQueued(nullptr),
|
||||
XPending(nullptr)
|
||||
{
|
||||
|
@ -241,3 +318,4 @@ std::string X11_Hook::GetLibraryName() const
|
|||
{
|
||||
return LibraryName;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,12 @@ private:
|
|||
bool _Initialized;
|
||||
Window _GameWnd;
|
||||
|
||||
// In (bool): Is toggle wanted
|
||||
// Out(bool): Is the overlay visible, if true, inputs will be disabled
|
||||
std::function<bool(bool)> _KeyCombinationCallback;
|
||||
std::set<uint32_t> _NativeKeyCombination;
|
||||
bool _KeyCombinationPushed;
|
||||
|
||||
// Functions
|
||||
X11_Hook();
|
||||
int _CheckForOverlay(Display *d, int num_events);
|
||||
|
@ -52,8 +58,6 @@ private:
|
|||
static int MyXEventsQueued(Display * display, int mode);
|
||||
static int MyXPending(Display* display);
|
||||
|
||||
std::function<bool(bool)> _KeyCombinationCallback;
|
||||
|
||||
public:
|
||||
std::string LibraryName;
|
||||
|
||||
|
@ -65,7 +69,7 @@ public:
|
|||
|
||||
Window GetGameWnd() const{ return _GameWnd; }
|
||||
|
||||
bool StartHook(std::function<bool(bool)>& key_combination_callback);
|
||||
bool StartHook(std::function<bool(bool)>& key_combination_callback, std::set<ingame_overlay::ToggleKey> const& toggle_keys);
|
||||
static X11_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
};
|
||||
|
|
|
@ -213,6 +213,7 @@ void Steam_Overlay::UnSetupOverlay()
|
|||
|
||||
void Steam_Overlay::HookReady(bool ready)
|
||||
{
|
||||
PRINT_DEBUG("%s %u\n", __FUNCTION__, ready);
|
||||
{
|
||||
// TODO: Uncomment this and draw our own cursor (cosmetics)
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
|
@ -223,9 +224,6 @@ void Steam_Overlay::HookReady(bool ready)
|
|||
io.IniFilename = NULL;
|
||||
|
||||
is_ready = ready;
|
||||
if (is_ready) {
|
||||
CreateFonts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -710,18 +708,64 @@ void Steam_Overlay::BuildNotifications(int width, int height)
|
|||
|
||||
void Steam_Overlay::CreateFonts()
|
||||
{
|
||||
//TODO: remove from dx_whatever hook
|
||||
if(ImGui::GetCurrentContext() == nullptr)
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImFontConfig fontcfg;
|
||||
|
||||
float font_size = 16.0;
|
||||
fontcfg.OversampleH = fontcfg.OversampleV = 1;
|
||||
fontcfg.PixelSnapH = true;
|
||||
fontcfg.GlyphRanges = io.Fonts->GetGlyphRangesDefault();
|
||||
fontcfg.SizePixels = font_size;
|
||||
|
||||
font_default = io.Fonts->AddFontDefault(&fontcfg);
|
||||
font_notif = io.Fonts->AddFontDefault(&fontcfg);
|
||||
ImFontGlyphRangesBuilder font_builder;
|
||||
for (auto & x : achievements) {
|
||||
font_builder.AddText(x.title.c_str());
|
||||
font_builder.AddText(x.description.c_str());
|
||||
}
|
||||
|
||||
font_builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
|
||||
|
||||
ImVector<ImWchar> ranges;
|
||||
font_builder.BuildRanges(&ranges);
|
||||
|
||||
bool need_extra_fonts = false;
|
||||
for (auto &x : ranges) {
|
||||
if (x > 0xFF) {
|
||||
need_extra_fonts = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fontcfg.GlyphRanges = ranges.Data;
|
||||
ImFont *font = NULL;
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
font = io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\micross.ttf", font_size, &fontcfg);
|
||||
#endif
|
||||
|
||||
if (!font) {
|
||||
font = io.Fonts->AddFontDefault(&fontcfg);
|
||||
}
|
||||
|
||||
font_notif = font_default = font;
|
||||
|
||||
if (need_extra_fonts) {
|
||||
PRINT_DEBUG("loading extra fonts\n");
|
||||
fontcfg.MergeMode = true;
|
||||
#if defined(__WINDOWS__)
|
||||
io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\simsun.ttc", font_size, &fontcfg);
|
||||
io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\malgun.ttf", font_size, &fontcfg);
|
||||
#endif
|
||||
}
|
||||
|
||||
io.Fonts->Build();
|
||||
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style.WindowRounding = 0.0; // Disable round window
|
||||
reset_LastError();
|
||||
}
|
||||
|
||||
// Try to make this function as short as possible or it might affect game's fps.
|
||||
|
@ -893,7 +937,7 @@ void Steam_Overlay::OverlayProc()
|
|||
|
||||
bool show_warning = local_save || warning_forced || appid == 0;
|
||||
if (show_warning) {
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(ImGui::GetFontSize() * 64, ImGui::GetFontSize() * 64), ImVec2(8192, 8192));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(ImGui::GetFontSize() * 32, ImGui::GetFontSize() * 32), ImVec2(8192, 8192));
|
||||
ImGui::SetNextWindowFocus();
|
||||
if (ImGui::Begin("WARNING", &show_warning)) {
|
||||
if (appid == 0) {
|
||||
|
@ -955,10 +999,45 @@ void Steam_Overlay::Callback(Common_Message *msg)
|
|||
|
||||
void Steam_Overlay::RunCallbacks()
|
||||
{
|
||||
if (!achievements.size()) {
|
||||
Steam_User_Stats* steamUserStats = get_steam_client()->steam_user_stats;
|
||||
uint32 achievements_num = steamUserStats->GetNumAchievements();
|
||||
if (achievements_num) {
|
||||
PRINT_DEBUG("POPULATE OVERLAY ACHIEVEMENTS\n");
|
||||
for (unsigned i = 0; i < achievements_num; ++i) {
|
||||
Overlay_Achievement ach;
|
||||
ach.name = steamUserStats->GetAchievementName(i);
|
||||
ach.title = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "name");
|
||||
ach.description = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "desc");
|
||||
const char *hidden = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "hidden");
|
||||
if (strlen(hidden) && hidden[0] == '1') {
|
||||
ach.hidden = true;
|
||||
} else {
|
||||
ach.hidden = false;
|
||||
}
|
||||
|
||||
bool achieved = false;
|
||||
uint32 unlock_time = 0;
|
||||
if (steamUserStats->GetAchievementAndUnlockTime(ach.name.c_str(), &achieved, &unlock_time)) {
|
||||
ach.achieved = achieved;
|
||||
ach.unlock_time = unlock_time;
|
||||
} else {
|
||||
ach.achieved = false;
|
||||
ach.unlock_time = 0;
|
||||
}
|
||||
|
||||
achievements.push_back(ach);
|
||||
}
|
||||
|
||||
PRINT_DEBUG("POPULATE OVERLAY ACHIEVEMENTS DONE\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!Ready() && future_renderer.valid()) {
|
||||
if (future_renderer.wait_for(std::chrono::milliseconds{0}) == std::future_status::ready) {
|
||||
_renderer = future_renderer.get();
|
||||
PRINT_DEBUG("got renderer %p\n", _renderer);
|
||||
CreateFonts();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -967,7 +1046,8 @@ void Steam_Overlay::RunCallbacks()
|
|||
_renderer->OverlayProc = std::bind(&Steam_Overlay::OverlayProc, this);
|
||||
auto callback = std::bind(&Steam_Overlay::OpenOverlayHook, this, std::placeholders::_1);
|
||||
PRINT_DEBUG("start renderer\n", _renderer);
|
||||
bool started = _renderer->StartHook(callback);
|
||||
std::set<ingame_overlay::ToggleKey> keys = {ingame_overlay::ToggleKey::SHIFT, ingame_overlay::ToggleKey::TAB};
|
||||
bool started = _renderer->StartHook(callback, keys);
|
||||
PRINT_DEBUG("tried to start renderer %u\n", started);
|
||||
}
|
||||
|
||||
|
@ -1094,40 +1174,6 @@ void Steam_Overlay::RunCallbacks()
|
|||
}
|
||||
has_friend_action.pop();
|
||||
}
|
||||
|
||||
if (!achievements.size()) {
|
||||
Steam_User_Stats* steamUserStats = get_steam_client()->steam_user_stats;
|
||||
uint32 achievements_num = steamUserStats->GetNumAchievements();
|
||||
if (achievements_num) {
|
||||
PRINT_DEBUG("POPULATE OVERLAY ACHIEVEMENTS\n");
|
||||
for (unsigned i = 0; i < achievements_num; ++i) {
|
||||
Overlay_Achievement ach;
|
||||
ach.name = steamUserStats->GetAchievementName(i);
|
||||
ach.title = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "name");
|
||||
ach.description = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "desc");
|
||||
const char *hidden = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "hidden");
|
||||
if (strlen(hidden) && hidden[0] == '1') {
|
||||
ach.hidden = true;
|
||||
} else {
|
||||
ach.hidden = false;
|
||||
}
|
||||
|
||||
bool achieved = false;
|
||||
uint32 unlock_time = 0;
|
||||
if (steamUserStats->GetAchievementAndUnlockTime(ach.name.c_str(), &achieved, &unlock_time)) {
|
||||
ach.achieved = achieved;
|
||||
ach.unlock_time = unlock_time;
|
||||
} else {
|
||||
ach.achieved = false;
|
||||
ach.unlock_time = 0;
|
||||
}
|
||||
|
||||
achievements.push_back(ach);
|
||||
}
|
||||
|
||||
PRINT_DEBUG("POPULATE OVERLAY ACHIEVEMENTS DONE\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -123,8 +123,8 @@ class Steam_Overlay
|
|||
|
||||
std::recursive_mutex overlay_mutex;
|
||||
std::atomic<bool> i_have_lobby;
|
||||
std::future<Renderer_Hook*> future_renderer;
|
||||
Renderer_Hook* _renderer;
|
||||
std::future<ingame_overlay::Renderer_Hook*> future_renderer;
|
||||
ingame_overlay::Renderer_Hook* _renderer;
|
||||
|
||||
Steam_Overlay(Steam_Overlay const&) = delete;
|
||||
Steam_Overlay(Steam_Overlay&&) = delete;
|
||||
|
|
|
@ -35,7 +35,7 @@ inline void SafeRelease(T*& pUnk)
|
|||
}
|
||||
}
|
||||
|
||||
bool DX10_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||
bool DX10_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
|
||||
{
|
||||
if (!_Hooked)
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ bool DX10_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
|
||||
return false;
|
||||
|
||||
_WindowsHooked = true;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <dxgi1_2.h>
|
||||
|
||||
class DX10_Hook :
|
||||
public Renderer_Hook,
|
||||
public ingame_overlay::Renderer_Hook,
|
||||
public Base_Hook
|
||||
{
|
||||
public:
|
||||
|
@ -64,7 +64,7 @@ public:
|
|||
|
||||
virtual ~DX10_Hook();
|
||||
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
|
||||
virtual bool IsStarted();
|
||||
static DX10_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
|
|
|
@ -45,7 +45,7 @@ static HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11De
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool DX11_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||
bool DX11_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
|
||||
{
|
||||
if (!_Hooked)
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ bool DX11_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
|
||||
return false;
|
||||
|
||||
_WindowsHooked = true;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <dxgi1_2.h>
|
||||
|
||||
class DX11_Hook :
|
||||
public Renderer_Hook,
|
||||
public ingame_overlay::Renderer_Hook,
|
||||
public Base_Hook
|
||||
{
|
||||
public:
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
|
||||
virtual ~DX11_Hook();
|
||||
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
|
||||
virtual bool IsStarted();
|
||||
static DX11_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
|
|
|
@ -35,7 +35,7 @@ inline void SafeRelease(T*& pUnk)
|
|||
}
|
||||
}
|
||||
|
||||
bool DX12_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||
bool DX12_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
|
||||
{
|
||||
if (!_Hooked)
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ bool DX12_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
|
||||
return false;
|
||||
|
||||
_WindowsHooked = true;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <dxgi1_4.h>
|
||||
|
||||
class DX12_Hook :
|
||||
public Renderer_Hook,
|
||||
public ingame_overlay::Renderer_Hook,
|
||||
public Base_Hook
|
||||
{
|
||||
public:
|
||||
|
@ -127,7 +127,7 @@ public:
|
|||
|
||||
virtual ~DX12_Hook();
|
||||
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
|
||||
virtual bool IsStarted();
|
||||
static DX12_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
|
|
|
@ -36,7 +36,7 @@ inline void SafeRelease(T*& pUnk)
|
|||
}
|
||||
}
|
||||
|
||||
bool DX9_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||
bool DX9_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
|
||||
{
|
||||
if (!_Hooked)
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ bool DX9_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
|
||||
return false;
|
||||
|
||||
_WindowsHooked = true;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <d3d9.h>
|
||||
|
||||
class DX9_Hook :
|
||||
public Renderer_Hook,
|
||||
public ingame_overlay::Renderer_Hook,
|
||||
public Base_Hook
|
||||
{
|
||||
public:
|
||||
|
@ -63,7 +63,7 @@ public:
|
|||
|
||||
virtual ~DX9_Hook();
|
||||
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
|
||||
virtual bool IsStarted();
|
||||
static DX9_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
OpenGL_Hook* OpenGL_Hook::_inst = nullptr;
|
||||
|
||||
bool OpenGL_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||
bool OpenGL_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
|
||||
{
|
||||
if (!_Hooked)
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ bool OpenGL_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
|
||||
return false;
|
||||
|
||||
_WindowsHooked = true;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "../internal_includes.h"
|
||||
|
||||
class OpenGL_Hook :
|
||||
public Renderer_Hook,
|
||||
public ingame_overlay::Renderer_Hook,
|
||||
public Base_Hook
|
||||
{
|
||||
public:
|
||||
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
virtual ~OpenGL_Hook();
|
||||
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
|
||||
virtual bool IsStarted();
|
||||
static OpenGL_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
Vulkan_Hook* Vulkan_Hook::_inst = nullptr;
|
||||
|
||||
bool Vulkan_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||
bool Vulkan_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
|
||||
{
|
||||
SPDLOG_WARN("Vulkan overlay is not yet supported.");
|
||||
return false;
|
||||
|
@ -37,7 +37,7 @@ bool Vulkan_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
|
||||
return false;
|
||||
|
||||
_WindowsHooked = true;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <vulkan/vulkan.h>
|
||||
|
||||
class Vulkan_Hook :
|
||||
public Renderer_Hook,
|
||||
public ingame_overlay::Renderer_Hook,
|
||||
public Base_Hook
|
||||
{
|
||||
public:
|
||||
|
@ -54,7 +54,7 @@ public:
|
|||
|
||||
virtual ~Vulkan_Hook();
|
||||
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
|
||||
virtual bool IsStarted();
|
||||
static Vulkan_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
|
|
|
@ -29,10 +29,55 @@ constexpr decltype(Windows_Hook::DLL_NAME) Windows_Hook::DLL_NAME;
|
|||
|
||||
Windows_Hook* Windows_Hook::_inst = nullptr;
|
||||
|
||||
bool Windows_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback)
|
||||
int ToggleKeyToNativeKey(ingame_overlay::ToggleKey k)
|
||||
{
|
||||
struct {
|
||||
ingame_overlay::ToggleKey lib_key;
|
||||
int native_key;
|
||||
} mapping[] = {
|
||||
{ ingame_overlay::ToggleKey::ALT , VK_MENU },
|
||||
{ ingame_overlay::ToggleKey::CTRL , VK_CONTROL },
|
||||
{ ingame_overlay::ToggleKey::SHIFT, VK_SHIFT },
|
||||
{ ingame_overlay::ToggleKey::TAB , VK_TAB },
|
||||
{ ingame_overlay::ToggleKey::F1 , VK_F1 },
|
||||
{ ingame_overlay::ToggleKey::F2 , VK_F2 },
|
||||
{ ingame_overlay::ToggleKey::F3 , VK_F3 },
|
||||
{ ingame_overlay::ToggleKey::F4 , VK_F4 },
|
||||
{ ingame_overlay::ToggleKey::F5 , VK_F5 },
|
||||
{ ingame_overlay::ToggleKey::F6 , VK_F6 },
|
||||
{ ingame_overlay::ToggleKey::F7 , VK_F7 },
|
||||
{ ingame_overlay::ToggleKey::F8 , VK_F8 },
|
||||
{ ingame_overlay::ToggleKey::F9 , VK_F9 },
|
||||
{ ingame_overlay::ToggleKey::F10 , VK_F10 },
|
||||
{ ingame_overlay::ToggleKey::F11 , VK_F11 },
|
||||
{ ingame_overlay::ToggleKey::F12 , VK_F12 },
|
||||
};
|
||||
|
||||
for (auto const& item : mapping)
|
||||
{
|
||||
if (item.lib_key == k)
|
||||
return item.native_key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Windows_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback, std::set<ingame_overlay::ToggleKey> const& toggle_keys)
|
||||
{
|
||||
if (!_Hooked)
|
||||
{
|
||||
if (!_key_combination_callback)
|
||||
{
|
||||
SPDLOG_ERROR("Failed to hook Windows: No key combination callback.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (toggle_keys.empty())
|
||||
{
|
||||
SPDLOG_ERROR("Failed to hook Windows: No key combination.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void* hUser32 = System::Library::GetLibraryHandle(DLL_NAME);
|
||||
if (hUser32 == nullptr)
|
||||
{
|
||||
|
@ -71,6 +116,15 @@ bool Windows_Hook::StartHook(std::function<bool(bool)>& _key_combination_callbac
|
|||
SPDLOG_INFO("Hooked Windows");
|
||||
_KeyCombinationCallback = std::move(_key_combination_callback);
|
||||
|
||||
for (auto& key : toggle_keys)
|
||||
{
|
||||
uint32_t k = ToggleKeyToNativeKey(key);
|
||||
if (k != 0)
|
||||
{
|
||||
_NativeKeyCombination.insert(k);
|
||||
}
|
||||
}
|
||||
|
||||
BeginHook();
|
||||
HookFuncs(
|
||||
std::make_pair<void**, void*>(&(PVOID&)GetRawInputBuffer, &Windows_Hook::MyGetRawInputBuffer),
|
||||
|
@ -134,12 +188,9 @@ bool Windows_Hook::PrepareForOverlay(HWND hWnd)
|
|||
POINT pos;
|
||||
if (this->GetCursorPos(&pos) && ScreenToClient(hWnd, &pos))
|
||||
{
|
||||
io.MousePos = ImVec2((float)pos.x, (float)pos.y);
|
||||
io.AddMousePosEvent((float)pos.x, (float)pos.y);
|
||||
}
|
||||
|
||||
io.KeyCtrl = (this->GetKeyState(VK_CONTROL) & 0x8000) != 0;
|
||||
io.KeyShift = (this->GetKeyState(VK_SHIFT) & 0x8000) != 0;
|
||||
io.KeyAlt = (this->GetKeyState(VK_MENU) & 0x8000) != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -219,13 +270,18 @@ LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
|
|||
if (inst->_Initialized)
|
||||
{
|
||||
// Is the event is a key press
|
||||
if (uMsg == WM_KEYDOWN)
|
||||
if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN || uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP)
|
||||
{
|
||||
// Tab is pressed and was not pressed before
|
||||
if (wParam == VK_TAB && !(lParam & (1 << 30)))
|
||||
int key_count = 0;
|
||||
for (auto const& key : inst->_NativeKeyCombination)
|
||||
{
|
||||
// If Left Shift is pressed
|
||||
if (inst->GetAsyncKeyState(VK_LSHIFT) & (1 << 15))
|
||||
if (inst->GetAsyncKeyState(key) & (1 << 15))
|
||||
++key_count;
|
||||
}
|
||||
|
||||
if (key_count == inst->_NativeKeyCombination.size())
|
||||
{// All shortcut keys are pressed
|
||||
if (!inst->_KeyCombinationPushed)
|
||||
{
|
||||
if (inst->_KeyCombinationCallback(true))
|
||||
{
|
||||
|
@ -234,12 +290,13 @@ LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
|
|||
// so we can spoof the GetCursorPos return value.
|
||||
inst->GetCursorPos(&inst->_SavedCursorPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
clean_keys = true;
|
||||
}
|
||||
inst->_KeyCombinationPushed = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->_KeyCombinationPushed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_input && IgnoreMsg(uMsg))
|
||||
|
@ -248,7 +305,8 @@ LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
|
|||
if (clean_keys)
|
||||
{
|
||||
auto& io = ImGui::GetIO();
|
||||
memset(io.KeysDown, 0, sizeof(io.KeysDown));
|
||||
io.ClearInputKeys();
|
||||
io.ClearInputCharacters();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -369,6 +427,7 @@ Windows_Hook::Windows_Hook() :
|
|||
_RecurseCallCount(0),
|
||||
_GameHwnd(nullptr),
|
||||
_GameWndProc(nullptr),
|
||||
_KeyCombinationPushed(false),
|
||||
GetRawInputBuffer(nullptr),
|
||||
GetRawInputData(nullptr),
|
||||
GetKeyState(nullptr),
|
||||
|
|
|
@ -38,6 +38,12 @@ private:
|
|||
WNDPROC _GameWndProc;
|
||||
POINT _SavedCursorPos;
|
||||
|
||||
// In (bool): Is toggle wanted
|
||||
// Out(bool): Is the overlay visible, if true, inputs will be disabled
|
||||
std::function<bool(bool)> _KeyCombinationCallback;
|
||||
std::set<int> _NativeKeyCombination;
|
||||
bool _KeyCombinationPushed;
|
||||
|
||||
// Functions
|
||||
Windows_Hook();
|
||||
|
||||
|
@ -59,10 +65,6 @@ private:
|
|||
static BOOL WINAPI MyGetCursorPos(LPPOINT lpPoint);
|
||||
static BOOL WINAPI MySetCursorPos(int X, int Y);
|
||||
|
||||
// In (bool): Is toggle wanted
|
||||
// Out(bool): Is the overlay visible, if true, inputs will be disabled
|
||||
std::function<bool(bool)> _KeyCombinationCallback;
|
||||
|
||||
public:
|
||||
std::string LibraryName;
|
||||
|
||||
|
@ -75,7 +77,7 @@ public:
|
|||
HWND GetGameHwnd() const;
|
||||
WNDPROC GetGameWndProc() const;
|
||||
|
||||
bool StartHook(std::function<bool(bool)>& key_combination_callback);
|
||||
bool StartHook(std::function<bool(bool)>& key_combination_callback, std::set<ingame_overlay::ToggleKey> const& toggle_keys);
|
||||
static Windows_Hook* Inst();
|
||||
virtual std::string GetLibraryName() const;
|
||||
};
|
||||
|
|
|
@ -17,6 +17,9 @@ import os
|
|||
import sys
|
||||
import json
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import threading
|
||||
import queue
|
||||
|
||||
prompt_for_unavailable = True
|
||||
|
||||
|
@ -82,7 +85,49 @@ def get_stats_schema(client, game_id, owner_id):
|
|||
client.send(message)
|
||||
return client.wait_msg(EMsg.ClientGetUserStatsResponse, timeout=5)
|
||||
|
||||
def download_achievement_images(game_id, image_names, output_folder):
|
||||
q = queue.Queue()
|
||||
|
||||
def downloader_thread():
|
||||
while True:
|
||||
name = q.get()
|
||||
succeeded = False
|
||||
if name is None:
|
||||
q.task_done()
|
||||
return
|
||||
for u in ["https://cdn.akamai.steamstatic.com/steamcommunity/public/images/apps/", "https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/"]:
|
||||
url = "{}{}/{}".format(u, game_id, name)
|
||||
try:
|
||||
with urllib.request.urlopen(url) as response:
|
||||
image_data = response.read()
|
||||
with open(os.path.join(output_folder, name), "wb") as f:
|
||||
f.write(image_data)
|
||||
succeeded = True
|
||||
break
|
||||
except urllib.error.HTTPError as e:
|
||||
print("HTTPError downloading", url, e.code)
|
||||
except urllib.error.URLError as e:
|
||||
print("URLError downloading", url, e.code)
|
||||
if not succeeded:
|
||||
print("error could not download", name)
|
||||
q.task_done()
|
||||
|
||||
num_threads = 5
|
||||
for i in range(num_threads):
|
||||
threading.Thread(target=downloader_thread, daemon=True).start()
|
||||
|
||||
for name in image_names:
|
||||
q.put(name)
|
||||
q.join()
|
||||
|
||||
for i in range(num_threads):
|
||||
q.put(None)
|
||||
q.join()
|
||||
|
||||
|
||||
def generate_achievement_stats(client, game_id, output_directory, backup_directory):
|
||||
achievement_images_dir = os.path.join(output_directory, "achievement_images")
|
||||
images_to_download = []
|
||||
steam_id_list = TOP_OWNER_IDS + [client.steam_id]
|
||||
for x in steam_id_list:
|
||||
out = get_stats_schema(client, game_id, x)
|
||||
|
@ -91,10 +136,20 @@ def generate_achievement_stats(client, game_id, output_directory, backup_directo
|
|||
with open(os.path.join(backup_directory, 'UserGameStatsSchema_{}.bin'.format(appid)), 'wb') as f:
|
||||
f.write(out.body.schema)
|
||||
achievements, stats = achievements_gen.generate_stats_achievements(out.body.schema, output_directory)
|
||||
return
|
||||
for ach in achievements:
|
||||
if "icon" in ach:
|
||||
images_to_download.append(ach["icon"])
|
||||
if "icon_gray" in ach:
|
||||
images_to_download.append(ach["icon_gray"])
|
||||
break
|
||||
else:
|
||||
print("no schema", out)
|
||||
|
||||
if (len(images_to_download) > 0):
|
||||
if not os.path.exists(achievement_images_dir):
|
||||
os.makedirs(achievement_images_dir)
|
||||
download_achievement_images(game_id, images_to_download, achievement_images_dir)
|
||||
|
||||
def get_ugc_info(client, published_file_id):
|
||||
return client.send_um_and_wait('PublishedFile.GetDetails#1', {
|
||||
'publishedfileids': [published_file_id],
|
||||
|
@ -173,6 +228,13 @@ for appid in appids:
|
|||
game_info_common = game_info["common"]
|
||||
if "community_visible_stats" in game_info_common:
|
||||
generate_achievement_stats(client, appid, out_dir, backup_dir)
|
||||
if "languages" in game_info_common:
|
||||
with open(os.path.join(out_dir, "supported_languages.txt"), 'w') as f:
|
||||
languages = game_info_common["languages"]
|
||||
for l in languages:
|
||||
if languages[l] != "0":
|
||||
f.write("{}\n".format(l))
|
||||
|
||||
|
||||
with open(os.path.join(out_dir, "steam_appid.txt"), 'w') as f:
|
||||
f.write(str(appid))
|
||||
|
@ -187,6 +249,7 @@ for appid in appids:
|
|||
|
||||
dlc_config_list = []
|
||||
dlc_list, depot_app_list = get_dlc(game_info)
|
||||
dlc_infos_backup = ""
|
||||
if (len(dlc_list) > 0):
|
||||
dlc_raw = client.get_product_info(apps=dlc_list)["apps"]
|
||||
for dlc in dlc_raw:
|
||||
|
@ -194,6 +257,7 @@ for appid in appids:
|
|||
dlc_config_list.append((dlc, dlc_raw[dlc]["common"]["name"]))
|
||||
except:
|
||||
dlc_config_list.append((dlc, None))
|
||||
dlc_infos_backup = json.dumps(dlc_raw, indent=4)
|
||||
|
||||
with open(os.path.join(out_dir, "DLC.txt"), 'w', encoding="utf-8") as f:
|
||||
for x in dlc_config_list:
|
||||
|
@ -218,7 +282,21 @@ for appid in appids:
|
|||
if (controller_type in ["controller_xbox360", "controller_xboxone"] and (("default" in enabled_branches) or ("public" in enabled_branches))):
|
||||
parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(out_dir, "controller"))
|
||||
config_generated = True
|
||||
if "steamcontrollertouchconfigdetails" in game_info["config"]:
|
||||
controller_details = game_info["config"]["steamcontrollertouchconfigdetails"]
|
||||
for id in controller_details:
|
||||
details = controller_details[id]
|
||||
controller_type = ""
|
||||
enabled_branches = ""
|
||||
if "controller_type" in details:
|
||||
controller_type = details["controller_type"]
|
||||
if "enabled_branches" in details:
|
||||
enabled_branches = details["enabled_branches"]
|
||||
print(id, controller_type)
|
||||
out_vdf = download_published_file(client, int(id), os.path.join(backup_dir, controller_type + str(id)))
|
||||
|
||||
game_info_backup = json.dumps(game_info, indent=4)
|
||||
with open(os.path.join(backup_dir, "product_info.json"), "w") as f:
|
||||
f.write(game_info_backup)
|
||||
with open(os.path.join(backup_dir, "dlc_product_info.json"), "w") as f:
|
||||
f.write(dlc_infos_backup)
|
||||
|
|
|
@ -75,7 +75,7 @@ def generate_stats_achievements(schema, config_directory):
|
|||
with open(os.path.join(config_directory, "stats.txt"), 'w') as f:
|
||||
f.write(output_stats)
|
||||
|
||||
return (output_ach, output_stats)
|
||||
return (achievements_out, stats_out)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
|
|
Loading…
Reference in New Issue