
sh0ckfr/universal-dear-imgui-hook
Developer toolsA universal Dear ImGui hook for DirectX 12/11/10/9, OpenGL, and Vulkan. Compatible with Windows, Linux, and Steam Deck, featuring integrated MCP via a NamedPipe for game debugging and control.
Overview
A Dear ImGui overlay that draws your interface inside another application, whatever graphics API it uses, and lets an AI assistant such as Claude Code see and play the game through MCP over a local named pipe or Unix socket. The API is detected at runtime: build once, inject anywhere. Windows games running under Wine or Proton use the Windows DLL. - : the backend is picked from the first API that presents a frame. Inject before or after the game initializes its graphics. - : through MCP and a local named pipe (Windows) or Unix socket (Linux), an assistant such as Claude Code sees the game, writes to the player over it and presses its keys. - : INSERT, or L3 + R3 on a controller, opens the menu; F11 removes the overlay and unloads the DLL. The keys are settings in example/config.cpp. While the menu is open the game sees no keyboard, mouse or controller input (Windows), and an XInput controller navigates the menu.
README
Universal-Dear-ImGui-Hook
A Dear ImGui overlay that draws your interface inside another application, whatever graphics API it uses, and lets an AI assistant such as Claude Code see and play the game through MCP over a local named pipe or Unix socket. The API is detected at runtime: build once, inject anywhere.
| API | Windows (x86, x64) | Linux (x86-64, ARM64) |
|---|---|---|
| Direct3D 9, 9Ex | :white_check_mark: | NOT REQUIRED |
| Direct3D 10, 11, 12 | :white_check_mark: | NOT REQUIRED |
| Vulkan | :white_check_mark: | :white_check_mark: |
| OpenGL 3.0+ | :white_check_mark: (WGL) | :white_check_mark: (GLX, EGL) |
Windows games running under Wine or Proton use the Windows DLL.
Contents
- Features
- Quick start
- Usage: Windows, Linux, settings, your menu, as a library
- Remote control by an AI assistant
- API
- How it works
- Building
- Tests
- Contributing
- Limitations
- Support
Sections marked with ▶ unfold on click.
Features
- One library for every API: the backend is picked from the first API that presents a frame. Inject before or after the game initializes its graphics.
- Remote control by an AI assistant: through MCP and a local named pipe (Windows) or Unix socket (Linux), an assistant such as Claude Code sees the game, writes to the player over it and presses its keys.
- Menu input:
INSERT, or L3 + R3 on a controller, opens the menu;F11removes the overlay and unloads the DLL. The keys are settings inexample/config.cpp. While the menu is open the game sees no keyboard, mouse or controller input (Windows), and an XInput controller navigates the menu. - No crash from the overlay (Windows, MSVC builds): an exception in the overlay, from a renderer backend or the menu code, removes it instead of taking the game down; the menu key brings it back.
- Images and frame capture:
uih::CreateTexture()turns RGBA pixels into an image forImGui::Image(), anduih::CaptureFrame()copies what the game draws, without the overlay, on every backend. - Several windows: when the game presents to more than one window or swap chain, the overlay stays on one of them and follows the focus.
- Readable on any display: the interface follows the DPI of the game window, or a fixed scale, with correct colors on sRGB and floating-point back buffers.
- No injector needed: the DLL can be loaded as
dinput8.dll, and the Linux library withLD_PRELOAD. - No dependencies: Dear ImGui, MinHook and the Vulkan headers are vendored; the C and C++ runtimes are linked statically.
Quick start
1. Get the library. Prebuilt libraries are attached to each release, and every commit’s builds are kept as workflow artifacts. Pick the one that matches the game, not your machine:
| Game | File |
|---|---|
| Windows, 64-bit | Universal-ImGui-Hook-msvc-x64.dll |
| Windows, 32-bit | Universal-ImGui-Hook-msvc-Win32.dll |
| Linux, x86-64 or ARM64 | Universal-ImGui-Hook-linux-x86_64.so or -linux-aarch64.so (glibc 2.28 or later) |
2. Or build it. On Windows, open Universal-ImGui-Hook.sln in Visual Studio 2022 or newer and build Release|x64: the DLL is build/vs/x64/Release/Universal-ImGui-Hook.dll. On Linux:
sudo apt install cmake ninja-build g++ pkg-config libxcb1-dev
cmake --preset linux && cmake --build --preset linux
LD_PRELOAD=$PWD/build/linux/Universal-ImGui-Hook.so ./game
3. Make it yours. You only edit the example; the hook itself, in src/, needs no change:
| To change | Edit |
|---|---|
| The menu | example/menu.cpp, plain Dear ImGui code run every frame |
| Hotkeys, controller buttons, graphics API, interface scale | example/config.cpp |
| Remote control by an AI assistant, its pipe or socket name | example/config.cpp, see Remote control by an AI assistant |
| Fonts and style | a config.setup callback, run when the ImGui context is created, set next to config.render in example/dllmain.cpp (Windows) or example/preload.cpp (Linux) |
Usage
Windows
Inject Universal-ImGui-Hook.dll with any injector or LoadLibrary. An injected DLL is unloaded by F11; inject it again to bring the overlay back.
To load it without an injector, rename it to dinput8.dll and put it next to the game’s executable: it exports DirectInput8Create and forwards it to the system library, so any game that imports DirectInput 8 loads it. Under Wine or Proton, add WINEDLLOVERRIDES="dinput8=n,b" %command% to the launch options. Loaded this way the DLL stays in the game, which references it: F11 removes the overlay and INSERT brings it back.
Logs (config.debugLog) go to OutputDebugString: read them with DebugView. The example DLL writes them when the game runs with the environment variable UIH_DEBUG=1.
Linux
LD_PRELOAD=/path/to/Universal-ImGui-Hook.so ./game
For a Steam game, set the launch options to LD_PRELOAD=/path/to/Universal-ImGui-Hook.so %command%. UIH_DEBUG=1 prints the log on stderr. A preloaded library cannot leave the process: F11 removes the overlay and its hooks, and INSERT brings them back.
Settings
The settings of the example library are compiled into it: edit example/config.cpp, next to dllmain.cpp, and rebuild.
void ApplySettings(uih::Config& config) {
config.menuKey = VK_INSERT; // opens and closes the menu
config.unloadKey = VK_F11; // removes the overlay, unloads the DLL
config.menuButtons = uih::GamepadL3 | uih::GamepadR3; // controller buttons held together, 0 to disable
config.backend = uih::Backend::None; // graphics API to hook, None detects it
config.scale = 0.0f; // interface size, 0 follows the DPI
config.remoteControl = false; // remote control by an AI assistant
config.remotePipe = "universal-imgui-hook"; // name of its pipe (Windows) or socket (Linux)
}
Writing your menu
The interface lives in example/menu.cpp. DrawMenu() is called every frame between ImGui::NewFrame() and ImGui::Render(), so any Dear ImGui code works there. The entry points, example/dllmain.cpp on Windows and example/preload.cpp on Linux, apply the settings and start the hook:
uih::Config config;
ApplySettings(config); // example/config.cpp
config.render = DrawMenu; // every frame
config.setup = LoadFonts; // when the ImGui context is created: fonts, style
config.module = module; // Windows: DLL unloaded by unloadKey
uih::Start(config);
Images are created once from RGBA pixels and drawn like any ImGui texture:
static ImTextureData* logo = uih::CreateTexture(pixels, 64, 64);
ImGui::Image(logo->GetTexRef(), ImVec2(64, 64));
The example menu is a tour of the common widgets (buttons, combo and list boxes, inputs, sliders, colors, tabs, trees, tables, plots, popups, draw lists) with imgui.png shown under the slider, and its Menu bar opens Dear ImGui’s own demo window, which covers every function. example/image.cpp embeds the picture in the library and decodes it with stb_image.
Using the hook as a library
The repository is a CMake package; link uih::uih to get include/uih.h and Dear ImGui’s headers:
include(FetchContent)
FetchContent_Declare(uih GIT_REPOSITORY https://github.com/Sh0ckFR/Universal-Dear-ImGui-Hook.git GIT_TAG master)
FetchContent_MakeAvailable(uih)
target_link_libraries(my_overlay PRIVATE uih::uih)
tests/consumer/ is a complete example, built by the CI. On Linux, linking uih::uih into a shared library applies src/linux/exports.map, which only exports the hooked functions.
Remote control by an AI assistant
The library can let an AI assistant, such as Claude Code, see the game, write to the player over it and press its keys, through the Model Context Protocol (MCP) and a local named pipe on Windows, or a Unix socket on Linux. Every graphics API; on Linux, X11 and XWayland games.
flowchart LR
A["Assistant, such as Claude Code"] -- "MCP on stdin and stdout" --> B["remote/uih_mcp.py"]
B -- "local named pipe or Unix socket" --> C["The library in the game"]
1. Turn it on in example/config.cpp, then build the DLL or the .so:
config.remoteControl = true;
config.remotePipe = "universal-imgui-hook"; // \\.\pipe\universal-imgui-hook, or $XDG_RUNTIME_DIR/universal-imgui-hook on Linux
2. Load it into the game, with any injector, as dinput8.dll, or with the script, which needs Python 3.8 or newer and nothing else:
python remote/uih_mcp.py inject game.exe build/vs/x64/Release/Universal-ImGui-Hook.dll
On Linux, preload it: LD_PRELOAD=/path/to/Universal-ImGui-Hook.so ./game. The socket opens with the first frame of the overlay, in the process that draws it, not in the launch scripts that preload the library too.
3. Give the assistant the MCP server, once. With Claude Code:
claude mcp add game -- python C:/path/to/Universal-Dear-ImGui-Hook/remote/uih_mcp.py
On Linux, the same with python3 /path/to/Universal-Dear-ImGui-Hook/remote/uih_mcp.py. With another remotePipe, add --pipe after the script. Other MCP clients, such as Claude Desktop, take the same command in their configuration:
{
"mcpServers": {
"game": { "command": "python", "args": ["C:/path/to/Universal-Dear-ImGui-Hook/remote/uih_mcp.py"] }
}
}
4. Ask. Start a new session of the assistant, or run /mcp in Claude Code, and talk about the game:
- Look at the game and tell me what you see.
- Write “Well done!” in the game for 5 seconds.
- Walk right to the edge of the platform, then jump.
- Open the overlay menu and describe it.
The assistant gets these tools:
| Tool | Does |
|---|---|
screenshot |
The current frame, without the overlay, at most 1280 pixels wide or high by default |
show_text |
A message to the player at the top of the screen, drawn by the overlay, for 10 seconds by default |
press_key |
Holds keys for a duration, 150 ms by default; right+space holds them together |
game_info |
Graphics API, window size, keyboard focus, menu state |
API
Everything is in include/uih.h, namespace uih.
| Function | Description |
|---|---|
Start(config) |
Installs the hooks on a worker thread and returns. Safe from DllMain or a library constructor. |
Stop() |
Removes the overlay, releases the GPU resources on the rendering thread and removes the hooks. Blocks; not from DllMain or a hook. Start() can be called again afterwards. |
ActiveBackend(), BackendName(backend) |
API the overlay is drawn with, Backend::None until the first frame. |
IsMenuOpen(), SetMenuOpen(open) |
Menu state, also toggled by menuKey. |
CreateTexture(rgba, width, height) |
Image from RGBA pixels, uploaded by the active backend on the next frame and again after a backend switch. Any thread. Null once kMaxTextures (256) images exist. |
DestroyTexture(texture) |
Releases an image on the next frame. |
CaptureFrame(pixels, width, height, timeoutMs) |
Copies the next frame of the game, without the overlay, as RGBA pixels. Waits for that frame on any thread but the render callback’s; false on timeout, or with a back buffer of more than 10 bits per channel (HDR). |
How it works
Building
| Target | Output | CMake presets |
|---|---|---|
| Windows game, 64-bit | Universal-ImGui-Hook.dll |
msvc-x64, mingw-x64 |
| Windows game, 32-bit | Universal-ImGui-Hook.dll |
msvc-x86, mingw-x86 |
| Native Linux game | Universal-ImGui-Hook.so |
linux |
Each preset builds into build/.
Visual Studio 2022 or newer, with the “Desktop development with C++” workload. Pick one:
Universal-ImGui-Hook.slnbuilds the DLL anduih_hostwithout CMake, intobuild/vs///.- Open the folder: Visual Studio reads
CMakePresets.json. - Command line:
cmake --preset msvc-x64, thencmake --build --preset msvc-x64.
Tests
-DUIH_BUILD_TESTS=ON builds uih_host, which renders a solid color with one API and checks the overlay, and registers the scenarios with CTest:
cmake --preset msvc-x64 -DUIH_BUILD_TESTS=ON && cmake --build --preset msvc-x64
ctest --test-dir build/msvc-x64 -C Release
Some tests press real keys and move the mouse. They are skipped when the host window does not have the focus: leave the machine alone while they run. A test whose screen check fails saves the capture as build/tests/capture-*.bmp.
Contributing
- A new source file goes into
CMakeLists.txtand the matching project invs/. - A fix comes with a
uih_hostscenario that fails without it. - Run the CTest suite on Windows; the CI covers Linux.
Limitations
Windows
- HDR10 swap chains (PQ color space) show the overlay with wrong colors, and
CaptureFrame()only copies 8-bit and 10-bit back buffers: the floating-point ones of HDR output are not captured. - A Vulkan swap chain created before the hook has no overlay until the game recreates it: its presents report
VK_SUBOPTIMAL_KHR, which games answer by recreating it. - When the game, or another overlay, subclasses the window after the hook, the hook’s window procedure stays in its chain: the unload key leaves the DLL loaded, and injecting it again does not start it.
- Native ARM64 Windows games are not supported: MinHook only handles x86 and x64.
- Only Windows builds made with MSVC, the released ones, survive an exception in the overlay: MinGW-w64 has no structured exception handling, and Linux builds are not protected either.
- D3D9: after an exception in a draw callback (
ImDrawList::AddCallback), the state block of the Dear ImGui backend is never released, and the game cannot reset its device.
Linux
- Input is read from the X server: native Wayland windows get no menu input (run SDL games with
SDL_VIDEODRIVER=x11), and the game still receives the keyboard and the mouse while the menu is open. The mouse wheel and input methods are not handled. - 32-bit games, OpenGL ES, and games that link their GL or Vulkan loader statically are not supported.
- The remote control sends no keys to native Wayland games.
Credits
Built with Dear ImGui, MinHook, Vulkan-Headers and stb_image (the example’s picture).
| Who | What |
|---|---|
| Sh0ckFR, Revan600 | ImGui and input hooks |
| Rebzzel | Initial work on the kiero library (no longer used) |
| primemb | Bug fixes |
Support
This project is free and MIT-licensed. Building it from scratch represents roughly 83 days of senior C++ work, about €54,000 at French freelance rates: six graphics backends on two operating systems, input blocking, crash protection, frame capture and the remote control by an AI assistant, and about 130 test scenarios run on every commit, real games included. If it saved you time, consider sponsoring or starring the repository.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Install
This server does not publish a one-line install command.
Open the repository installation guide New to MCP? Start with the mcpskill.org guide →Configuration
{
"mcpServers": {
"game": { "command": "python", "args": ["C:/path/to/Universal-Dear-ImGui-Hook/remote/uih_mcp.py"] }
}
}