Skip to main content

Input Routing Philosophy

Dear ImGui’s input system is designed around a crucial principle:
Always forward ALL input to Dear ImGui, then check if ImGui wants to use it before passing it to your application.
This allows Dear ImGui to:
  • Detect clicks in empty space to unfocus windows
  • Handle dragging that starts outside widgets
  • Properly manage focus and hover states
  • Provide smooth interaction behavior

The Want Capture Flags

After calling ImGui::NewFrame(), check these flags in ImGuiIO to determine input routing:

io.WantCaptureMouse

Set when Dear ImGui wants to use mouse input:
ImGuiIO& io = ImGui::GetIO();

void HandleMouseInput()
{
    // (1) ALWAYS forward mouse input to ImGui
    io.AddMousePosEvent(mouse_x, mouse_y);
    io.AddMouseButtonEvent(0, left_button_down);
    io.AddMouseWheelEvent(wheel_h, wheel_v);
    
    // (2) ONLY forward to your game if ImGui doesn't want it
    if (!io.WantCaptureMouse)
    {
        my_game->HandleMouseInput(mouse_x, mouse_y, left_button_down);
    }
}
When is it set?
  • Hovering over any Dear ImGui window
  • Clicking on any Dear ImGui widget
  • Dragging a slider, scrollbar, or window
  • Using mouse wheel over a Dear ImGui window
Don’t manually check if the mouse is over a window! Use io.WantCaptureMouse instead:
// WRONG - doesn't handle dragging, popups, etc.
if (!ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
    my_game->HandleMouse();

// CORRECT
if (!io.WantCaptureMouse)
    my_game->HandleMouse();

io.WantCaptureKeyboard

Set when Dear ImGui wants to use keyboard input:
void HandleKeyboardInput()
{
    ImGuiIO& io = ImGui::GetIO();
    
    // (1) ALWAYS forward keyboard input to ImGui
    io.AddKeyEvent(ImGuiKey_A, key_down);
    io.AddKeyEvent(ImGuiKey_Space, space_down);
    // ... etc
    
    // (2) ONLY forward to your game if ImGui doesn't want it
    if (!io.WantCaptureKeyboard)
    {
        my_game->HandleKeyboard(key_codes);
    }
}
When is it set?
  • An InputText widget has focus
  • Keyboard navigation is active (io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard)
  • A keyboard shortcut is being processed
Special case: Text input widgets release focus on the “KeyDown” event of Return, so the “KeyUp” event will have io.WantCaptureKeyboard == false. Track which keys were pressed while ImGui had focus if this matters to your application.

io.WantTextInput

Set when Dear ImGui expects text input (useful for on-screen keyboards):
if (io.WantTextInput)
{
    // Show on-screen keyboard (mobile, console)
    ShowVirtualKeyboard();
}
else
{
    HideVirtualKeyboard();
}
When is it set?
  • An InputText widget is active
  • An InputTextMultiline widget is active

Mouse Input

Mouse Position

// Update mouse position every frame
io.AddMousePosEvent(mouse_x, mouse_y);

// Mouse left the window/application
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);

Mouse Buttons

// Button 0 = Left, 1 = Right, 2 = Middle
io.AddMouseButtonEvent(0, button_down);  // Left button
io.AddMouseButtonEvent(1, button_down);  // Right button  
io.AddMouseButtonEvent(2, button_down);  // Middle button

Mouse Wheel

// Vertical scroll
io.AddMouseWheelEvent(0.0f, wheel_delta_y);

// Horizontal scroll
io.AddMouseWheelEvent(wheel_delta_x, 0.0f);

// Both
io.AddMouseWheelEvent(wheel_delta_x, wheel_delta_y);

Mouse Source (Optional)

// Specify input source (useful for multi-input devices)
io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);      // Regular mouse
io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); // Touch screen
io.AddMouseSourceEvent(ImGuiMouseSource_Pen);        // Stylus/pen

Reading Mouse State

ImGuiIO& io = ImGui::GetIO();

// Current mouse position
ImVec2 mouse_pos = io.MousePos;

// Mouse button states
bool left_down = io.MouseDown[0];
bool right_down = io.MouseDown[1];

