mirror of
https://gitlab.com/Mr_Goldberg/goldberg_emulator.git
synced 2024-11-09 22:28:38 +01:00
Fix build
This commit is contained in:
parent
1785ae6eaf
commit
b9cd9ae6c2
26 changed files with 1544 additions and 109 deletions
302
ImGui/impls/linux/imgui_impl_x11.cpp
Normal file
302
ImGui/impls/linux/imgui_impl_x11.cpp
Normal file
|
@ -0,0 +1,302 @@
|
|||
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications)
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
|
||||
// Implemented features:
|
||||
// [?] Platform: Clipboard support
|
||||
// [?] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [?] Platform: Keyboard arrays indexed using
|
||||
// [?] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_x11.h"
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <GL/glew.h>
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2019-08-31: Initial X11 implementation
|
||||
|
||||
// X11 Data
|
||||
static Display* g_Display = nullptr;
|
||||
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||
static bool g_HasGamepad = false;
|
||||
static bool g_WantUpdateHasGamepad = true;
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplX11_Init(void *display)
|
||||
{
|
||||
//if (!::QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond))
|
||||
// return false;
|
||||
//if (!::QueryPerformanceCounter((LARGE_INTEGER *)&g_Time))
|
||||
// return false;
|
||||
|
||||
// Setup back-end capabilities flags
|
||||
g_Display = reinterpret_cast<Display*>(display);
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
io.BackendPlatformName = "imgui_impl_x11";
|
||||
io.ImeWindowHandle = nullptr;
|
||||
|
||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
|
||||
io.KeyMap[ImGuiKey_Tab] = -1;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = -1;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = -1;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = -1;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = -1;
|
||||
io.KeyMap[ImGuiKey_PageUp] = -1;
|
||||
io.KeyMap[ImGuiKey_PageDown] = -1;
|
||||
io.KeyMap[ImGuiKey_Home] = -1;
|
||||
io.KeyMap[ImGuiKey_End] = -1;
|
||||
io.KeyMap[ImGuiKey_Insert] = -1;
|
||||
io.KeyMap[ImGuiKey_Delete] = -1;
|
||||
io.KeyMap[ImGuiKey_Backspace] = -1;
|
||||
io.KeyMap[ImGuiKey_Space] = -1;
|
||||
io.KeyMap[ImGuiKey_Enter] = -1;
|
||||
io.KeyMap[ImGuiKey_Escape] = -1;
|
||||
io.KeyMap[ImGuiKey_A] = -1;
|
||||
io.KeyMap[ImGuiKey_C] = -1;
|
||||
io.KeyMap[ImGuiKey_V] = -1;
|
||||
io.KeyMap[ImGuiKey_X] = -1;
|
||||
io.KeyMap[ImGuiKey_Y] = -1;
|
||||
io.KeyMap[ImGuiKey_Z] = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplX11_Shutdown()
|
||||
{
|
||||
g_Display = nullptr;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplWin32_UpdateMouseCursor()
|
||||
{
|
||||
/*
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||
return false;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
::SetCursor(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
LPTSTR win32_cursor = IDC_ARROW;
|
||||
switch (imgui_cursor)
|
||||
{
|
||||
case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
|
||||
case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
|
||||
case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
|
||||
case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
|
||||
case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
|
||||
case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
|
||||
case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
|
||||
case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
|
||||
}
|
||||
::SetCursor(::LoadCursor(NULL, win32_cursor));
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_UpdateMousePos()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||
//if (io.WantSetMousePos)
|
||||
//{
|
||||
// POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
|
||||
// ::ClientToScreen(g_hWnd, &pos);
|
||||
// ::SetCursorPos(pos.x, pos.y);
|
||||
//}
|
||||
|
||||
// Set mouse position
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* TODO: support linux gamepad ?
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "xinput")
|
||||
#endif
|
||||
|
||||
// Gamepad navigation mapping
|
||||
static void ImGui_ImplWin32_UpdateGamepads()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||
return;
|
||||
|
||||
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
|
||||
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
|
||||
if (g_WantUpdateHasGamepad)
|
||||
{
|
||||
XINPUT_CAPABILITIES caps;
|
||||
g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS);
|
||||
g_WantUpdateHasGamepad = false;
|
||||
}
|
||||
|
||||
XINPUT_STATE xinput_state;
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
|
||||
{
|
||||
const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
|
||||
#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
|
||||
#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
||||
MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
|
||||
MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
|
||||
MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
|
||||
MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
|
||||
MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
|
||||
MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
|
||||
MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
|
||||
MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
|
||||
MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
||||
MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void ImGui_ImplX11_NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
Window rootWnd = DefaultRootWindow(g_Display);
|
||||
|
||||
// Todo: use X11 to get this value
|
||||
GLint m_viewport[4];
|
||||
glGetIntegerv( GL_VIEWPORT, m_viewport );
|
||||
io.DisplaySize.x = m_viewport[2];
|
||||
io.DisplaySize.y = m_viewport[3];
|
||||
|
||||
|
||||
/*
|
||||
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
|
||||
|
||||
// Setup time step
|
||||
INT64 current_time;
|
||||
::QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
|
||||
io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
|
||||
g_Time = current_time;
|
||||
|
||||
// Read keyboard modifiers inputs
|
||||
io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
|
||||
io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
|
||||
io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
|
||||
io.KeySuper = false;
|
||||
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
|
||||
|
||||
// Update OS mouse position
|
||||
ImGui_ImplWin32_UpdateMousePos();
|
||||
|
||||
// Update OS mouse cursor with the cursor requested by imgui
|
||||
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
|
||||
if (g_LastMouseCursor != mouse_cursor)
|
||||
{
|
||||
g_LastMouseCursor = mouse_cursor;
|
||||
ImGui_ImplWin32_UpdateMouseCursor();
|
||||
}
|
||||
*/
|
||||
|
||||
// Update game controllers (if enabled and available)
|
||||
//ImGui_ImplWin32_UpdateGamepads();
|
||||
}
|
||||
|
||||
// Process Win32 mouse/keyboard inputs.
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds.
|
||||
// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag.
|
||||
IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent &event)
|
||||
{
|
||||
if (ImGui::GetCurrentContext() == NULL)
|
||||
return 0;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
switch (event.type)
|
||||
{
|
||||
case ButtonPress:
|
||||
switch(event.xbutton.button )
|
||||
{
|
||||
case Button1: case Button2: case Button3:
|
||||
io.MouseDown[event.xbutton.button-1] = true;
|
||||
break;
|
||||
|
||||
case Button4: // Mouse wheel up
|
||||
event.xbutton.button = Button4;
|
||||
//io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
|
||||
return 0;
|
||||
|
||||
case Button5: // Mouse wheel down
|
||||
event.xbutton.button = Button5;
|
||||
//io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ButtonRelease:
|
||||
switch(event.xbutton.button )
|
||||
{
|
||||
case Button1: case Button2: case Button3:
|
||||
io.MouseDown[event.xbutton.button-1] = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
break;
|
||||
|
||||
case MotionNotify:
|
||||
io.MousePos.x = event.xmotion.x;
|
||||
io.MousePos.y = event.xmotion.y;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
if (wParam < 256)
|
||||
io.KeysDown[wParam] = 1;
|
||||
return 0;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
if (wParam < 256)
|
||||
io.KeysDown[wParam] = 0;
|
||||
return 0;
|
||||
case WM_CHAR:
|
||||
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
|
||||
io.AddInputCharacter((unsigned int)wParam);
|
||||
return 0;
|
||||
case WM_DEVICECHANGE:
|
||||
if ((UINT)wParam == DBT_DEVNODES_CHANGED)
|
||||
g_WantUpdateHasGamepad = true;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
21
ImGui/impls/linux/imgui_impl_x11.h
Normal file
21
ImGui/impls/linux/imgui_impl_x11.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications)
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui)
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
|
||||
#pragma once
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplX11_Init(void* display);
|
||||
IMGUI_IMPL_API void ImGui_ImplX11_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplX11_NewFrame();
|
||||
|
||||
// Handler for Win32 messages, update mouse/keyboard data.
|
||||
// You may or not need this for your implementation, but it can serve as reference for handling inputs.
|
||||
// Intentionally commented out to avoid dragging dependencies on <windows.h> types. You can COPY this line into your .cpp code instead.
|
||||
/*
|
||||
IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent *event);
|
||||
*/
|
|
@ -23,7 +23,7 @@
|
|||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2016-05-07: DirectX10: Disabling depth-write.
|
||||
|
||||
#include "../imgui.h"
|
||||
#include "../../imgui.h"
|
||||
#include "imgui_impl_dx10.h"
|
||||
|
||||
// DirectX
|
||||
|
@ -31,7 +31,7 @@
|
|||
#include <d3d10_1.h>
|
||||
#include <d3d10.h>
|
||||
|
||||
#include "../../overlay_experimental/ImGui_ShaderBlobs.h"
|
||||
#include "../../../overlay_experimental/windows/ImGui_ShaderBlobs.h"
|
||||
|
||||
#ifdef USE_D3DCOMPILE
|
||||
static ID3DBlob* g_pVertexShaderBlob = NULL;
|
||||
|
|
|
@ -23,14 +23,14 @@
|
|||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2016-05-07: DirectX11: Disabling depth-write.
|
||||
|
||||
#include "../imgui.h"
|
||||
#include "../../imgui.h"
|
||||
#include "imgui_impl_dx11.h"
|
||||
|
||||
// DirectX
|
||||
#include <stdio.h>
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "../../overlay_experimental/ImGui_ShaderBlobs.h"
|
||||
#include "../../../overlay_experimental/windows/ImGui_ShaderBlobs.h"
|
||||
|
||||
#ifdef USE_D3DCOMPILE
|
||||
static ID3DBlob* g_pVertexShaderBlob = NULL;
|
||||
|
|
|
@ -23,14 +23,14 @@
|
|||
// 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport).
|
||||
// 2018-02-22: Merged into master with all Win32 code synchronized to other examples.
|
||||
|
||||
#include "../imgui.h"
|
||||
#include "../../imgui.h"
|
||||
#include "imgui_impl_dx12.h"
|
||||
|
||||
// DirectX
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_4.h>
|
||||
|
||||
#include "../../overlay_experimental/ImGui_ShaderBlobs.h"
|
||||
#include "../../../overlay_experimental/windows/ImGui_ShaderBlobs.h"
|
||||
|
||||
#ifdef USE_D3DCOMPILE
|
||||
static ID3DBlob* g_pVertexShaderBlob = NULL;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
|
||||
#include "../imgui.h"
|
||||
#include "../../imgui.h"
|
||||
#include "imgui_impl_dx9.h"
|
||||
|
||||
// DirectX
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "../../imgui.h"
|
||||
#include "imgui_impl_win32.h"
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
|
|
@ -8,68 +8,20 @@
|
|||
|
||||
#include "../detours/detours.h"
|
||||
|
||||
void Base_Hook::BeginHook()
|
||||
{
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
}
|
||||
#define DETOUR_HOOKBEGIN DetourTransactionBegin
|
||||
#define DETOUR_UPDATETHREAD() DetourUpdateThread(GetCurrentThread())
|
||||
#define DETOUR_ENDHOOK DetourTransactionCommit
|
||||
#define DETOUR_HOOK DetourAttach
|
||||
#define DETOUR_UNHOOK DetourDetach
|
||||
|
||||
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())
|
||||
{
|
||||
BeginHook();
|
||||
std::for_each(_hooked_funcs.begin(), _hooked_funcs.end(), [](std::pair<void**, void*>& hook) {
|
||||
DetourDetach(hook.first, hook.second);
|
||||
});
|
||||
EndHook();
|
||||
_hooked_funcs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#elif defined(__LINUX__)
|
||||
#include "linux/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();
|
||||
}
|
||||
}
|
||||
#define DETOUR_HOOKBEGIN Linux_Detour::transaction_begin
|
||||
#define DETOUR_UPDATETHREAD() Linux_Detour::update_thread(pthread_self())
|
||||
#define DETOUR_ENDHOOK Linux_Detour::transaction_commit
|
||||
#define DETOUR_HOOK Linux_Detour::hook_func
|
||||
#define DETOUR_UNHOOK Linux_Detour::unhook_func
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -87,4 +39,34 @@ const char* Base_Hook::get_lib_name() const
|
|||
return "<no_name>";
|
||||
}
|
||||
|
||||
void Base_Hook::BeginHook()
|
||||
{
|
||||
DETOUR_HOOKBEGIN();
|
||||
DETOUR_UPDATETHREAD();
|
||||
}
|
||||
|
||||
void Base_Hook::EndHook()
|
||||
{
|
||||
DETOUR_ENDHOOK();
|
||||
}
|
||||
|
||||
void Base_Hook::HookFunc(std::pair<void**, void*> hook)
|
||||
{
|
||||
if( DETOUR_HOOK(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) {
|
||||
DETOUR_UNHOOK(hook.first, hook.second);
|
||||
});
|
||||
EndHook();
|
||||
_hooked_funcs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#endif//NO_OVERLAY
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
constexpr int max_hook_retries = 500;
|
||||
|
||||
#ifdef STEAM_WIN32
|
||||
#include "DX12_Hook.h"
|
||||
#include "DX11_Hook.h"
|
||||
#include "DX10_Hook.h"
|
||||
#include "DX9_Hook.h"
|
||||
#include "OpenGL_Hook.h"
|
||||
#include "Windows_Hook.h"
|
||||
#include "windows/DX12_Hook.h"
|
||||
#include "windows/DX11_Hook.h"
|
||||
#include "windows/DX10_Hook.h"
|
||||
#include "windows/DX9_Hook.h"
|
||||
#include "windows/OpenGL_Hook.h"
|
||||
#include "windows/Windows_Hook.h"
|
||||
|
||||
static decltype(&IDXGISwapChain::Present) _IDXGISwapChain_Present = nullptr;
|
||||
static decltype(&IDirect3DDevice9::Present) _IDirect3DDevice9_Present = nullptr;
|
||||
|
|
637
overlay_experimental/linux/Linux_Detour.cpp
Normal file
637
overlay_experimental/linux/Linux_Detour.cpp
Normal file
|
@ -0,0 +1,637 @@
|
|||
#include "Linux_Detour.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
|
||||
//------------------------------------------------------------------------------//
|
||||
// Helper funcs
|
||||
//------------------------------------------------------------------------------//
|
||||
constexpr static auto relative_jump_size = 5;
|
||||
constexpr static auto relative_addr_jump_size = sizeof(int32_t);
|
||||
constexpr static auto absolute_jump_size = 6;
|
||||
|
||||
struct
|
||||
{
|
||||
bool has_r_m;
|
||||
uint8_t base_size;
|
||||
} s_opcodes[256] =
|
||||
{
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 0 - 7
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 8 - 15
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 16 - 23
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 24 - 31
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 32 - 39
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 40 - 47
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 48 - 55
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 56 - 63
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 64 - 71
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 72 - 79
|
||||
// PUSH ...
|
||||
{false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, // 80 - 87
|
||||
// POP ...
|
||||
{false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, // 88 - 95
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 96 - 103
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 104 - 111
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 112 - 129
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 120 - 127
|
||||
// MOV, ADD, ... R8 <- IMM8 TEST_8 TEST XCHG_8 XCHG
|
||||
{true , 3}, {true , 6}, {true , 3}, {true , 3}, {true , 2}, {true , 2}, {true , 2}, {true , 2}, // 128 - 135
|
||||
// MOV_8 MOV MOV_R8_B MOV_R32_D MOV_32_ES LEA MOV_ES_32 POP
|
||||
{true , 2}, {true , 2}, {true , 2}, {true , 2}, {true , 2}, {true , 2}, {true , 2}, {false, 2}, // 136 - 143
|
||||
// NOP
|
||||
{false, 1}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 144 - 151
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 152 - 159
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 160 - 167
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 168 - 175
|
||||
// MOV_AL MOV_CL MOV_DL MOV_BL MOV_AH MOV_CH MOV_DH MOV_BH
|
||||
{false, 2}, {false, 2}, {false, 2}, {false, 2}, {false, 2}, {false, 2}, {false, 2}, {false, 2}, // 176 - 183
|
||||
// MOV_EAX MOV_ECX MOV_EDX MOV_EBX MOV_ESP MOV_EBP MOV_ESI MOV_EDI,
|
||||
{false, 5}, {false, 5}, {false, 5}, {false, 5}, {false, 5}, {false, 5}, {false, 5}, {false, 5}, // 184 - 191
|
||||
// RETN_IMM16 RETN
|
||||
{false, 0}, {false, 0}, {false, 3}, {false, 1}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 192 - 199
|
||||
// LEAVE RETF_IMM16 RETF INT INT_IMM8 INTO
|
||||
{false, 0}, {false, 1}, {false, 3}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 0}, // 200 - 207
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 208 - 215
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 216 - 223
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 224 - 231
|
||||
// CALL JMP LJMP SHORT_JMP
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 232 - 239
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 240 - 247
|
||||
// EXTENDED
|
||||
{false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 6}, // 248 - 255
|
||||
};
|
||||
|
||||
static constexpr auto mod_mask = 0xC0;
|
||||
static constexpr auto register_addressing_mode = 0xC0;
|
||||
static constexpr auto four_bytes_signed_displacement = 0x80;
|
||||
static constexpr auto one_byte_signed_displacement = 0x40;
|
||||
|
||||
static constexpr auto rm_mask = 0x05;
|
||||
static constexpr auto displacement_only_addressing = 0x05;
|
||||
static constexpr auto sib_with_no_displacement = 0x04;
|
||||
static constexpr auto register_indirect_addressing_mode = 0x00;
|
||||
|
||||
enum opcodes_e // Commonly used opcode in the beginning of functions
|
||||
{
|
||||
PUSH_EAX = 0x50, PUSH_ECX, PUSH_EDX, PUSH_EBX, PUSH_ESP, PUSH_EBP, PUSH_ESI, PUSH_EDI,
|
||||
POP_EAX , POP_ECX , POP_EDX , POP_EBX , POP_ESP , POP_EBP , POP_ESI , POP_EDI ,
|
||||
|
||||
R8_IMM8 = 0x80, R32_IMM32, R8_IMM8_2, R32_IMM8,
|
||||
TEST_8, TEST,
|
||||
XCHG_8, XCHG,
|
||||
MOV_8 , MOV,
|
||||
MOV_8_B, MOV_32_D, MOV_32_ES,
|
||||
LEA,
|
||||
MOV_ES_32, POP,
|
||||
NOP,
|
||||
MOV_AL = 0xB0, MOV_CL, MOV_DL, MOV_BL, MOV_AH, MOV_CH, MOV_DH, MOV_BH,
|
||||
MOV_EAX, MOV_ECX, MOV_EDX, MOV_EBX, MOV_ESP, MOV_EBP, MOV_ESI, MOV_EDI,
|
||||
RETN_IMM16 = 0xC2, RETN,
|
||||
LEAVE = 0xC9, RETF_IMM16, RETF, INT, INT_IMM8, INTO,
|
||||
CALL = 0xE8, // 5 bytes don't process
|
||||
JMP, // 5 bytes don't process
|
||||
LJMP, // 7 bytes, don't process
|
||||
SHORT_JMP, // 2 bytes don't process
|
||||
EXTENDED = 0xFF,
|
||||
};
|
||||
|
||||
const char* opcode_name(uint8_t opcode)
|
||||
{
|
||||
#define NAME(opcode_name) case opcode_name: return #opcode_name
|
||||
switch( opcode )
|
||||
{
|
||||
NAME(PUSH_EAX); NAME(PUSH_ECX); NAME(PUSH_EDX); NAME(PUSH_EBX);
|
||||
NAME(PUSH_ESP); NAME(PUSH_EBP); NAME(PUSH_ESI); NAME(PUSH_EDI);
|
||||
NAME(POP_EAX); NAME(POP_ECX); NAME(POP_EDX); NAME(POP_EBX);
|
||||
NAME(POP_ESP); NAME(POP_EBP); NAME(POP_ESI); NAME(POP_EDI);
|
||||
NAME(R8_IMM8); NAME(R32_IMM32); NAME(R8_IMM8_2); NAME(R32_IMM8);
|
||||
NAME(TEST_8); NAME(TEST); NAME(XCHG_8); NAME(XCHG); NAME(MOV_8); NAME(MOV);
|
||||
NAME(MOV_8_B); NAME(MOV_32_D); NAME(MOV_32_ES);
|
||||
NAME(LEA);
|
||||
NAME(MOV_ES_32); NAME(POP);
|
||||
NAME(NOP);
|
||||
NAME(MOV_AL) ; NAME(MOV_CL) ; NAME(MOV_DL) ; NAME(MOV_BL) ; NAME(MOV_AH) ; NAME(MOV_CH) ; NAME(MOV_DH) ; NAME(MOV_BH) ;
|
||||
NAME(MOV_EAX); NAME(MOV_ECX); NAME(MOV_EDX); NAME(MOV_EBX); NAME(MOV_ESP); NAME(MOV_EBP); NAME(MOV_ESI); NAME(MOV_EDI);
|
||||
NAME(RETN_IMM16); NAME(RETN); NAME(LEAVE); NAME(RETF_IMM16); NAME(RETF);
|
||||
NAME(INT); NAME(INT_IMM8); NAME(INTO); NAME(CALL); NAME(JMP); NAME(LJMP); NAME(SHORT_JMP);
|
||||
NAME(EXTENDED);
|
||||
}
|
||||
#undef NAME
|
||||
return "no registered";
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct trampoline_x86_t
|
||||
{
|
||||
uint8_t trampolineBytes[16+relative_jump_size]; // trampoline + original function opcodes
|
||||
uint8_t hookJump[relative_jump_size]; // jump to hook addr, needed because of relative jump overflow
|
||||
uint8_t nOriginalBytes; // number of original function bytes bkp
|
||||
uint8_t originalBytes[16]; // original function bytes
|
||||
};
|
||||
|
||||
typedef trampoline_x86_t trampoline_t;
|
||||
|
||||
struct trampoline_region_t
|
||||
{
|
||||
uint32_t header;
|
||||
uint8_t numTrampolines; // current trampolines allocated
|
||||
trampoline_t *trampolines_start; // start pointer of current region trampolines
|
||||
trampoline_t *next_free_trampoline; // next free trampoline in region
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct transaction_t
|
||||
{
|
||||
bool detach;
|
||||
void** ppOriginalFunc;
|
||||
trampoline_t *trampoline;
|
||||
};
|
||||
|
||||
static std::list<trampoline_region_t> trampoline_regions;
|
||||
|
||||
static bool transaction_started = false;
|
||||
static std::list<transaction_t> cur_transaction;
|
||||
|
||||
inline size_t page_size()
|
||||
{
|
||||
static size_t _page_size = sysconf(_SC_PAGESIZE);
|
||||
return _page_size;
|
||||
}
|
||||
|
||||
inline size_t region_size()
|
||||
{
|
||||
return page_size();
|
||||
}
|
||||
|
||||
static uint8_t max_trampolines_in_region = region_size() / sizeof(trampoline_t);
|
||||
|
||||
inline void* library_address_by_handle(void *library)
|
||||
{
|
||||
return (library == nullptr ? nullptr : *reinterpret_cast<void**>(library));
|
||||
}
|
||||
|
||||
inline size_t page_align(size_t size, size_t page_size)
|
||||
{
|
||||
return (size+(page_size-1)) & (((size_t)-1)^(page_size-1));
|
||||
}
|
||||
|
||||
inline void* page_addr(void* addr, size_t page_size)
|
||||
{
|
||||
return reinterpret_cast<void*>(reinterpret_cast<size_t>(addr) & (((size_t)-1)^(page_size-1)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
/// Tiny disasm
|
||||
|
||||
bool is_opcode_terminating_function(uint8_t* pCode)
|
||||
{
|
||||
switch( *pCode )
|
||||
{
|
||||
case LEAVE:
|
||||
case RETN: case RETN_IMM16:
|
||||
case RETF: case RETF_IMM16:
|
||||
case INT: case INT_IMM8: case INTO:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int find_space_for_trampoline(uint8_t* func, int bytes_needed)
|
||||
{
|
||||
if( func == nullptr )
|
||||
return -1;
|
||||
|
||||
int code_len = -1;
|
||||
bool search = true;
|
||||
uint8_t *startCode = reinterpret_cast<uint8_t*>(func);
|
||||
uint8_t *pCode = startCode;
|
||||
while( search ) // Find opcodes size and try to find at least 5 bytes for our JMP
|
||||
{
|
||||
if( is_opcode_terminating_function(pCode) )
|
||||
break;
|
||||
|
||||
if( s_opcodes[*pCode].has_r_m )
|
||||
{ // MOD-REG-R/M Byte
|
||||
// 7 6 5 4 3 2 1 0 - bits
|
||||
//[ MOD ][ REG ][ R/M ]
|
||||
switch( pCode[1] & mod_mask ) // Check MOD to know how many bytes we have after this opcode
|
||||
{
|
||||
case register_addressing_mode : pCode += s_opcodes[*pCode].base_size ; break;// register addressing mode [opcode] [R/M] [XX]
|
||||
case four_bytes_signed_displacement: pCode += s_opcodes[*pCode].base_size+5; break;// address mode byte + 4 bytes displacement
|
||||
case one_byte_signed_displacement : pCode += s_opcodes[*pCode].base_size+2; break;// address mode byte + 1 byte displacement
|
||||
case 0x00:
|
||||
switch( pCode[1] & rm_mask )
|
||||
{
|
||||
case sib_with_no_displacement : pCode += s_opcodes[*pCode].base_size+1; break;// SIB with no displacement
|
||||
case displacement_only_addressing : pCode += s_opcodes[*pCode].base_size+4; break;// 4 bytes Displacement only addressing mode
|
||||
case register_indirect_addressing_mode: pCode += s_opcodes[*pCode].base_size; // Register indirect addressing mode
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( s_opcodes[*pCode].base_size )
|
||||
{
|
||||
pCode += s_opcodes[*pCode].base_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( *pCode )
|
||||
{
|
||||
case CALL: case JMP: case LJMP: case SHORT_JMP:
|
||||
//std::cerr << "CALL and JMP are not supported for trampolines." << std::endl;
|
||||
search = false;
|
||||
break;
|
||||
|
||||
case EXTENDED:
|
||||
//std::cerr << "IMPORT_JUMP is not handled" << std::endl;
|
||||
if (pCode[1] == 0x25) // This is an imported function
|
||||
{ // Get the true function call
|
||||
//pCode = (uint8_t*)*(pCode+2);
|
||||
//startCode = pCode;
|
||||
// For now disable this case
|
||||
search = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
search = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//std::cerr << "opcode " << std::hex << (uint32_t)*pCode << " no registered" << std::endl;
|
||||
search = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( (pCode - startCode) >= bytes_needed && search )
|
||||
{
|
||||
search = false;
|
||||
code_len = pCode-startCode;
|
||||
}
|
||||
}
|
||||
return code_len;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Tiny asm
|
||||
|
||||
inline uint8_t* gen_immediate_addr(uint8_t* opcode_addr, uint8_t* dest)
|
||||
{
|
||||
*reinterpret_cast<int32_t*>(opcode_addr) = (dest - (opcode_addr + relative_addr_jump_size));
|
||||
return opcode_addr + relative_addr_jump_size;
|
||||
}
|
||||
|
||||
inline uint8_t* gen_immediate_jump(uint8_t* opcode_addr, uint8_t* dest)
|
||||
{
|
||||
*opcode_addr++ = JMP;
|
||||
return gen_immediate_addr(opcode_addr, dest);
|
||||
}
|
||||
|
||||
inline uint8_t* gen_immediate_call(uint8_t* opcode_addr, uint8_t* dest)
|
||||
{
|
||||
*opcode_addr++ = CALL;
|
||||
return gen_immediate_addr(opcode_addr, dest);
|
||||
}
|
||||
|
||||
uint8_t* relative_addr_to_absolute(int32_t rel_addr, uint8_t *code_addr)
|
||||
{
|
||||
return code_addr + rel_addr + relative_jump_size;
|
||||
}
|
||||
|
||||
void alloc_new_trampoline_region()
|
||||
{
|
||||
trampoline_region_t region;
|
||||
|
||||
region.numTrampolines = 0;
|
||||
// allocate new trampoline right in the middle of memory so relative jump can access any function
|
||||
region.trampolines_start = reinterpret_cast<trampoline_t*>(mmap((void*)std::numeric_limits<int32_t>::max(), // allocate the page near the half of memory addressing
|
||||
region_size(), // size
|
||||
PROT_EXEC|PROT_WRITE|PROT_READ, // protection
|
||||
MAP_PRIVATE|MAP_32BIT|MAP_ANONYMOUS, // don't map a file but memory
|
||||
-1, // fd = -1
|
||||
0) // offset
|
||||
);
|
||||
// Fill the region with 0
|
||||
std::fill(reinterpret_cast<uint8_t*>(region.trampolines_start), reinterpret_cast<uint8_t*>(region.trampolines_start)+region_size(), 0);
|
||||
region.next_free_trampoline = region.trampolines_start;
|
||||
// Protect trampoline region memory
|
||||
mprotect((void*)region.trampolines_start, region_size(), PROT_READ|PROT_EXEC);
|
||||
|
||||
trampoline_regions.push_back(region);
|
||||
}
|
||||
|
||||
trampoline_t* get_free_trampoline()
|
||||
{
|
||||
if (!transaction_started)
|
||||
return nullptr;
|
||||
|
||||
trampoline_t *res = nullptr;
|
||||
auto it = std::find_if(trampoline_regions.begin(), trampoline_regions.end(), [&res](trampoline_region_t ®ion){
|
||||
if( region.numTrampolines == max_trampolines_in_region )
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
if( it == trampoline_regions.end() )
|
||||
{
|
||||
alloc_new_trampoline_region();
|
||||
it = --trampoline_regions.end();
|
||||
}
|
||||
res = it->next_free_trampoline;
|
||||
|
||||
trampoline_t *next_new_trampoline = res+1;
|
||||
if( it->numTrampolines != max_trampolines_in_region )
|
||||
{
|
||||
while( next_new_trampoline->nOriginalBytes != 0 )
|
||||
{
|
||||
++next_new_trampoline;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
next_new_trampoline = nullptr;
|
||||
}
|
||||
it->next_free_trampoline = next_new_trampoline;
|
||||
|
||||
++it->numTrampolines;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void clear_trampoline(trampoline_region_t& region, trampoline_t *trampoline)
|
||||
{
|
||||
--region.numTrampolines;
|
||||
|
||||
std::fill(reinterpret_cast<uint8_t*>(trampoline), reinterpret_cast<uint8_t*>(trampoline+1), 0);
|
||||
if( region.next_free_trampoline == nullptr || region.next_free_trampoline > trampoline )
|
||||
region.next_free_trampoline = trampoline;
|
||||
}
|
||||
|
||||
inline bool is_page_inside_region(void *page, trampoline_region_t& region)
|
||||
{
|
||||
if( page >= region.trampolines_start && page <= (region.trampolines_start+region_size()) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------//
|
||||
|
||||
/*
|
||||
#include <signal.h>
|
||||
#include <dirent.h>
|
||||
|
||||
static pid_t tid = 0;
|
||||
|
||||
struct dism_pthread_t
|
||||
{
|
||||
uint32_t d0;
|
||||
uint32_t d4;
|
||||
uint32_t d8;
|
||||
uint32_t dc;
|
||||
uint32_t d10;
|
||||
uint32_t d14;
|
||||
uint32_t d18;
|
||||
uint32_t d1c;
|
||||
uint32_t d20;
|
||||
uint32_t d24;
|
||||
uint32_t d28;
|
||||
uint32_t d2c;
|
||||
uint32_t d30;
|
||||
uint32_t d34;
|
||||
uint32_t d38;
|
||||
uint32_t d3c;
|
||||
uint32_t d40;
|
||||
uint32_t d44;
|
||||
uint32_t d48;
|
||||
uint32_t d4c;
|
||||
uint32_t d50;
|
||||
uint32_t d54;
|
||||
uint32_t d58;
|
||||
uint32_t d5c;
|
||||
uint32_t d60;
|
||||
uint32_t d64;
|
||||
pid_t task_id;
|
||||
};
|
||||
*/
|
||||
|
||||
int Linux_Detour::update_thread(pthread_t thread_id)
|
||||
{
|
||||
//dism_pthread_t *dt = (dism_pthread_t*)thread_id;
|
||||
|
||||
// dt->task_id == syscall(SYS_gettid);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Linux_Detour::transaction_begin()
|
||||
{
|
||||
if( transaction_started )
|
||||
return -1;
|
||||
|
||||
transaction_started = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Linux_Detour::transaction_abort()
|
||||
{
|
||||
if(!transaction_started)
|
||||
return -1;
|
||||
|
||||
for( auto &i : cur_transaction )
|
||||
{
|
||||
trampoline_t *trampoline = i.trampoline;
|
||||
void *page_start = page_addr(reinterpret_cast<void*>(trampoline), page_size());
|
||||
auto it = std::find_if(trampoline_regions.begin(), trampoline_regions.end(), [page_start](trampoline_region_t ®ion){
|
||||
if( is_page_inside_region(page_start, region) )
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
if( it != trampoline_regions.end() )
|
||||
{
|
||||
clear_trampoline(*it, trampoline);
|
||||
}
|
||||
}
|
||||
cur_transaction.clear();
|
||||
transaction_started = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Linux_Detour::transaction_commit()
|
||||
{
|
||||
if (!transaction_started )
|
||||
return -1;
|
||||
|
||||
for( auto &i : cur_transaction)
|
||||
{
|
||||
trampoline_t *trampoline = i.trampoline;
|
||||
void **ppOriginalFunc = i.ppOriginalFunc;
|
||||
|
||||
int res;
|
||||
|
||||
if( i.detach )
|
||||
{
|
||||
void* trampoline_page = page_addr(reinterpret_cast<void*>(trampoline), page_size());
|
||||
|
||||
*ppOriginalFunc = (void*)(relative_addr_to_absolute(*reinterpret_cast<int32_t*>(trampoline->trampolineBytes+trampoline->nOriginalBytes+1),
|
||||
trampoline->trampolineBytes));
|
||||
|
||||
void* originalFunctionPage = page_addr(*ppOriginalFunc, page_size());
|
||||
|
||||
// Allow write on the original func
|
||||
res = mprotect(originalFunctionPage, page_size()*2, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
|
||||
// Write the original opcodes
|
||||
std::copy(trampoline->originalBytes, trampoline->originalBytes+trampoline->nOriginalBytes,
|
||||
reinterpret_cast<uint8_t*>(*ppOriginalFunc));
|
||||
|
||||
// Remove write permission
|
||||
res = mprotect(originalFunctionPage, page_size()*2, PROT_READ|PROT_EXEC);
|
||||
|
||||
// Allow write on trampoline page
|
||||
res = mprotect(trampoline_page, page_size()*2, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
|
||||
clear_trampoline(*reinterpret_cast<trampoline_region_t*>(trampoline_page), trampoline);
|
||||
|
||||
// Remove write permission
|
||||
res = mprotect(trampoline_page, page_size()*2, PROT_READ|PROT_EXEC);
|
||||
}
|
||||
else
|
||||
{
|
||||
void* originalFunctionPage = page_addr(*ppOriginalFunc, page_size());
|
||||
|
||||
// Allow write on the original func
|
||||
res = mprotect(originalFunctionPage, page_size()*2, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
|
||||
// Write the jump to trampoline
|
||||
gen_immediate_jump(reinterpret_cast<uint8_t*>(*ppOriginalFunc), trampoline->hookJump);
|
||||
|
||||
// Remove write permission
|
||||
res = mprotect(originalFunctionPage, page_size()*2, PROT_READ|PROT_EXEC);
|
||||
|
||||
*ppOriginalFunc = (void*)(trampoline->trampolineBytes);
|
||||
}
|
||||
}
|
||||
cur_transaction.clear();
|
||||
transaction_started = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Linux_Detour::unhook_func(void** ppOriginalFunc, void* _hook)
|
||||
{
|
||||
if( !transaction_started )
|
||||
return -EPERM;
|
||||
|
||||
if( ppOriginalFunc == nullptr || _hook == nullptr || *ppOriginalFunc == nullptr )
|
||||
return -EINVAL;
|
||||
|
||||
trampoline_t *trampoline = reinterpret_cast<trampoline_t*>(*ppOriginalFunc);
|
||||
void *page_start = page_addr(reinterpret_cast<void*>(trampoline), page_size());
|
||||
auto it = std::find_if(trampoline_regions.begin(), trampoline_regions.end(), [page_start](trampoline_region_t ®ion){
|
||||
if( is_page_inside_region(page_start, region) )
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
if( it != trampoline_regions.end() )
|
||||
{
|
||||
cur_transaction.push_back({true, ppOriginalFunc, trampoline});
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int Linux_Detour::hook_func(void** ppOriginalFunc, void* _hook)
|
||||
{
|
||||
if( !transaction_started )
|
||||
return -EPERM;
|
||||
|
||||
if( ppOriginalFunc == nullptr || _hook == nullptr || *ppOriginalFunc == nullptr )
|
||||
return -EINVAL;
|
||||
|
||||
uint8_t* hook = reinterpret_cast<uint8_t*>(_hook);
|
||||
uint8_t* pOriginalFunc = reinterpret_cast<uint8_t*>(*ppOriginalFunc);
|
||||
int code_len = find_space_for_trampoline(pOriginalFunc, relative_jump_size);
|
||||
|
||||
if( code_len < relative_jump_size )
|
||||
return -ENOSPC;
|
||||
|
||||
// Allocate the trampoline, try to put it right in the middle of the mem, so a relative jump can access any function in the app (+/-2GB)
|
||||
//
|
||||
// Our hook is a 5 bytes JMP (1 bytes for opcode, 4 for RELATIVE jump)
|
||||
// /!\ TODO: Add checks on JMP overflow
|
||||
|
||||
trampoline_t *trampoline = get_free_trampoline();
|
||||
uint8_t *pTrampolineCode = trampoline->trampolineBytes;
|
||||
|
||||
void* trampoline_page = page_addr(reinterpret_cast<void*>(trampoline), page_size());
|
||||
|
||||
// Enable write to the trampoline region
|
||||
mprotect(trampoline_page, page_size()*2, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
// Create relative jmp to hook
|
||||
gen_immediate_jump(trampoline->hookJump, hook);
|
||||
// Copy original opcodes
|
||||
trampoline->nOriginalBytes = code_len;
|
||||
std::copy((uint8_t*)pOriginalFunc, ((uint8_t*)pOriginalFunc)+code_len, trampoline->originalBytes);
|
||||
std::copy((uint8_t*)pOriginalFunc, ((uint8_t*)pOriginalFunc)+code_len, pTrampolineCode);
|
||||
pTrampolineCode += code_len;
|
||||
// Create the relative jmp to original (function + backed up opcodes)
|
||||
pTrampolineCode = gen_immediate_jump(pTrampolineCode, pOriginalFunc+code_len);
|
||||
pTrampolineCode += relative_addr_jump_size;
|
||||
|
||||
// Disable trampoline region write
|
||||
mprotect(trampoline_page, page_size()*2, PROT_READ|PROT_EXEC);
|
||||
|
||||
cur_transaction.push_back({false, ppOriginalFunc, trampoline});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------ DOCUMENTATION ------
|
||||
http://www.c-jump.com/CIS77/CPU/x86/lecture.html <- some help to understand [MOD][REG][R/M] (see paragraph #6)
|
||||
http://shell-storm.org/online/Online-Assembler-and-Disassembler <- online assembler
|
||||
http://ref.x86asm.net/coder32.html <- opcodes reference
|
||||
|
||||
X86
|
||||
|
||||
push ebx : 0x53
|
||||
sub esp ?? : 0x83 0xEC 0x??
|
||||
call ????????: 0xE8 0x?? 0x?? 0x?? 0x??
|
||||
|
||||
|
||||
// relative jmp: ???????? = dst_addr - curr_addr - 5
|
||||
jmp ???????? : 0xe9 0x?? 0x?? 0x?? 0x??
|
||||
destination = 0x8dba8
|
||||
jmp location: 0x91995 - opcodes: e9 0e c2 ff ff
|
||||
0e c2 ff ff = 0x8dba8 - 0x91995 - 5
|
||||
|
||||
// short jmp: ?? = dst_addr - curr_addr - 2
|
||||
jmp short ??: 0xeb 0x??
|
||||
destination = 0x91964
|
||||
jmp location: 0x9198f - opcodes: 0xeb 0xd3
|
||||
d3 = 0x91964 - 0x9198f - 2
|
||||
|
||||
X64
|
||||
|
||||
TODO:
|
||||
Hint: make relative jump to near (+/-2Gb) code : 5 bytes
|
||||
load absolute addr into R11 and call a jmp on register R11 : 13 bytes
|
||||
Or
|
||||
Reuse x86 relative jmp method
|
||||
|
||||
Example:
|
||||
mov r11, 0x0123456789abcdef -> 0x49 0xbb 0xef 0xcd 0xab 0x89 0x67 0x45 0x23 0x01
|
||||
jmp r11 -> 0x41 0xff 0xe3
|
||||
|
||||
|
||||
*/
|
32
overlay_experimental/linux/Linux_Detour.h
Normal file
32
overlay_experimental/linux/Linux_Detour.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef LINUX_DETOUR_H
|
||||
#define LINUX_DETOUR_H
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <thread>
|
||||
|
||||
class Linux_Detour
|
||||
{
|
||||
public:
|
||||
static int update_thread(pthread_t thread_id);
|
||||
static int transaction_begin();
|
||||
static int transaction_abort();
|
||||
static int transaction_commit();
|
||||
static int hook_func(void** ppOriginalFunc, void* _hook);
|
||||
static int unhook_func(void** ppOriginalFunc, void* _hook);
|
||||
|
||||
private:
|
||||
static int hook_func_abs(void** ppOriginalFunc, void* _hook);
|
||||
static int hook_func_rel(void** ppOriginalFunc, void* _hook);
|
||||
|
||||
Linux_Detour() = delete;
|
||||
Linux_Detour(Linux_Detour const&) = delete;
|
||||
Linux_Detour(Linux_Detour &&) = delete;
|
||||
Linux_Detour& operator=(Linux_Detour const&) = delete;
|
||||
Linux_Detour& operator=(Linux_Detour &&) = delete;
|
||||
};
|
||||
|
||||
extern "C" void *elf_hook(char const *library_filename, void const *library_address, char const *function_name, void const *substitution_address);
|
||||
|
||||
#endif // LINUX_DETOUR_H
|
152
overlay_experimental/linux/OpenGLX_Hook.cpp
Normal file
152
overlay_experimental/linux/OpenGLX_Hook.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
#include "OpenGLX_Hook.h"
|
||||
#include "X11_Hook.h"
|
||||
#include "../Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
|
||||
#ifdef __LINUX__
|
||||
#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
|
||||
#endif//__LINUX__
|
45
overlay_experimental/linux/OpenGLX_Hook.h
Normal file
45
overlay_experimental/linux/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__
|
216
overlay_experimental/linux/X11_Hook.cpp
Normal file
216
overlay_experimental/linux/X11_Hook.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
#include "X11_Hook.h"
|
||||
#include "../Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
|
||||
#ifdef __LINUX__
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <imgui.h>
|
||||
#include <impls/linux/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:
|
||||
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
|
||||
#endif//#__LINUX__
|
50
overlay_experimental/linux/X11_Hook.h
Normal file
50
overlay_experimental/linux/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__
|
|
@ -1,12 +1,12 @@
|
|||
#include "DX10_Hook.h"
|
||||
#include "Windows_Hook.h"
|
||||
#include "Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
#include "../Renderer_Detector.h"
|
||||
#include "../../dll/dll.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <imgui.h>
|
||||
#include <impls/imgui_impl_dx10.h>
|
||||
#include <impls/windows/imgui_impl_dx10.h>
|
||||
|
||||
DX10_Hook* DX10_Hook::_inst = nullptr;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __INCLUDED_DX10_HOOK_H__
|
||||
#define __INCLUDED_DX10_HOOK_H__
|
||||
|
||||
#include "Base_Hook.h"
|
||||
#include "../Base_Hook.h"
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <d3d10.h>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include "DX11_Hook.h"
|
||||
#include "Windows_Hook.h"
|
||||
#include "Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
#include "../Renderer_Detector.h"
|
||||
#include "../../dll/dll.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <imgui.h>
|
||||
#include <impls/imgui_impl_dx11.h>
|
||||
#include <impls/windows/imgui_impl_dx11.h>
|
||||
|
||||
DX11_Hook* DX11_Hook::_inst = nullptr;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __INCLUDED_DX11_HOOK_H__
|
||||
#define __INCLUDED_DX11_HOOK_H__
|
||||
|
||||
#include "Base_Hook.h"
|
||||
#include "../Base_Hook.h"
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <d3d11.h>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include "DX12_Hook.h"
|
||||
#include "Windows_Hook.h"
|
||||
#include "Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
#include "../Renderer_Detector.h"
|
||||
#include "../../dll/dll.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <imgui.h>
|
||||
#include <impls/imgui_impl_dx12.h>
|
||||
#include <impls/windows/imgui_impl_dx12.h>
|
||||
|
||||
#include <dxgi1_4.h>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __INCLUDED_DX12_HOOK_H__
|
||||
#define __INCLUDED_DX12_HOOK_H__
|
||||
|
||||
#include "Base_Hook.h"
|
||||
#include "../Base_Hook.h"
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <d3d12.h>
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
#include "DX9_Hook.h"
|
||||
#include "Windows_Hook.h"
|
||||
#include "Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
#include "../Renderer_Detector.h"
|
||||
#include "../../dll/dll.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <imgui.h>
|
||||
#include <impls/imgui_impl_dx9.h>
|
||||
|
||||
#include "steam_overlay.h"
|
||||
#include <impls/windows/imgui_impl_dx9.h>
|
||||
|
||||
DX9_Hook* DX9_Hook::_inst = nullptr;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __INCLUDED_DX9_HOOK_H__
|
||||
#define __INCLUDED_DX9_HOOK_H__
|
||||
|
||||
#include "Base_Hook.h"
|
||||
#include "../Base_Hook.h"
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <d3d9.h>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "OpenGL_Hook.h"
|
||||
#include "Windows_Hook.h"
|
||||
#include "Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
#include "../Renderer_Detector.h"
|
||||
#include "../../dll/dll.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include "steam_overlay.h"
|
||||
#include "../steam_overlay.h"
|
||||
|
||||
OpenGL_Hook* OpenGL_Hook::_inst = nullptr;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __INCLUDED_OPENGL_HOOK_H__
|
||||
#define __INCLUDED_OPENGL_HOOK_H__
|
||||
|
||||
#include "Base_Hook.h"
|
||||
#include "../Base_Hook.h"
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
class OpenGL_Hook : public Base_Hook
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include "Windows_Hook.h"
|
||||
#include "Renderer_Detector.h"
|
||||
#include "../dll/dll.h"
|
||||
#include "../Renderer_Detector.h"
|
||||
#include "../../dll/dll.h"
|
||||
|
||||
#ifndef NO_OVERLAY
|
||||
|
||||
#include <imgui.h>
|
||||
#include <impls/imgui_impl_win32.h>
|
||||
#include <impls/windows/imgui_impl_win32.h>
|
||||
|
||||
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
|
|
Loading…
Reference in a new issue