ImGui Input Handling for Keyboard, Mouse, and Gamepad: Architecture and Implementation
ImGui does not poll hardware directly; instead, platform backends capture native OS events and forward them to the core library via the ImGuiIO structure using functions like AddKeyEvent(), AddMousePosEvent(), and AddKeyAnalogEvent().
The ocornut/imgui library implements a deliberate abstraction where input handling remains strictly separated from UI rendering. Rather than accessing hardware directly, the core library consumes standardized input events submitted through the ImGuiIO interface, allowing the same UI code to function across Win32, GLFW, SDL, and other platforms. This architecture ensures that keyboard, mouse, and gamepad inputs are processed uniformly regardless of the underlying operating system.
The ImGuiIO Data Structure and Event API
All input state flows through ImGuiIO, declared in [imgui.h](https://github.com/ocornut/imgui/blob/master/imgui.h). This structure stores configuration flags, timing data, and the current frame's input events. Since ImGui 1.87, the modern approach requires backends to use specific event submission functions rather than modifying internal arrays directly.
Key members and methods for input handling include:
AddKeyEvent(key, down)– Records digital button presses for keyboard keys (ImGuiKey_A,ImGuiKey_Space) and gamepad buttons (ImGuiKey_Gamepad_Start).AddKeyAnalogEvent(key, down, value)– Records analog inputs such as gamepad triggers and thumbsticks with float values between 0.0 and 1.0.AddMousePosEvent(x, y)– Updates cursor position in screen coordinates.AddMouseButtonEvent(button, down)– Updates mouse button state where0= left,1= right,2= middle.AddMouseWheelEvent(wheel_x, wheel_y)– Submits horizontal and vertical scroll deltas.BackendFlags– Declares backend capabilities such asImGuiBackendFlags_HasMouseCursorsandImGuiBackendFlags_HasGamepad.ConfigFlags– Enables navigation features viaImGuiConfigFlags_NavEnableKeyboardandImGuiConfigFlags_NavEnableGamepad.
The implementation of these functions resides in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) around lines 1908-1915, where events are pushed into internal circular buffers and modifier flags are automatically updated.
Platform Backend Implementation Patterns
Platform backends reside in the backends/ directory and serve as the translation layer between native OS events and ImGui's abstract input system. Each backend follows the same pattern: capture native events, translate them to ImGuiKey values, and submit via ImGuiIO methods.
Win32 Backend (imgui_impl_win32.cpp)
The Win32 implementation processes WM_* messages and XInput gamepad state:
- Keyboard: Translates virtual-key codes (
VK_*) toImGuiKeyvalues and callsio.AddKeyEvent(). Modifier keys use dedicatedImGuiMod_*constants. - Mouse: Maps
WM_MOUSEMOVEtoAddMousePosEvent(),WM_LBUTTONDOWN/WM_RBUTTONDOWNtoAddMouseButtonEvent(), andWM_MOUSEWHEELtoAddMouseWheelEvent(). - Gamepad: Polls XInput devices and maps buttons to
ImGuiKey_Gamepad_*via theMAP_BUTTONmacro around line 369. Analog sticks useAddKeyAnalogEvent()with values derived fromXINPUT_GAMEPADthumbstick data.
GLFW Backend (imgui_impl_glfw.cpp)
This cross-platform backend uses GLFW callbacks and polling functions:
- Keyboard: Queries
glfwGetKey()for each relevant key and submits viaio.AddKeyEvent(). - Mouse: Retrieves cursor position via
glfwGetCursorPos()forAddMousePosEvent()and button states viaglfwGetMouseButton()forAddMouseButtonEvent(). - Gamepad: Accesses joystick state through
glfwGetJoystickAxes()andglfwGetJoystickButtons(), translating to analog events around line 912.
SDL2 and SDL3 Backends (imgui_impl_sdl2.cpp, imgui_impl_sdl3.cpp)
Both SDL backends follow identical architectural patterns with API-specific implementations:
- Keyboard: Uses
SDL_GetKeyboardState()to poll key states andSDL_GetModState()for modifiers (lines 371-374 in SDL3). - Mouse: Processes
SDL_MOUSEMOTIONandSDL_MOUSEBUTTONDOWNevents into correspondingAddMouse*calls. - Gamepad: For SDL2, uses
SDL_GameControllerGetAxis()andSDL_GameControllerGetButton()(around line 461). SDL3 implements similar logic at line 757 using the updated controller API.
Navigation Source Selection
ImGui maintains an active navigation source that determines whether keyboard or gamepad input drives focus movement. The global state g.NavInputSource (an ImGuiInputSource enum) is updated in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) at lines 13948-13957:
if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad)
g.NavInputSource = ImGuiInputSource_Gamepad;
if (nav_keyboard_active && g.NavInputSource != ImGuiInputSource_Keyboard)
g.NavInputSource = ImGuiInputSource_Keyboard;
The navigation system checks ImGuiWindowFlags_NoNavInputs at line 13264 to disable navigation for specific windows. When ImGuiConfigFlags_NavEnableKeyboard or ImGuiConfigFlags_NavEnableGamepad are set in io.ConfigFlags, the corresponding input source becomes eligible for navigation control.
Practical Input Implementation Example
The following example demonstrates initializing ImGui with GLFW and manually injecting synthetic input events:
#include "imgui.h"
#include "backends/imgui_impl_glfw.h"
#include "backends/imgui_impl_opengl3.h"
#include <GLFW/glfw3.h>
int main()
{
// Initialize GLFW and ImGui context
glfwInit();
GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui Input Demo", nullptr, nullptr);
glfwMakeContextCurrent(window);
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 150");
while (!glfwWindowShouldClose(window))
{
// Poll native events (backend populates ImGuiIO internally)
glfwPollEvents();
ImGui_ImplGlfw_NewFrame();
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
// Inject synthetic keyboard input (Space key press)
io.AddKeyEvent(ImGuiKey_Space, true);
io.AddKeyEvent(ImGuiKey_Space, false);
// Inject mouse movement and left-click
io.AddMousePosEvent(400.0f, 300.0f);
io.AddMouseButtonEvent(0, true);
io.AddMouseButtonEvent(0, false);
// Inject gamepad analog input (left stick 75% left)
io.AddKeyAnalogEvent(ImGuiKey_Gamepad_LStickLeft, true, 0.75f);
// Build UI
ImGui::Begin("Input Test");
ImGui::Text("Input events processed from multiple sources");
ImGui::End();
// Render
ImGui::Render();
// ... OpenGL rendering code ...
glfwSwapBuffers(window);
}
// Cleanup omitted for brevity
return 0;
}
This example illustrates that while the GLFW backend automatically populates ImGuiIO from window events, applications can inject additional synthetic events programmatically using the public Add* API.
Summary
- ImGui uses a backend-driven architecture where platform code translates native events into standardized
ImGuiIOcalls rather than the core library polling hardware directly. - Modern input submission requires using
AddKeyEvent(),AddMousePosEvent(), andAddKeyAnalogEvent()introduced in version 1.87; direct modification ofKeysDown[]arrays is deprecated. - Navigation sources are tracked separately via
g.NavInputSourceinimgui.cpp, automatically switching betweenImGuiInputSource_Keyboard,ImGuiInputSource_Gamepad, andImGuiInputSource_Mousebased on recent activity. - Backend implementations in
imgui_impl_win32.cpp,imgui_impl_glfw.cpp, andimgui_impl_sdl2.cppdemonstrate consistent patterns for mapping platform-specific input to abstract ImGui keys.
Frequently Asked Questions
How does ImGui differentiate between keyboard and gamepad navigation?
ImGui tracks the most recently active navigation source in the g.NavInputSource variable according to the logic in imgui.cpp lines 13948-13957. When nav_gamepad_active detects analog stick or gamepad button input, the source switches to ImGuiInputSource_Gamepad; keyboard activity switches it to ImGuiInputSource_Keyboard. This determines which input method controls focus navigation during the current frame.
Can I use ImGui without a platform backend?
Yes, but you must implement the input translation yourself. Your application must call ImGuiIO methods like AddKeyEvent() and AddMousePosEvent() directly from your windowing system's event callbacks. The backend files (imgui_impl_*.cpp) serve as reference implementations for Win32, GLFW, SDL, and other platforms.
Why does my gamepad not work with ImGui?
Gamepad support requires three conditions: the backend must set ImGuiBackendFlags_HasGamepad in io.BackendFlags, you must enable ImGuiConfigFlags_NavEnableGamepad in io.ConfigFlags, and the backend must poll the gamepad hardware and call AddKeyEvent() or AddKeyAnalogEvent() for gamepad buttons and axes. Check your backend implementation (lines 369 in Win32, line 912 in GLFW, or line 461 in SDL2) to ensure gamepad polling is implemented.
What is the difference between AddKeyEvent and AddKeyAnalogEvent?
AddKeyEvent(ImGuiKey key, bool down) handles digital inputs where a key is either pressed or released, suitable for keyboard keys and gamepad face buttons. AddKeyAnalogEvent(ImGuiKey key, bool down, float value) handles analog inputs like gamepad triggers and thumbsticks, where value represents the analog magnitude (typically 0.0 to 1.0). Both functions are defined in imgui.cpp around lines 1908-1915.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →