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

  1. Plugin start – The compiled shared library (built from client/src/*.cpp and client/src/*.hpp) is loaded by OBS. The OBS entry point is defined in the plugin source (not listed explicitly, but typical OBS plugins expose obs_module_load).
  2. Input captureclient/src/uiohook_helper.cpp registers callbacks with libuiohook for keyboard and mouse. client/src/gamepad_helper.cpp opens SDL3 gamepad devices and polls them. Both helpers forward raw events to client/src/io_client.cpp.
  3. Event processingio_client.cpp normalises events, applies user‑defined filters (referenced from client/src/client_util.cpp), and pushes them into a thread‑safe queue.
  4. Network exportnetwork_helper.cpp runs a Mongoose WebSocket server (deps/mongoose/mongoose.c). It dequeues events, serialises them to JSON (using deps/json11/json11.cpp), and broadcasts to any connected browser.
  5. Overlay rendering – The HTML page data/overlay_render/renderer.html loads data/overlay_render/js/main.js. This script opens a WebSocket to ws://localhost:<port> (port configured in config.js), receives JSON, and calls draw.js to 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 filesdeps/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.cpp and network_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.