// Mouse button clicks this frame
bool left_clicked = io.MouseClicked[0];

// Mouse button double-clicks
bool left_double_clicked = io.MouseDoubleClicked[0];

// Mouse wheel delta this frame
float wheel_y = io.MouseWheel;
float wheel_x = io.MouseWheelH;

// Mouse drag delta
ImVec2 drag_delta = io.MouseDelta;

Keyboard Input

Key Events (Modern API)

Dear ImGui uses a named key system:
// Send key press/release
io.AddKeyEvent(ImGuiKey_A, is_down);
io.AddKeyEvent(ImGuiKey_Space, is_down);
io.AddKeyEvent(ImGuiKey_Enter, is_down);
io.AddKeyEvent(ImGuiKey_Escape, is_down);
io.AddKeyEvent(ImGuiKey_Backspace, is_down);

// Arrow keys
io.AddKeyEvent(ImGuiKey_LeftArrow, is_down);
io.AddKeyEvent(ImGuiKey_RightArrow, is_down);
io.AddKeyEvent(ImGuiKey_UpArrow, is_down);
io.AddKeyEvent(ImGuiKey_DownArrow, is_down);

// Modifiers
io.AddKeyEvent(ImGuiMod_Ctrl, is_down);
io.AddKeyEvent(ImGuiMod_Shift, is_down);
io.AddKeyEvent(ImGuiMod_Alt, is_down);
io.AddKeyEvent(ImGuiMod_Super, is_down);  // Windows key, Command key

Character Input

For text input, send Unicode characters:
// Add a character to the input queue
io.AddInputCharacter('A');
io.AddInputCharacter(0x4E2D);  // Unicode character (中)

// UTF-16 surrogate pairs
io.AddInputCharacterUTF16(0xD83D);  // High surrogate
io.AddInputCharacterUTF16(0xDE00);  // Low surrogate
On Windows, use WM_CHAR messages. On other platforms, convert keyboard input to UTF-8/UTF-16 characters.

Reading Keyboard State

// Check if key is currently down
if (ImGui::IsKeyDown(ImGuiKey_Space))
    printf("Space is held\n");

// Check if key was pressed this frame
if (ImGui::IsKeyPressed(ImGuiKey_Enter))
    printf("Enter was pressed\n");

// Check if key was released this frame  
if (ImGui::IsKeyReleased(ImGuiKey_Escape))
    printf("Escape was released\n");

// Check key presses with repeat
if (ImGui::IsKeyPressed(ImGuiKey_Backspace, true))  // true = allow repeat
    printf("Backspace (with repeat)\n");

Keyboard Shortcuts

// Check for Ctrl+S
if (ImGui::IsKeyPressed(ImGuiKey_S) && io.KeyCtrl)
    SaveFile();

// Check for Ctrl+Shift+N
if (ImGui::IsKeyPressed(ImGuiKey_N) && io.KeyCtrl && io.KeyShift)
    NewFile();

// Using Shortcut() function (cleaner)
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_S))
    SaveFile();

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_N))
    NewFile();

Modifier Keys

ImGuiIO& io = ImGui::GetIO();

if (io.KeyCtrl)
    printf("Ctrl is held\n");

if (io.KeyShift)
    printf("Shift is held\n");

if (io.KeyAlt)
    printf("Alt is held\n");

if (io.KeySuper)
    printf("Super/Windows/Command key is held\n");

Gamepad Input

Enable gamepad navigation:
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;  // Set by backend

Gamepad Buttons

// D-Pad
io.AddKeyEvent(ImGuiKey_GamepadDpadUp, is_down);
io.AddKeyEvent(ImGuiKey_GamepadDpadDown, is_down);
io.AddKeyEvent(ImGuiKey_GamepadDpadLeft, is_down);
io.AddKeyEvent(ImGuiKey_GamepadDpadRight, is_down);

// Face buttons (Xbox layout: A, B, X, Y)
io.AddKeyEvent(ImGuiKey_GamepadFaceDown, is_down);   // A / Cross
io.AddKeyEvent(ImGuiKey_GamepadFaceRight, is_down);  // B / Circle
io.AddKeyEvent(ImGuiKey_GamepadFaceLeft, is_down);   // X / Square
io.AddKeyEvent(ImGuiKey_GamepadFaceUp, is_down);     // Y / Triangle

