mirror of
https://gitlab.com/Mr_Goldberg/goldberg_emulator.git
synced 2024-12-25 12:08:39 +01:00
Linux hooks
This commit is contained in:
parent
8a6db1c401
commit
86f94bc337
5 changed files with 514 additions and 18 deletions
|
@ -1,20 +1,13 @@
|
|||
#include "Base_Hook.h"
|
||||
#include "Hook_Manager.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
#ifdef STEAM_WIN32
|
||||
|
||||
#include "../detours/detours.h"
|
||||
|
||||
Base_Hook::Base_Hook():
|
||||
_library(nullptr)
|
||||
{}
|
||||
|
||||
Base_Hook::~Base_Hook()
|
||||
{
|
||||
UnhookAll();
|
||||
}
|
||||
|
||||
void Base_Hook::BeginHook()
|
||||
{
|
||||
DetourTransactionBegin();
|
||||
|
@ -26,6 +19,12 @@ void Base_Hook::EndHook()
|
|||
DetourTransactionCommit();
|
||||
}
|
||||
|
||||
void Base_Hook::HookFunc(std::pair<void**, void*> hook)
|
||||
{
|
||||
if( DetourAttach(hook.first, hook.second) == 0 )
|
||||
_hooked_funcs.emplace_back(hook);
|
||||
}
|
||||
|
||||
void Base_Hook::UnhookAll()
|
||||
{
|
||||
if (_hooked_funcs.size())
|
||||
|
@ -39,15 +38,53 @@ void Base_Hook::UnhookAll()
|
|||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#include "Linux_Detour.h"
|
||||
|
||||
void Base_Hook::BeginHook()
|
||||
{
|
||||
Linux_Detour::transaction_begin();
|
||||
Linux_Detour::update_thread(pthread_self());
|
||||
}
|
||||
|
||||
void Base_Hook::EndHook()
|
||||
{
|
||||
Linux_Detour::transaction_commit();
|
||||
}
|
||||
|
||||
void Base_Hook::HookFunc(std::pair<void**, void*> hook)
|
||||
{
|
||||
if( Linux_Detour::hook_func(hook.first, hook.second) == 0 )
|
||||
_hooked_funcs.emplace_back(hook);
|
||||
}
|
||||
|
||||
void Base_Hook::UnhookAll()
|
||||
{
|
||||
if (_hooked_funcs.size())
|
||||
{
|
||||
BeginHook();
|
||||
std::for_each(_hooked_funcs.begin(), _hooked_funcs.end(), [](std::pair<void**, void*>& hook) {
|
||||
Linux_Detour::unhook_func(hook.first, hook.second);
|
||||
});
|
||||
EndHook();
|
||||
_hooked_funcs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Base_Hook::Base_Hook():
|
||||
_library(nullptr)
|
||||
{}
|
||||
|
||||
Base_Hook::~Base_Hook()
|
||||
{
|
||||
UnhookAll();
|
||||
}
|
||||
|
||||
const char* Base_Hook::get_lib_name() const
|
||||
{
|
||||
return "<no_name>";
|
||||
}
|
||||
|
||||
void Base_Hook::HookFunc(std::pair<void**, void*> hook)
|
||||
{
|
||||
if( DetourAttach(hook.first, hook.second) == 0 )
|
||||
_hooked_funcs.emplace_back(hook);
|
||||
}
|
||||
|
||||
#endif//NO_OVERLAY
|
||||
#endif//NO_OVERLAY
|
||||
|
|
150
overlay_experimental/OpenGLX_Hook.cpp
Normal file
150
overlay_experimental/OpenGLX_Hook.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
#include "OpenGLX_Hook.h"
|
||||
#include "X11_Hook.h"
|
||||
#include "Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <imgui.h>
|
||||
#include <impls/imgui_impl_opengl3.h>
|
||||
|
||||
#include "steam_overlay.h"
|
||||
|
||||
OpenGLX_Hook* OpenGLX_Hook::_inst = nullptr;
|
||||
|
||||
bool OpenGLX_Hook::start_hook()
|
||||
{
|
||||
bool res = true;
|
||||
if (!hooked)
|
||||
{
|
||||
if (!X11_Hook::Inst()->start_hook())
|
||||
return false;
|
||||
|
||||
GLenum err = glewInit();
|
||||
|
||||
if (err == GLEW_OK)
|
||||
{
|
||||
PRINT_DEBUG("Hooked OpenGLX\n");
|
||||
|
||||
hooked = true;
|
||||
Renderer_Detector::Inst().renderer_found(this);
|
||||
|
||||
UnhookAll();
|
||||
BeginHook();
|
||||
HookFuncs(
|
||||
std::make_pair<void**, void*>(&(void*&)_glXSwapBuffers, (void*)&OpenGLX_Hook::MyglXSwapBuffers)
|
||||
);
|
||||
EndHook();
|
||||
|
||||
get_steam_client()->steam_overlay->HookReady();
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT_DEBUG("Failed to hook OpenGLX\n");
|
||||
/* Problem: glewInit failed, something is seriously wrong. */
|
||||
PRINT_DEBUG("Error: %s\n", glewGetErrorString(err));
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLX_Hook::resetRenderState()
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
//X11_Hook::Inst()->resetRenderState();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
||||
void OpenGLX_Hook::prepareForOverlay(Display* display)
|
||||
{
|
||||
PRINT_DEBUG("Called SwapBuffer hook");
|
||||
|
||||
if( ! initialized )
|
||||
{
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.IniFilename = NULL;
|
||||
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if( initialized )
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
GLint m_viewport[4];
|
||||
glGetIntegerv( GL_VIEWPORT, m_viewport );
|
||||
int width = m_viewport[2];
|
||||
int height = m_viewport[3];
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
X11_Hook::Inst()->prepareForOverlay(display);
|
||||
|
||||
ImGui::NewFrame();
|
||||
|
||||
get_steam_client()->steam_overlay->OverlayProc(width, height);
|
||||
|
||||
ImGui::EndFrame();
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLX_Hook::MyglXSwapBuffers(Display* display, GLXDrawable drawable)
|
||||
{
|
||||
OpenGLX_Hook::Inst()->prepareForOverlay(display);
|
||||
OpenGLX_Hook::Inst()->_glXSwapBuffers(display, drawable);
|
||||
}
|
||||
|
||||
OpenGLX_Hook::OpenGLX_Hook():
|
||||
initialized(false),
|
||||
hooked(false),
|
||||
_glXSwapBuffers(nullptr)
|
||||
{
|
||||
//_library = dlopen(DLL_NAME);
|
||||
}
|
||||
|
||||
OpenGLX_Hook::~OpenGLX_Hook()
|
||||
{
|
||||
PRINT_DEBUG("OpenGLX Hook removed\n");
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
//dlclose(_library);
|
||||
|
||||
_inst = nullptr;
|
||||
}
|
||||
|
||||
OpenGLX_Hook* OpenGLX_Hook::Inst()
|
||||
{
|
||||
if (_inst == nullptr)
|
||||
_inst = new OpenGLX_Hook;
|
||||
|
||||
return _inst;
|
||||
}
|
||||
|
||||
const char* OpenGLX_Hook::get_lib_name() const
|
||||
{
|
||||
return DLL_NAME;
|
||||
}
|
||||
|
||||
void OpenGLX_Hook::loadFunctions(decltype(glXSwapBuffers)* pfnglXSwapBuffers)
|
||||
{
|
||||
_glXSwapBuffers = pfnglXSwapBuffers;
|
||||
}
|
||||
|
||||
#endif//NO_OVERLAY
|
45
overlay_experimental/OpenGLX_Hook.h
Normal file
45
overlay_experimental/OpenGLX_Hook.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef __INCLUDED_OPENGLX_HOOK_H__
|
||||
#define __INCLUDED_OPENGLX_HOOK_H__
|
||||
|
||||
#include "Base_Hook.h"
|
||||
|
||||
#ifdef __LINUX__
|
||||
#ifndef NO_OVERLAY
|
||||
#include <GL/glew.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
class OpenGLX_Hook : public Base_Hook
|
||||
{
|
||||
public:
|
||||
static constexpr const char *DLL_NAME = "libGLX.so";
|
||||
|
||||
private:
|
||||
static OpenGLX_Hook* _inst;
|
||||
|
||||
// Variables
|
||||
bool hooked;
|
||||
bool initialized;
|
||||
|
||||
// Functions
|
||||
OpenGLX_Hook();
|
||||
|
||||
void resetRenderState();
|
||||
void prepareForOverlay(Display* display);
|
||||
|
||||
// Hook to render functions
|
||||
static void MyglXSwapBuffers(Display* display, GLXDrawable drawable);
|
||||
|
||||
decltype(glXSwapBuffers)* _glXSwapBuffers;
|
||||
|
||||
public:
|
||||
virtual ~OpenGLX_Hook();
|
||||
|
||||
bool start_hook();
|
||||
static OpenGLX_Hook* Inst();
|
||||
virtual const char* get_lib_name() const;
|
||||
void loadFunctions(decltype(glXSwapBuffers)* pfnglXSwapBuffers);
|
||||
};
|
||||
|
||||
#endif//NO_OVERLAY
|
||||
#endif//__LINUX__
|
||||
#endif//__INCLUDED_OPENGLX_HOOK_H__
|
214
overlay_experimental/X11_Hook.cpp
Normal file
214
overlay_experimental/X11_Hook.cpp
Normal file
|
@ -0,0 +1,214 @@
|
|||
#include "X11_Hook.h"
|
||||
#include "Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <imgui.h>
|
||||
#include <impls/imgui_impl_x11.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <fstream>
|
||||
|
||||
extern int ImGui_ImplX11_EventHandler(XEvent &event);
|
||||
|
||||
X11_Hook* X11_Hook::_inst = nullptr;
|
||||
|
||||
bool X11_Hook::start_hook()
|
||||
{
|
||||
bool res = true;
|
||||
if (!hooked)
|
||||
{
|
||||
res = false;
|
||||
std::ifstream flibrary("/proc/self/maps");
|
||||
std::string line;
|
||||
while( std::getline(flibrary, line) )
|
||||
{
|
||||
if( strcasestr(line.c_str(), DLL_NAME) != nullptr )
|
||||
{
|
||||
_library = dlopen(line.substr(line.find('/')).c_str(), RTLD_NOW);
|
||||
|
||||
if( _library != nullptr )
|
||||
{
|
||||
// Hook only this
|
||||
_XEventsQueued = (decltype(_XEventsQueued))dlsym(_library, "XEventsQueued");
|
||||
// Thoses are needed to ignore some events when overlay is on
|
||||
_XPeekEvent = (decltype(_XPeekEvent))dlsym(_library, "XPeekEvent");
|
||||
_XNextEvent = (decltype(_XNextEvent))dlsym(_library, "XNextEvent");
|
||||
_XKeysymToKeycode = (decltype(_XKeysymToKeycode))dlsym(_library, "XKeysymToKeycode");
|
||||
_XLookupKeysym = (decltype(_XLookupKeysym))dlsym(_library, "XLookupKeysym");
|
||||
|
||||
if( _XEventsQueued != nullptr && _XPeekEvent != nullptr
|
||||
&& _XNextEvent != nullptr && _XKeysymToKeycode != nullptr
|
||||
&& _XLookupKeysym != nullptr )
|
||||
{
|
||||
PRINT_DEBUG("Hooked X11\n");
|
||||
hooked = true;
|
||||
|
||||
BeginHook();
|
||||
HookFuncs(
|
||||
std::make_pair<void**, void*>(&(void*&)_XEventsQueued, (void*)&X11_Hook::MyXEventsQueued)
|
||||
);
|
||||
|
||||
EndHook();
|
||||
break;
|
||||
}
|
||||
dlclose(_library);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void X11_Hook::resetRenderState()
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
initialized = false;
|
||||
ImGui_ImplX11_Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void X11_Hook::prepareForOverlay(Display *display)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
ImGui_ImplX11_Init(display);
|
||||
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
io.KeyMap[ImGuiKey_Tab] = _XKeysymToKeycode(display, XK_Tab);
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = _XKeysymToKeycode(display, XK_Left);
|
||||
io.KeyMap[ImGuiKey_RightArrow] = _XKeysymToKeycode(display, XK_Right);
|
||||
io.KeyMap[ImGuiKey_UpArrow] = _XKeysymToKeycode(display, XK_Up);
|
||||
io.KeyMap[ImGuiKey_DownArrow] = _XKeysymToKeycode(display, XK_Down);
|
||||
io.KeyMap[ImGuiKey_PageUp] = _XKeysymToKeycode(display, XK_Prior);
|
||||
io.KeyMap[ImGuiKey_PageDown] = _XKeysymToKeycode(display, XK_Next);
|
||||
io.KeyMap[ImGuiKey_Home] = _XKeysymToKeycode(display, XK_Home);
|
||||
io.KeyMap[ImGuiKey_End] = _XKeysymToKeycode(display, XK_End);
|
||||
io.KeyMap[ImGuiKey_Insert] = _XKeysymToKeycode(display, XK_Insert);
|
||||
io.KeyMap[ImGuiKey_Delete] = _XKeysymToKeycode(display, XK_Delete);
|
||||
io.KeyMap[ImGuiKey_Backspace] = _XKeysymToKeycode(display, XK_BackSpace);
|
||||
io.KeyMap[ImGuiKey_Space] = _XKeysymToKeycode(display, XK_space);
|
||||
io.KeyMap[ImGuiKey_Enter] = _XKeysymToKeycode(display, XK_Return);
|
||||
io.KeyMap[ImGuiKey_Escape] = _XKeysymToKeycode(display, XK_Escape);
|
||||
io.KeyMap[ImGuiKey_A] = _XKeysymToKeycode(display, XK_A);
|
||||
io.KeyMap[ImGuiKey_C] = _XKeysymToKeycode(display, XK_C);
|
||||
io.KeyMap[ImGuiKey_V] = _XKeysymToKeycode(display, XK_V);
|
||||
io.KeyMap[ImGuiKey_X] = _XKeysymToKeycode(display, XK_X);
|
||||
io.KeyMap[ImGuiKey_Y] = _XKeysymToKeycode(display, XK_Y);
|
||||
io.KeyMap[ImGuiKey_Z] = _XKeysymToKeycode(display, XK_Z);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
ImGui_ImplX11_NewFrame();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// X11 window hooks
|
||||
bool IgnoreEvent(XEvent &event)
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
// Keyboard
|
||||
case KeyPress: case KeyRelease:
|
||||
// MouseButton
|
||||
case ButtonPress: case ButtonRelease:
|
||||
// Mouse move
|
||||
case MotionNotify: case ClientMessage:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int X11_Hook::MyXEventsQueued(Display *display, int mode)
|
||||
{
|
||||
static Time prev_time = {};
|
||||
X11_Hook* inst = X11_Hook::Inst();
|
||||
XEvent event = {};
|
||||
|
||||
int res = inst->_XEventsQueued(display, mode);
|
||||
|
||||
if( res > 0 )
|
||||
{
|
||||
/// The XPeekEvent function returns the first event from the event queue,
|
||||
/// but it does not remove the event from the queue. If the queue is
|
||||
/// empty, XPeekEvent flushes the output buffer and blocks until an event
|
||||
/// is received.
|
||||
inst->_XPeekEvent(display, &event);
|
||||
Steam_Overlay* overlay = get_steam_client()->steam_overlay;
|
||||
bool show = overlay->ShowOverlay();
|
||||
// Is the event is a key press
|
||||
if (event.type == KeyPress)
|
||||
{
|
||||
// Tab is pressed and was not pressed before
|
||||
if (event.xkey.keycode == inst->_XKeysymToKeycode(display, XK_Tab) && event.xkey.state & ShiftMask)
|
||||
{
|
||||
// if key TAB is help, don't make the overlay flicker :p
|
||||
if( event.xkey.time != prev_time)
|
||||
{
|
||||
overlay->ShowOverlay(!overlay->ShowOverlay());
|
||||
|
||||
if (overlay->ShowOverlay())
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(event.type == KeyRelease && event.xkey.keycode == inst->_XKeysymToKeycode(display, XK_Tab))
|
||||
{
|
||||
prev_time = event.xkey.time;
|
||||
}
|
||||
|
||||
if (show)
|
||||
{
|
||||
ImGui_ImplX11_EventHandler(event);
|
||||
|
||||
if (IgnoreEvent(event))
|
||||
{
|
||||
inst->_XNextEvent(display, &event);
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// XEventsQueued returns the num of events available.
|
||||
// Usually, games tend to read all events queued before calling again XEventsQueued
|
||||
// making us unavailable to intercept undesired events
|
||||
return res;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
X11_Hook::X11_Hook() :
|
||||
initialized(false),
|
||||
hooked(false)
|
||||
{
|
||||
//_library = dlopen(DLL_NAME, RTLD_NOW);
|
||||
}
|
||||
|
||||
X11_Hook::~X11_Hook()
|
||||
{
|
||||
PRINT_DEBUG("X11 Hook removed\n");
|
||||
|
||||
resetRenderState();
|
||||
|
||||
//dlclose(_library);
|
||||
|
||||
_inst = nullptr;
|
||||
}
|
||||
|
||||
X11_Hook* X11_Hook::Inst()
|
||||
{
|
||||
if (_inst == nullptr)
|
||||
_inst = new X11_Hook;
|
||||
|
||||
return _inst;
|
||||
}
|
||||
|
||||
const char* X11_Hook::get_lib_name() const
|
||||
{
|
||||
return DLL_NAME;
|
||||
}
|
||||
|
||||
#endif//NO_OVERLAY
|
50
overlay_experimental/X11_Hook.h
Normal file
50
overlay_experimental/X11_Hook.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef __INCLUDED_X11_HOOK_H__
|
||||
#define __INCLUDED_X11_HOOK_H__
|
||||
|
||||
#include "Base_Hook.h"
|
||||
|
||||
#ifdef __LINUX__
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <X11/X.h> // XEvent types
|
||||
#include <X11/Xlib.h> // XEvent structure
|
||||
|
||||
class X11_Hook : public Base_Hook
|
||||
{
|
||||
public:
|
||||
static constexpr const char* DLL_NAME = "libX11.so";
|
||||
|
||||
private:
|
||||
static X11_Hook* _inst;
|
||||
|
||||
// Variables
|
||||
bool hooked;
|
||||
bool initialized;
|
||||
|
||||
// Functions
|
||||
X11_Hook();
|
||||
|
||||
// Hook to X11 window messages
|
||||
static int MyXEventsQueued(Display * display, int mode);
|
||||
|
||||
decltype(XEventsQueued)* _XEventsQueued;
|
||||
|
||||
decltype(XPeekEvent)* _XPeekEvent;
|
||||
decltype(XNextEvent)* _XNextEvent;
|
||||
decltype(XKeysymToKeycode)* _XKeysymToKeycode;
|
||||
decltype(XLookupKeysym)* _XLookupKeysym;
|
||||
|
||||
public:
|
||||
virtual ~X11_Hook();
|
||||
|
||||
void resetRenderState();
|
||||
void prepareForOverlay(Display *display);
|
||||
|
||||
bool start_hook();
|
||||
static X11_Hook* Inst();
|
||||
virtual const char* get_lib_name() const;
|
||||
};
|
||||
|
||||
#endif//NO_OVERLAY
|
||||
#endif//__LINUX__
|
||||
#endif//__INCLUDED_X11_HOOK_H__
|
Loading…
Reference in a new issue