The Problem
Streamers need a visual cue of what keys, mouse clicks, or gamepad actions they are performing. Without a live overlay, viewers cannot follow the interaction, which reduces engagement for tutorials, speed‑runs, or e‑sports broadcasts.
What This Does
The repository builds an OBS Studio plugin (C/C++ in client/src/) that captures keyboard, mouse and gamepad events via libuiohook, SDL3, and Mongoose. Captured data is emitted as JSON over a local WebSocket server (client/src/network_helper.cpp). A browser‑based overlay reads that stream with the JavaScript files under data/overlay_render/js/ (main.js, draw.js, gamepad.js, etc.) and renders the input on top of the video source. Configuration files (data/locale/*.ini and data/overlay_render/js/config.js) let users customise appearance and key mappings.
How It Is Wired
- Plugin start – The compiled shared library (built from
client/src/*.cppandclient/src/*.hpp) is loaded by OBS. The OBS entry point is defined in the plugin source (not listed explicitly, but typical OBS plugins exposeobs_module_load). - Input capture –
client/src/uiohook_helper.cppregisters callbacks with libuiohook for keyboard and mouse.client/src/gamepad_helper.cppopens SDL3 gamepad devices and polls them. Both helpers forward raw events toclient/src/io_client.cpp. - Event processing –
io_client.cppnormalises events, applies user‑defined filters (referenced fromclient/src/client_util.cpp), and pushes them into a thread‑safe queue. - Network export –
network_helper.cppruns a Mongoose WebSocket server (deps/mongoose/mongoose.c). It dequeues events, serialises them to JSON (usingdeps/json11/json11.cpp), and broadcasts to any connected browser. - Overlay rendering – The HTML page
data/overlay_render/renderer.htmlloadsdata/overlay_render/js/main.js. This script opens a WebSocket tows://localhost:<port>(port configured inconfig.js), receives JSON, and callsdraw.jsto update SVG/Canvas elements. No other modules import each other, so the internal import graph shows zero edges and zero cycles, confirming a flat dependency layout.
The widest blast‑radius files are network_helper.cpp (exposes the WebSocket API) and io_client.cpp (central event hub). Changes here affect all downstream rendering code.
How To Use It
# Clone and build
git clone https://github.com/moses-y/input-overlay
cd input-overlay
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . --config Release
Copy the produced plugin (libinput_overlay.so or input_overlay.dll) into OBS’s plugin directory (<obs‑install>/obs-plugins/64bit).
Configuration files live in data/overlay_render/js/ (config.js) and the locale INI files under data/locale/. Edit them before launching OBS.
In OBS, add a Browser source pointing at data/overlay_render/renderer.html (local file URL). The overlay will connect automatically to the native plugin’s WebSocket and start drawing input.
Real‑World Use
A streamer runs a competitive FPS, streams via OBS, and adds the browser source to the scene. While playing, every key press and mouse click appears as a translucent icon on the video, letting viewers see the exact timing of actions. The overlay can be toggled on/off in OBS without restarting the game.
Code Health & Issues
- High – Deep nesting – 34 files (e.g.,
client/src/network_helper.cpp,deps/json11/json11.cpp,deps/mongoose/mongoose.c) reach 8‑level indentation, making logic hard to follow. - High – Duplicated code – Repeated 6‑line blocks appear in 6+ files (
client_util.cpp,gamepad_helper.hpp,io_client.cpp). Consolidate into shared helpers. - High – Oversized files –
deps/mongoose/mongoose.c(≈3942 lines) and large SDL headers exceed 3000 lines; consider splitting or wrapping in smaller abstractions. - Medium – High branching density – 19 files contain >15 branch points per 52 lines, notably
io_client.cppandnetwork_helper.cpp. Refactor to reduce decision complexity.
Other hygiene: tests are present, CI runs via GitHub Actions, a LICENSE file exists, no Dockerfile or lockfile, and no secrets were detected.
The Bottom Line
The repo delivers a functional OBS overlay for visualising input, with a clear split between native capture (C/C++) and web‑based rendering (JS). Build steps are straightforward, but the codebase suffers from deep nesting, duplicated snippets, and very large third‑party files, which will increase maintenance effort. It is suitable for teams comfortable editing C++ and JavaScript and willing to address the identified code‑health issues.