# How Dear ImGui's Input System Works: Keyboard, Mouse, and Gamepad Handling

> Discover how Dear ImGui's input system handles keyboard, mouse, and gamepad events. Learn how ImGuiIO processes user input for seamless integration.

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

---

**Dear ImGui receives all user input through the `ImGuiIO` structure, where backends queue events via `Add*` functions and `ImGui::NewFrame()` processes them into state that widgets query each frame.**

The `ocornut/imgui` repository implements a minimal, platform-agnostic input system that unifies keyboard, mouse, and gamepad handling through a single event queue. This design allows the core library to remain OS-independent while backend implementations translate platform-specific windowing events into Dear ImGui's standard input format.

## The ImGuiIO Structure: Central Input Hub

All input configuration and state lives in the **`ImGuiIO`** structure defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 2425. This structure serves as the bridge between your application and Dear ImGui's internal systems.

Key input-related members include:

- **`MousePos`**, **`MouseDelta`**, **`MouseDown[5]`**, **`MouseWheel`** – Mouse state updated each frame
- **`KeysDown[]`** and **`KeysData[]`** – Keyboard key states indexed by `ImGuiKey` values
- **`NavInputs[]`** – Gamepad and navigation controller analog values
- **`KeyMap[]`** – Array mapping `ImGuiKey_*` identifiers to native key codes
- **`WantCaptureMouse`** / **`WantCaptureKeyboard`** – Flags indicating whether Dear ImGui consumed the input

The backend populates these fields indirectly by calling event addition functions, while the UI queries them directly through public API functions like `ImGui::IsKeyPressed()` and `ImGui::IsMouseClicked()`.

## Input Event Architecture

Dear ImGui uses a **queued event system** rather than immediate state modification. This ensures thread safety and consistent input handling across different backends.

### The Event Queue Flow

Input flows through three distinct stages:

1. **Platform Event Receipt** – The OS delivers raw input (Windows messages, GLFW callbacks, SDL events)
2. **Backend Translation** – Backend code calls `ImGuiIO` **Add* functions** to queue standardized events
3. **Frame Processing** – `ImGui::NewFrame()` (implemented in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) around line 4808) consumes the queue and updates the live state

The main **Add* functions** declared in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 2555 include:

- `AddMousePosEvent(float x, float y)`
- `AddMouseButtonEvent(int button, bool down)`
- `AddMouseWheelEvent(float wheel_x, float wheel_y)`
- `AddKeyEvent(ImGuiKey key, bool down)`
- `AddKeyAnalogEvent(ImGuiKey key, bool down, float v)` – Used for gamepad triggers and sticks
- `AddInputCharacter(unsigned int c)` – For text input

These implementations reside in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) around line 4626, where they push events into an internal ring buffer.

## Keyboard Input Handling

Keyboard handling relies on the **`ImGuiKey`** enum defined around line 3300 in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h), which provides logical identifiers for every key (e.g., `ImGuiKey_A`, `ImGuiKey_LeftArrow`, `ImGuiKey_LeftCtrl`).

### Key Mapping Configuration

Backends must populate the **`io.KeyMap[]`** array to translate native key codes into Dear ImGui's logical keys. For example, in [`imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_glfw.cpp):

```cpp
ImGuiIO& io = ImGui::GetIO();
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;

```

### Key State Updates

When a key event occurs, the backend calls **`io.AddKeyEvent()`**:

```cpp
// In imgui_impl_glfw.cpp key callback
io.AddKeyEvent(ImGuiKey_Escape, (action == GLFW_PRESS));

```

After `NewFrame()` processes the queue, you can query key states:

```cpp
if (ImGui::IsKeyDown(ImGuiKey_Escape))
    // Handle escape key held
if (ImGui::IsKeyPressed(ImGuiKey_Enter))
    // Handle enter key pressed (with repeat)

```

The **`KeysData[]`** array in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) (around line 2220) stores per-key timing information used by the repeat logic, controlled by `io.KeyRepeatDelay` and `io.KeyRepeatRate`.

## Mouse Input Handling

Mouse state accumulates through discrete events that `NewFrame()` reconciles into continuous state.

### Position and Delta

The **`AddMousePosEvent(float x, float y)`** function updates the internal queue. After processing, `io.MousePos` contains the latest coordinates, while `io.MouseDelta` contains the frame-to-frame movement delta.

### Button States

Mouse buttons use zero-based indexing: 0 (left), 1 (right), 2 (middle), 3 (extra1), 4 (extra2). Backends call:

```cpp
io.AddMouseButtonEvent(0, true);   // Left button pressed
io.AddMouseButtonEvent(0, false);  // Left button released

```

The resulting state resides in **`io.MouseDown[]`**, where `io.MouseDown[0]` indicates whether the left button is currently held.

### Scroll and Cursor

Wheel events feed into **`io.MouseWheel`** (vertical) and **`io.MouseWheelH`** (horizontal) via `AddMouseWheelEvent`. The **`io.MouseDrawCursor`** flag allows Dear ImGui to render its own cursor, while **`io.WantCaptureMouse`** tells the host application whether to hide the system cursor or pass events to underlying game logic.

## Gamepad Input Handling

Gamepad support integrates with the navigation system through analog-aware key events and dedicated navigation inputs.

### Gamepad Keys and Analog Input

Gamepad buttons and axes use the **`ImGuiKey_Gamepad_*`** enum values (defined around line 3325 in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)), such as `ImGuiKey_Gamepad_DpadLeft` or `ImGuiKey_Gamepad_FaceLeft`.

