# ImGui Input Handling for Keyboard, Mouse, and Gamepad: Architecture and Implementation

> Learn ImGui input handling for keyboard, mouse, and gamepad. Discover how platform backends forward native OS events to the core ImGuiIO structure for seamless integration.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: internals
- Published: 2026-07-19

---

**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/main/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 where `0` = left, `1` = right, `2` = middle.
- **`AddMouseWheelEvent(wheel_x, wheel_y)`** – Submits horizontal and vertical scroll deltas.
- **`BackendFlags`** – Declares backend capabilities such as `ImGuiBackendFlags_HasMouseCursors` and `ImGuiBackendFlags_HasGamepad`.
- **`ConfigFlags`** – Enables navigation features via `ImGuiConfigFlags_NavEnableKeyboard` and `ImGuiConfigFlags_NavEnableGamepad`.

The implementation of these functions resides in [[`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/imgui_impl_win32.cpp))

The Win32 implementation processes `WM_*` messages and XInput gamepad state:

- **Keyboard**: Translates virtual-key codes (`VK_*`) to `ImGuiKey` values and calls `io.AddKeyEvent()`. Modifier keys use dedicated `ImGuiMod_*` constants.
- **Mouse**: Maps `WM_MOUSEMOVE` to `AddMousePosEvent()`, `WM_LBUTTONDOWN`/`WM_RBUTTONDOWN` to `AddMouseButtonEvent()`, and `WM_MOUSEWHEEL` to `AddMouseWheelEvent()`.
- **Gamepad**: Polls XInput devices and maps buttons to `ImGuiKey_Gamepad_*` via the `MAP_BUTTON` macro around line 369. Analog sticks use `AddKeyAnalogEvent()` with values derived from `XINPUT_GAMEPAD` thumbstick data.

### GLFW Backend ([`imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_glfw.cpp))

This cross-platform backend uses GLFW callbacks and polling functions:

- **Keyboard**: Queries `glfwGetKey()` for each relevant key and submits via `io.AddKeyEvent()`.
- **Mouse**: Retrieves cursor position via `glfwGetCursorPos()` for `AddMousePosEvent()` and button states via `glfwGetMouseButton()` for `AddMouseButtonEvent()`.
- **Gamepad**: Accesses joystick state through `glfwGetJoystickAxes()` and `glfwGetJoystickButtons()`, translating to analog events around line 912.

### SDL2 and SDL3 Backends ([`imgui_impl_sdl2.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_sdl2.cpp), [`imgui_impl_sdl3.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_sdl3.cpp))

Both SDL backends follow identical architectural patterns with API-specific implementations:

- **Keyboard**: Uses `SDL_GetKeyboardState()` to poll key states and `SDL_GetModState()` for modifiers (lines 371-374 in SDL3).
- **Mouse**: Processes `SDL_MOUSEMOTION` and `SDL_MOUSEBUTTONDOWN` events into corresponding `AddMouse*` calls.
- **Gamepad**: For SDL2, uses `SDL_GameControllerGetAxis()` and `SDL_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/main/imgui.cpp)](https://github.com/ocornut/imgui/blob/master/imgui.cpp) at lines 13948-13957:

```cpp
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:

```cpp
#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 `ImGuiIO` calls rather than the core library polling hardware directly.
- **Modern input submission** requires using `AddKeyEvent()`, `AddMousePosEvent()`, and `AddKeyAnalogEvent()` introduced in version 1.87; direct modification of `KeysDown[]` arrays is deprecated.
- **Navigation sources** are tracked separately via `g.NavInputSource` in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), automatically switching between `ImGuiInputSource_Keyboard`, `ImGuiInputSource_Gamepad`, and `ImGuiInputSource_Mouse` based on recent activity.
- **Backend implementations** in [`imgui_impl_win32.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_win32.cpp), [`imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_glfw.cpp), and [`imgui_impl_sdl2.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_sdl2.cpp) demonstrate 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`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) around lines 1908-1915.