Updated Linux X11 & OLGX hooks.

Use LD_PRELOAD=$PWD/libsteam_api.so app_name to load overlay.
This commit is contained in:
Nemirtingas 2019-09-03 10:32:32 +02:00
parent d6f29ffffa
commit ecd753422b
5 changed files with 232 additions and 139 deletions

View file

@ -30,12 +30,14 @@ bool OpenGLX_Hook::start_hook()
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();
}
@ -55,7 +57,7 @@ void OpenGLX_Hook::resetRenderState()
if (initialized)
{
ImGui_ImplOpenGL3_Shutdown();
//X11_Hook::Inst()->resetRenderState();
X11_Hook::Inst()->resetRenderState();
ImGui::DestroyContext();
initialized = false;
@ -63,10 +65,13 @@ void OpenGLX_Hook::resetRenderState()
}
// 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)
void OpenGLX_Hook::prepareForOverlay(Display* display, GLXDrawable drawable)
{
PRINT_DEBUG("Called SwapBuffer hook");
if( (Window)drawable != X11_Hook::Inst()->get_game_wnd() )
resetRenderState();
if( ! initialized )
{
ImGui::CreateContext();
@ -81,17 +86,12 @@ void OpenGLX_Hook::prepareForOverlay(Display* display)
{
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);
X11_Hook::Inst()->prepareForOverlay(display, (Window)drawable);
ImGui::NewFrame();
get_steam_client()->steam_overlay->OverlayProc(width, height);
get_steam_client()->steam_overlay->OverlayProc(io.DisplaySize.x, io.DisplaySize.y);
ImGui::EndFrame();
@ -103,7 +103,7 @@ void OpenGLX_Hook::prepareForOverlay(Display* display)
void OpenGLX_Hook::MyglXSwapBuffers(Display* display, GLXDrawable drawable)
{
OpenGLX_Hook::Inst()->prepareForOverlay(display);
OpenGLX_Hook::Inst()->prepareForOverlay(display, drawable);
OpenGLX_Hook::Inst()->_glXSwapBuffers(display, drawable);
}

View file

@ -24,14 +24,16 @@ private:
OpenGLX_Hook();
void resetRenderState();
void prepareForOverlay(Display* display);
void prepareForOverlay(Display* display, GLXDrawable drawable);
// Hook to render functions
static void MyglXSwapBuffers(Display* display, GLXDrawable drawable);
decltype(glXSwapBuffers)* _glXSwapBuffers;
public:
static void MyglXSwapBuffers(Display* display, GLXDrawable drawable);
virtual ~OpenGLX_Hook();
bool start_hook();

View file

@ -21,44 +21,8 @@ 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);
}
}
}
PRINT_DEBUG("Hooked X11\n");
hooked = true;
}
return res;
}
@ -67,44 +31,24 @@ void X11_Hook::resetRenderState()
{
if (initialized)
{
game_wnd = 0;
initialized = false;
ImGui_ImplX11_Shutdown();
}
}
void X11_Hook::prepareForOverlay(Display *display)
void X11_Hook::prepareForOverlay(Display *display, Window wnd)
{
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);
game_wnd = wnd;
initialized = true;
}
ImGui_ImplX11_NewFrame();
ImGui_ImplX11_NewFrame((void*)wnd);
}
/////////////////////////////////////////////////////////////////////////////////////
@ -126,28 +70,28 @@ bool IgnoreEvent(XEvent &event)
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 )
if( res )
{
/// 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);
static Time prev_time = {};
XEvent event;
//inst->_XPeekEvent(display, &event);
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 (event.xkey.keycode == inst->_XKeysymToKeycode(display, XK_Tab) && event.xkey.state & ShiftMask)
if (event.xkey.keycode == XKeysymToKeycode(display, XK_Tab) && event.xkey.state & ShiftMask)
{
// if key TAB is help, don't make the overlay flicker :p
// if key TAB is held, don't make the overlay flicker :p
if( event.xkey.time != prev_time)
{
overlay->ShowOverlay(!overlay->ShowOverlay());
@ -157,7 +101,8 @@ int X11_Hook::MyXEventsQueued(Display *display, int mode)
}
}
}
else if(event.type == KeyRelease && event.xkey.keycode == inst->_XKeysymToKeycode(display, XK_Tab))
//else if(event.type == KeyRelease && event.xkey.keycode == inst->_XKeysymToKeycode(display, XK_Tab))
else if(event.type == KeyRelease && event.xkey.keycode == XKeysymToKeycode(display, XK_Tab))
{
prev_time = event.xkey.time;
}
@ -168,22 +113,61 @@ int X11_Hook::MyXEventsQueued(Display *display, int mode)
if (IgnoreEvent(event))
{
inst->_XNextEvent(display, &event);
res = 0;
//inst->_XNextEvent(display, &event);
XNextEvent(display, &event);
return 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;
}
int X11_Hook::MyXNextEvent(Display* display, XEvent *event)
{
return Inst()->_XNextEvent(display, event);
}
int X11_Hook::MyXPeekEvent(Display* display, XEvent *event)
{
return Inst()->_XPeekEvent(display, event);
}
int X11_Hook::MyXPending(Display* display)
{
int res = Inst()->_XPending(display);
if( res && get_steam_client()->steam_overlay->ShowOverlay() )
{
XEvent event;
//Inst()->_XPeekEvent(display, &event);
XPeekEvent(display, &event);
if( IgnoreEvent(event) )
{
ImGui_ImplX11_EventHandler(event);
//Inst()->_XNextEvent(display, &event);
XNextEvent(display, &event);
res = 0;
}
}
return res;
}
/////////////////////////////////////////////////////////////////////////////////////
X11_Hook::X11_Hook() :
initialized(false),
hooked(false)
hooked(false),
game_wnd(0),
_XEventsQueued(nullptr),
_XPeekEvent(nullptr),
_XNextEvent(nullptr),
_XPending(nullptr)
{
//_library = dlopen(DLL_NAME, RTLD_NOW);
}

