Dear ImGui Input Handling Integration: A Complete Technical Guide to Platform Backends

Dear ImGui collects raw keyboard, mouse, focus and text events through the ImGuiIO API, which platform backends populate via Add*Event functions before each NewFrame() call.

Dear ImGui input handling integration relies on a clear separation between the core library and platform-specific code. The ocornut/imgui repository implements this architecture through the ImGuiIO structure defined in imgui.h, which acts as a centralized input queue that backends fill with native windowing events every frame. Understanding this contract is essential for implementing custom backends or modifying existing ones like GLFW, Win32, or SDL.

The ImGuiIO Input Queue API

The heart of Dear ImGui input handling is the ImGuiIO structure, which exposes a set of "Add" functions that backends must call to forward platform events. These functions are defined in imgui.h and push data into internal queues consumed during NewFrame().

Core Input Functions

According to the source code in imgui.h, backends must populate the following event types:

  • AddKeyEvent / AddKeyAnalogEvent – Queue key-down/up states or analog values (gamepad triggers, joystick axes)
  • AddMousePosEvent – Queue mouse cursor position updates (pass -FLT_MAX to signal no mouse)
  • AddMouseButtonEvent – Queue mouse button state changes
  • AddMouseWheelEvent – Queue horizontal and vertical scroll deltas
  • AddFocusEvent – Queue application focus gain/loss events
  • AddInputCharacter / AddInputCharacterUTF16 / AddInputCharactersUTF8 – Queue Unicode text input for InputText() widgets

Internally, these calls populate fields within ImGuiIO:

ImWchar16   InputQueueSurrogate;                // Used only by AddInputCharacterUTF16()
ImVector<ImWchar> InputQueueCharacters;         // Holds characters consumed by InputText()

These queues are cleared automatically at the end of each frame, ensuring frame-accurate input that preserves event ordering.

Platform Backend Integration Pattern

All official backends in the ocornut/imgui repository follow an identical integration pattern. A backend must store a pointer to its data structure (e.g., ImGui_ImplGlfw_Data), install callbacks with the native windowing library, and forward events to ImGuiIO inside those callbacks.

GLFW Backend Example

In backends/imgui_impl_glfw.cpp, the character input callback demonstrates this pattern:

void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
{
    ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
    if (bd->PrevUserCallbackChar && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
        bd->PrevUserCallbackChar(window, c);               // Preserve user-provided callback

    ImGuiIO& io = ImGui::GetIO(bd->Context);
    io.AddInputCharacter(c);                               // Forward text input to Dear ImGui
}

Win32 Backend Example

Similarly, backends/imgui_impl_win32.cpp handles WM_CHAR messages:

case WM_CHAR:
    // 2019-05-11: Don't filter the value before forwarding
    io.AddInputCharacter((unsigned int)wParam);           // Forward text input
    break;

Both implementations also forward mouse movement (WM_MOUSEMOVE or glfwSetCursorPosCallback) and button events using the corresponding AddMousePosEvent and AddMouseButtonEvent functions.

Frame Input Processing Flow

Understanding the execution order is critical for correct Dear ImGui input handling integration:

  1. Platform callbacks fire when the operating system delivers events (window messages, GLFW callbacks, etc.)
  2. Each callback pushes data into ImGuiIO fields via the Add*Event functions
  3. The application calls ImGui::NewFrame(), which reads queued input, updates internal state, and clears the queues
  4. UI widgets like InputText() consume characters from InputQueueCharacters during the frame

This queue-based design guarantees reliable text entry, mouse dragging, and key repeat handling regardless of platform event timing.

Customizing and Extending Input

Injecting Synthetic Events

To programmatically inject input for automated testing or macros, call the Add*Event functions directly from your application code:

ImGuiIO& io = ImGui::GetIO();
io.AddInputCharacter('A');          // Adds 'A' to the next InputText widget
io.AddKeyEvent(ImGuiKey_Space, true);  // Simulates Space key press

Filtering Text Input

To filter or modify characters before they reach widgets, use the ImGuiInputTextFlags_CallbackCharFilter flag on InputText() and adjust EventChar within your callback function.

High-DPI and Multi-Monitor Support

For high-DPI setups, backends typically scale mouse coordinates before calling AddMousePosEvent. The Win32 and GLFW backends handle this by querying monitor DPI and applying scaling factors to raw cursor positions.

Complete Implementation Example

The following pattern shows a complete GLFW-based input pipeline:

// 1. Initialise ImGui and backend
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 150");

// 2. Main loop
while (!glfwWindowShouldClose(window))
{
    glfwPollEvents();                   // Triggers ImGui_ImplGlfw_* callbacks

    // 3. Start frame (processes queued input)
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();

    // 4. UI code consumes input automatically
    static char buf[128] = "";
    ImGui::InputText("Label", buf, IM_ARRAYSIZE(buf));

    // 5. Render
    ImGui::Render();
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
    glfwSwapBuffers(window);
}

Key Source Files

Summary

  • ImGuiIO is the central contract between Dear ImGui and platform backends, defined in imgui.h
  • Backends call AddKeyEvent, AddMousePosEvent, AddInputCharacter, and related functions to queue raw input
  • Input queues are cleared every frame during NewFrame(), ensuring frame-accurate event processing
  • Official backends in backends/imgui_impl_glfw.cpp and backends/imgui_impl_win32.cpp demonstrate the callback-to-queue pattern
  • Synthetic events can be injected directly via ImGuiIO for testing or automation

Frequently Asked Questions

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

Scale mouse coordinates before calling io.AddMousePosEvent(). The official GLFW and Win32 backends query monitor DPI settings and apply scaling factors to raw cursor positions, ensuring UI elements align correctly with the mouse cursor on high-DPI displays.

Can I inject synthetic input events for automated testing?

Yes. Obtain the ImGuiIO reference via ImGui::GetIO() and call any Add*Event function directly from your test code. For example, io.AddInputCharacter('A') queues a character for the next InputText widget, while io.AddKeyEvent(ImGuiKey_Enter, true) simulates a key press.

What is the correct order of operations for input handling?

Platform callbacks must fire before ImGui::NewFrame(). The typical sequence is: (1) Poll native events (glfwPollEvents, PeekMessage), (2) callbacks populate ImGuiIO queues, (3) call NewFrame() to process input, (4) render UI. Reversing steps 2 and 3 results in one-frame input latency.

How do I filter characters entering an InputText widget?

Use the ImGuiInputTextFlags_CallbackCharFilter flag when calling InputText(), then modify EventChar in your callback function. This intercepts characters after they enter InputQueueCharacters but before the widget consumes them, allowing you to block specific inputs or convert characters programmatically.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →