How to Handle WantCaptureMouse and WantCaptureKeyboard for Input Dispatching in Dear ImGui

Query io.WantCaptureMouse and io.WantCaptureKeyboard after ImGui::NewFrame() to decide whether your application should process mouse and keyboard events, always forwarding raw input to ImGui first.

Dear ImGui (ocornut/imgui) provides the global ImGuiIO structure to communicate input capture intent between the UI library and your application. The WantCaptureMouse and WantCaptureKeyboard boolean flags indicate whether ImGui intends to consume the next frame's mouse or keyboard events. Understanding how to read these flags—and why you must always feed events to ImGui before checking them—is critical for preventing input conflicts between your UI and game logic.

Understanding the Capture Flags in ImGuiIO

The authoritative source for input routing decisions resides in the ImGuiIO structure defined in imgui.h. Each frame during ImGui::NewFrame(), ImGui updates these read-only flags based on the current UI state:

  • io.WantCaptureMouse – Set to true when ImGui requires mouse input, such as when a window is hovered, a widget is active, or a mouse click originated inside an ImGui window.
  • io.WantCaptureKeyboard – Set to true when ImGui requires keyboard input, such as when a text widget is active (InputText), a shortcut is being processed, or navigation is active.

These flags are read-only for the application. You must query them after calling ImGui::NewFrame() but before processing the same events in your own logic.

Implementing the Input Dispatch Loop

The correct pattern requires always forwarding raw platform events to ImGui first, then conditionally handling them in your application based on the capture flags.

// 1. Start the frame (updates WantCapture* flags)
ImGui_ImplXXX_NewFrame();
ImGui::NewFrame();

// 2. Build your UI
ImGui::Begin("Game Editor");
ImGui::Text("Frame time: %.3f ms", deltaTime);
ImGui::End();

// 3. Render
ImGui::Render();
ImGui_ImplXXX_RenderDrawData(ImGui::GetDrawData());

// 4. Query IO for capture state
ImGuiIO& io = ImGui::GetIO();
if (!io.WantCaptureMouse) {
    // Process mouse for game (camera rotation, picking, etc.)
}
if (!io.WantCaptureKeyboard) {
    // Process keyboard for game (movement, actions, etc.)
}

Platform Event Integration Example

In your platform-specific event loop, call the backend's event processor before checking the flags. Here is an SDL2 implementation referencing backends/imgui_impl_sdl2.h:

SDL_Event event;
while (SDL_PollEvent(&event)) {
    // Always forward to ImGui first
    ImGui_ImplSDL2_ProcessEvent(&event);
    
    ImGuiIO& io = ImGui::GetIO();
    
    // Application processing only if ImGui doesn't want it
    if (!io.WantCaptureMouse && event.type == SDL_MOUSEMOTION) {
        RotateCamera(event.motion.xrel, event.motion.yrel);
    }
    if (!io.WantCaptureKeyboard && event.type == SDL_KEYDOWN) {
        if (event.key.keysym.sym == SDLK_SPACE)
            PlayerJump();
    }
    
    if (event.type == SDL_QUIT)
        running = false;
}

Overriding Capture Behavior

Occasionally, you must force ImGui to capture or release input for the next frame, such as when opening a custom OS dialog or when implementing a global shortcut that should override the UI.

ImGui provides explicit setters in the public API (imgui.h):

ImGui::SetNextFrameWantCaptureMouse(bool want_capture);      // Sets io.WantCaptureMouse for next frame
ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture);   // Sets io.WantCaptureKeyboard for next frame

These functions write to internal override members (WantCaptureMouseNextFrame, WantCaptureKeyboardNextFrame) declared in imgui_internal.h, which are examined at the start of the subsequent NewFrame() call.

// Force ImGui to ignore mouse input next frame
if (show_native_file_dialog) {
    ImGui::SetNextFrameWantCaptureMouse(false);
    ImGui::SetNextFrameWantCaptureKeyboard(false);
}

Common Pitfalls and Special Cases

Do Not Use IsWindowHovered for Routing

ImGui::IsWindowHovered() and related widget-specific queries answer UI-specific questions (e.g., "is this particular window hovered"). They must never be used for generic input dispatch decisions because they ignore popups, modal windows, and the broader capture semantics. According to the Dear ImGui source code and FAQ, only io.WantCaptureMouse and io.WantCaptureKeyboard provide the authoritative signal for input routing.

Handling Popup Close Clicks

When a popup is open, ImGui sets an additional flag: io.WantCaptureMouseUnlessPopupClose. If both WantCaptureMouse and WantCaptureMouseUnlessPopupClose are true, your application should ignore mouse input unless the click would close the popup (typically a click outside the popup bounds).

Multiple Backends

When using multiple input sources (e.g., SDL2 for windowing plus custom game controller input), always forward the raw events to ImGui through the standard backend functions first. The capture flags remain the single source of truth regardless of how many input pipelines your application maintains.

Summary

  • Always forward raw mouse and keyboard events to ImGui via your backend's ProcessEvent functions before checking capture flags.
  • Query io.WantCaptureMouse and io.WantCaptureKeyboard from ImGui::GetIO() after ImGui::NewFrame() returns to determine if your application should process the current input.
  • Never use IsWindowHovered() or widget-specific checks for global input routing; use only the IO flags.
  • Override capture for specific frames using SetNextFrameWantCaptureMouse() and SetNextFrameWantCaptureKeyboard() when integrating native dialogs or special modes.
  • Handle special cases like WantCaptureMouseUnlessPopupClose when modals or popups are active.

Frequently Asked Questions

When should I check WantCaptureMouse and WantCaptureKeyboard?

Check these flags immediately after calling ImGui::NewFrame() in your main loop, or inside your platform event loop after forwarding the event to ImGui via the backend's ProcessEvent function. The flags reflect ImGui's intent for the current frame based on the active widgets and window focus states.

Can I use IsWindowHovered instead of WantCaptureMouse for input routing?

No. IsWindowHovered() is designed for UI-specific logic (like changing cursor styles or tooltips) and does not account for popups, modal windows, or widgets that may capture input outside their visual bounds. According to the Dear ImGui source code in imgui.h, io.WantCaptureMouse is the only authoritative source for determining if ImGui intends to consume input events.

How do I temporarily disable ImGui input capture?

Call ImGui::SetNextFrameWantCaptureMouse(false) or ImGui::SetNextFrameWantCaptureKeyboard(false) before the next NewFrame() call. This writes to the internal WantCaptureMouseNextFrame and WantCaptureKeyboardNextFrame members in imgui_internal.h, forcing the flags to false for the subsequent frame regardless of UI state.

Do I need to check these flags before calling ImGui input functions?

No. You must always feed raw input events to ImGui (via ImGui_ImplSDL2_ProcessEvent or equivalent) unconditionally. The capture flags are only for deciding whether your application should also process those events. ImGui requires all events to maintain its internal state machine, even when it ultimately reports WantCaptureMouse as false.

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 →