View file

@ -20,29 +20,48 @@ private:
// Variables
bool hooked;
bool initialized;
Window game_wnd;
// 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;
decltype(XPending)* _XPending;
//decltype(XKeysymToKeycode)* _XKeysymToKeycode;
//decltype(XLookupKeysym)* _XLookupKeysym;
//decltype(XGetGeometry)* _XGetGeometry;
public:
static int MyXEventsQueued(Display * display, int mode);
static int MyXNextEvent(Display* display, XEvent *event);
static int MyXPeekEvent(Display* display, XEvent *event);
static int MyXPending(Display* display);
virtual ~X11_Hook();
void resetRenderState();
void prepareForOverlay(Display *display);
void prepareForOverlay(Display *display, Window wnd);
Window get_game_wnd() const{ return game_wnd; }
bool start_hook();
static X11_Hook* Inst();
virtual const char* get_lib_name() const;
inline decltype(XEventsQueued)* get_XEventsQueued() const { return _XEventsQueued; }
inline decltype(XPeekEvent)* get_XPeekEvent() const { return _XPeekEvent; }
inline decltype(XNextEvent)* get_XNextEvent() const { return _XNextEvent; }
inline decltype(XPending)* get_XPending() const { return _XPending; }
inline void loadXEventsQueued(decltype(XEventsQueued)* pfnXEventsQueued) { _XEventsQueued = pfnXEventsQueued; }
inline void loadXPeekEvent(decltype(XPeekEvent)* pfnXPeekEvent) { _XPeekEvent = pfnXPeekEvent; }
inline void loadXNextEvent(decltype(XNextEvent)* pfnXNextEvent) { _XNextEvent = pfnXNextEvent; }
inline void loadXPending(decltype(XPending)* pfnXPending) { _XPending = pfnXPending; }
};
#endif//NO_OVERLAY