// Shoulder buttons
io.AddKeyEvent(ImGuiKey_GamepadL1, is_down);  // Left bumper
io.AddKeyEvent(ImGuiKey_GamepadR1, is_down);  // Right bumper

// Triggers (digital)
io.AddKeyEvent(ImGuiKey_GamepadL2, is_down);  // Left trigger
io.AddKeyEvent(ImGuiKey_GamepadR2, is_down);  // Right trigger

// Stick buttons
io.AddKeyEvent(ImGuiKey_GamepadL3, is_down);  // Left stick click
io.AddKeyEvent(ImGuiKey_GamepadR3, is_down);  // Right stick click

// System buttons
io.AddKeyEvent(ImGuiKey_GamepadStart, is_down);
io.AddKeyEvent(ImGuiKey_GamepadBack, is_down);

Gamepad Analog Inputs

// Left stick
io.AddKeyAnalogEvent(ImGuiKey_GamepadLStickLeft, left_x < 0, fabs(left_x));
io.AddKeyAnalogEvent(ImGuiKey_GamepadLStickRight, left_x > 0, fabs(left_x));
io.AddKeyAnalogEvent(ImGuiKey_GamepadLStickUp, left_y < 0, fabs(left_y));
io.AddKeyAnalogEvent(ImGuiKey_GamepadLStickDown, left_y > 0, fabs(left_y));

// Right stick  
io.AddKeyAnalogEvent(ImGuiKey_GamepadRStickLeft, right_x < 0, fabs(right_x));
io.AddKeyAnalogEvent(ImGuiKey_GamepadRStickRight, right_x > 0, fabs(right_x));
io.AddKeyAnalogEvent(ImGuiKey_GamepadRStickUp, right_y < 0, fabs(right_y));
io.AddKeyAnalogEvent(ImGuiKey_GamepadRStickDown, right_y > 0, fabs(right_y));

// Triggers (analog 0.0 to 1.0)
io.AddKeyAnalogEvent(ImGuiKey_GamepadL2, left_trigger > 0.1f, left_trigger);
io.AddKeyAnalogEvent(ImGuiKey_GamepadR2, right_trigger > 0.1f, right_trigger);
You’re responsible for applying dead zones and normalizing analog values. ImGui expects values in the range 0.0 to 1.0.

Focus and Hover Detection

Window Focus

if (ImGui::IsWindowFocused())
    printf("Current window is focused\n");

// Check if any ImGui window is focused
if (ImGui::IsWindowFocused(ImGuiHoveredFlags_AnyWindow))
    printf("Some ImGui window is focused\n");

// Check if current window or any child is focused
if (ImGui::IsWindowFocused(ImGuiHoveredFlags_ChildWindows))
    printf("This window or a child is focused\n");

Window Hover

if (ImGui::IsWindowHovered())
    printf("Mouse is over current window\n");

// Check if mouse is over any ImGui window
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
    printf("Mouse over some ImGui window\n");

// Include child windows
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows))
    printf("Mouse over this window or a child\n");

// Ignore popups blocking this window
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
    printf("Mouse over window (popup-aware)\n");

Item Hover and Focus

ImGui::Button("My Button");

if (ImGui::IsItemHovered())
    printf("Button is hovered\n");

if (ImGui::IsItemActive())
    printf("Button is being clicked\n");

if (ImGui::IsItemFocused())
    printf("Button has keyboard focus\n");

if (ImGui::IsItemClicked())
    printf("Button was clicked this frame\n");

if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
    printf("Button was right-clicked\n");

Custom Input Handling Example