For analog triggers and sticks, backends use **`AddKeyAnalogEvent`**:

```cpp
// From imgui_impl_sdl2.cpp
io.AddKeyAnalogEvent(ImGuiKey_Gamepad_L2, (gamepad_axis_l2 > 0), gamepad_axis_l2);
io.AddKeyAnalogEvent(ImGuiKey_Gamepad_LStickLeft, (gamepad_axis_left_x < -0.1f), -gamepad_axis_left_x);

```

### Navigation Inputs

The **`io.NavInputs[]`** array (indexed by `ImGuiNavInput_*` enum values defined around line 3340) stores processed analog values for navigation-concerned inputs like `ImGuiNavInput_DpadLeft` or `ImGuiNavInput_LStickLeft`. The navigation system consumes these during `NewFrame()` to determine focus movement.

Enable gamepad navigation by setting:

```cpp
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;

```

## Backend Integration Examples

Dear ImGui provides reference implementations in the `backends/` directory demonstrating platform-specific integration.

### GLFW Backend

[`imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_glfw.cpp) (around line 150) demonstrates GLFW callback translation:

```cpp
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
    ImGuiIO& io = ImGui::GetIO();
    if (action == GLFW_PRESS)
        io.AddMouseButtonEvent(button, true);
    else if (action == GLFW_RELEASE)
        io.AddMouseButtonEvent(button, false);
}

```

### SDL2 Backend

[`imgui_impl_sdl2.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_sdl2.cpp) (around line 380) handles SDL events including gamepad connections:

```cpp
case SDL_MOUSEMOTION:
    io.AddMousePosEvent((float)event.motion.x, (float)event.motion.y);
    break;
case SDL_KEYDOWN:
    io.AddKeyEvent(ImGui_ImplSDL2_KeycodeToImGuiKey(event.key.keysym.sym), true);
    break;

```

### Win32 Backend

[`imgui_impl_win32.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_win32.cpp) (around line 210) processes Windows messages (`WM_KEYDOWN`, `WM_MOUSEMOVE`) and manages IME (Input Method Editor) state for international text input.

## Manual Input Implementation

If implementing a custom backend or bypassing existing ones, you can populate the input queue directly:

```cpp
ImGuiIO& io = ImGui::GetIO();

// Poll your OS or input library
while (PollNativeEvents())
{
    // Mouse position
    if (event.type == MOUSE_MOVE)
        io.AddMousePosEvent(event.x, event.y);
    
    // Mouse buttons
    if (event.type == MOUSE_BUTTON)
        io.AddMouseButtonEvent(event.button, event.pressed);
    
    // Keyboard
    if (event.type == KEY_DOWN)
        io.AddKeyEvent(TranslateToImGuiKey(event.key), true);
    if (event.type == KEY_UP)
        io.AddKeyEvent(TranslateToImGuiKey(event.key), false);
    
    // Text characters
    if (event.type == TEXT_INPUT)
        io.AddInputCharacter(event.unicode);
}

ImGui::NewFrame();  // Processes all queued events
// ... Draw UI widgets ...
ImGui::Render();

```

## Summary

- **Dear ImGui's input system** centers on the `ImGuiIO` structure, which acts as a broker between platform-specific backends and the UI framework.
- **Event queuing** via `AddMousePosEvent`, `AddKeyEvent`, and `AddKeyAnalogEvent` ensures thread-safe input collection before `NewFrame()` processing.
- **Backend responsibility** involves translating OS windowing events (GLFW, SDL2, Win32) into Dear ImGui's logical key and button identifiers.
- **Unified handling** treats keyboard, mouse, and gamepad input uniformly through the same `ImGuiKey` enum and navigation system.
- **Query API** functions like `IsKeyPressed()` and `IsMouseClicked()` read the processed state after `NewFrame()` updates the internal structures.

## Frequently Asked Questions

### How do I check if Dear ImGui wants to capture mouse input?

Check the **`io.WantCaptureMouse`** boolean after calling `ImGui::NewFrame()`. If this value is true, Dear ImGui is interacting with a widget (hovering, clicking, or dragging), and your underlying application should not process the mouse input. Similarly, **`io.WantCaptureKeyboard`** indicates when text input or navigation is active.

### Can I use Dear ImGui with a gamepad only, without a mouse?

Yes. Set **`io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad`** before `NewFrame()`. Your backend must populate gamepad events using `AddKeyEvent` and `AddKeyAnalogEvent` with `ImGuiKey_Gamepad_*` values. The navigation system will automatically map the D-pad and left stick to move focus between widgets, and face buttons to activate them.

### What is the difference between AddKeyEvent and the old KeysDown array?

Modern Dear ImGui versions use **`AddKeyEvent()`** to queue changes, which `NewFrame()` processes into the internal `KeysData[]` structure (defined in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)). While `io.KeysDown[]` still exists for legacy compatibility, the event-based API provides better support for key repeat handling, analog values, and thread safety. Backends migrating from direct array manipulation should switch to the `Add*` functions.

### How do I handle high-DPI mouse coordinates in Dear ImGui?

Always pass **physical pixel coordinates** (not logical display coordinates) to `AddMousePosEvent`. If your OS or windowing library scales coordinates for high-DPI displays, divide by the scale factor before calling Dear ImGui functions, or set **`io.DisplayFramebufferScale`** appropriately so that `MousePos` values match your actual render target resolution.