Here’s a complete example of routing input:
class MyApplication
{
    ImGuiIO* io;
    
public:
    void ProcessInput()
    {
        // Update Dear ImGui input state
        UpdateMouseInput();
        UpdateKeyboardInput();
        UpdateGamepadInput();
        
        // Dear ImGui processes the input during NewFrame()
        ImGui::NewFrame();
        
        // Now check flags and route to application
        if (!io->WantCaptureMouse)
        {
            // Mouse is not over ImGui - handle game input
            if (IsMouseButtonDown(MOUSE_LEFT))
                FireWeapon();
            
            if (IsMouseButtonDown(MOUSE_RIGHT))
                Aim();
        }
        
        if (!io->WantCaptureKeyboard)
        {
            // Keyboard not captured - handle game input
            if (IsKeyDown(KEY_W)) MoveForward();
            if (IsKeyDown(KEY_S)) MoveBackward();
            if (IsKeyDown(KEY_A)) MoveLeft();
            if (IsKeyDown(KEY_D)) MoveRight();
        }
    }
    
    void UpdateMouseInput()
    {
        float mouse_x = GetMouseX();
        float mouse_y = GetMouseY();
        io->AddMousePosEvent(mouse_x, mouse_y);
        
        io->AddMouseButtonEvent(0, IsMouseButtonDown(MOUSE_LEFT));
        io->AddMouseButtonEvent(1, IsMouseButtonDown(MOUSE_RIGHT));
        io->AddMouseButtonEvent(2, IsMouseButtonDown(MOUSE_MIDDLE));
        
        float wheel = GetMouseWheel();
        if (wheel != 0.0f)
            io->AddMouseWheelEvent(0.0f, wheel);
    }
    
    void UpdateKeyboardInput()
    {
        // Update all keys that changed state
        for (int key = 0; key < 512; key++)
        {
            bool was_down = prev_keys[key];
            bool is_down = IsKeyDown(key);
            
            if (was_down != is_down)
            {
                ImGuiKey imgui_key = MapKeyToImGuiKey(key);
                if (imgui_key != ImGuiKey_None)
                    io->AddKeyEvent(imgui_key, is_down);
            }
            
            prev_keys[key] = is_down;
        }
        
        // Send character input
        while (char c = GetCharFromQueue())
            io->AddInputCharacter(c);
    }
};

IME (Input Method Editor) Support

For languages like Chinese, Japanese, Korean:
// Set IME callback
io.SetPlatformImeDataFn = MySetPlatformImeDataFn;

// Implement callback
void MySetPlatformImeDataFn(ImGuiViewport* viewport, ImGuiPlatformImeData* data)
{
    if (data->WantVisible)
    {
        // Position IME window at cursor
        SetIMEPosition(data->InputPos.x, data->InputPos.y);
    }
}

// Or use default implementation for Win32
io.GetMainViewport()->PlatformHandleRaw = hwnd;  // Set HWND
// Default implementation will position IME automatically

Touch Input

Touch input can be mapped to mouse input:
// Touch down = mouse button down + position
io.AddMousePosEvent(touch_x, touch_y);
io.AddMouseButtonEvent(0, true);

// Touch move = mouse position update
io.AddMousePosEvent(touch_x, touch_y);

// Touch up = mouse button up
io.AddMouseButtonEvent(0, false);

// Optionally specify it's touch input
io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
For better touch support:
// Increase touch padding for better hit detection
ImGuiStyle& style = ImGui::GetStyle();
style.TouchExtraPadding = ImVec2(4, 4);

Common Patterns

Pausing Game When UI is Active

if (io.WantCaptureMouse || io.WantCaptureKeyboard)
{
    // Pause game or reduce game input sensitivity
    game.paused = true;
}
else
{
    game.paused = false;
}

Global Shortcuts

// Always handle global shortcuts, even when ImGui wants keyboard
if (ImGui::IsKeyPressed(ImGuiKey_F1))
    show_help = !show_help;

if (ImGui::IsKeyPressed(ImGuiKey_F11))
    ToggleFullscreen();

// Only handle game shortcuts when ImGui doesn't want keyboard
if (!io.WantCaptureKeyboard)
{
    if (ImGui::IsKeyPressed(ImGuiKey_I))
        OpenInventory();
}

Mouse Delta for Camera

if (!io.WantCaptureMouse)
{
    // Use mouse delta for camera rotation
    camera_yaw += io.MouseDelta.x * sensitivity;
    camera_pitch += io.MouseDelta.y * sensitivity;
}

Next Steps

Build docs developers (and LLMs) love