How to Handle IME (Input Method Editor) Input for International Text in Dear ImGui

Dear ImGui supports IME input for international languages through a platform abstraction layer where ImGuiPlatformImeData communicates cursor position and visibility to the OS via the Platform_SetImeDataFn callback, requiring no additional application code when using official backends.

The ocornut/imgui library provides robust support for Input Method Editors (IME), enabling users to type non-Latin characters such as Chinese, Japanese, and Korean (CJK) in InputText widgets. This functionality relies on a cooperative effort between Dear ImGui's core logic and platform-specific backend implementations to position the IME composition window correctly.

Understanding the IME Architecture in Dear ImGui

IME support in Dear ImGui is split between a data structure that describes the text input state and a backend function that forwards this data to the operating system.

The Platform IME Data Structure

The ImGuiPlatformImeData struct, defined in [imgui.h](https://github.com/ocornut/imgui/blob/master/imgui.h#L4109), contains the information necessary to position the IME candidate window:

  • WantVisible – Boolean indicating whether the IME UI should be displayed
  • WantTextInput – Boolean requesting text input focus from the OS
  • InputPos – Screen coordinates (ImVec2) where the IME window should appear
  • InputLineHeight – Height of the text line for proper candidate list positioning
  • ViewportId – Target viewport ID for multi-window setups

The Backend Hook

The Platform_SetImeDataFn callback is stored in ImGuiPlatformIO (declared at [imgui.h](https://github.com/ocornut/imgui/blob/master/imgui.h#L4064)). Dear ImGui invokes this function pointer at the end of each frame in ImGui::EndFrame() (around line 5810 in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp#L5810)) to notify the backend of IME state changes.

How IME Input Works in Dear ImGui

The IME workflow follows a five-step pipeline that bridges OS composition events with Dear ImGui's text input widgets:

  1. OS generates composition events – When the user types, the OS sends platform-specific messages (e.g., WM_IME_COMPOSITION on Windows or SDL_TEXTINPUT on SDL).

  2. Backend translates events – The platform backend (Win32, SDL2, SDL3, etc.) receives these messages and calls io.AddInputCharacter() or io.AddKeyEvent() to feed them into Dear ImGui.

  3. ImGui calculates cursor position – After processing widgets, Dear ImGui updates the global g.PlatformImeData with the current text cursor screen position and line height.

  4. Backend forwards data – The Platform_SetImeDataFn callback is invoked with the filled ImGuiPlatformImeData struct. The backend then calls OS-specific APIs (e.g., ImmSetCompositionWindow on Win32, SDL_SetTextInputRect on SDL) to position the native IME UI.

  5. OS renders the candidate window – The operating system displays the IME composition interface at the specified coordinates, allowing character selection.

Because the backend drives this entire pipeline, most applications require no additional ImGui code to support international text input.

Backend-Specific Implementation Details

Different platform backends handle the Platform_SetImeDataFn callback in their respective source files.

Win32 Backend

In backends/imgui_impl_win32.cpp, the backend processes WM_IME_COMPOSITION and WM_IME_CHAR messages to handle character composition. When Platform_SetImeDataFn is called, the backend translates the ImGuiPlatformImeData coordinates and invokes ImmSetCompositionWindow() to position the IME candidate list.

SDL2 and SDL3 Backends

The SDL implementations in backends/imgui_impl_sdl2.cpp and backends/imgui_impl_sdl3.cpp follow the same pattern but require specific window hints to enable the IME UI. You must set the SDL_HINT_IME_SHOW_UI hint to "1" before creating the window:

SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
SDL_Window* window = SDL_CreateWindow("My App", ...);

The backend then calls SDL_SetTextInputRect() when the IME callback fires.

Custom Backend Implementation

If you are writing a custom backend, you must implement a function matching the Platform_SetImeDataFn signature and assign it to io.Platform_SetImeDataFn during initialization.

Practical Code Examples

Basic Usage (Zero Configuration)

When using an official backend with IME support enabled, international text input works automatically:

// Standard frame loop
ImGui::NewFrame();
ImGui::Begin("Chat Window");
ImGui::InputTextMultiline("##message", buffer, sizeof(buffer));
ImGui::End();
ImGui::Render();

For SDL2/SDL3, ensure you set the hint before window creation as shown in the backend section above.

Customizing IME Cursor Position

To manually control where the IME candidate window appears, modify the ImGuiPlatformImeData structure before the frame ends:

ImGuiIO& io = ImGui::GetIO();
ImGui::InputText("Username", buf, sizeof(buf));

// Position IME at a specific location
io.PlatformImeData.WantVisible = true;
io.PlatformImeData.WantTextInput = true;
io.PlatformImeData.InputPos = ImGui::GetCursorScreenPos();
io.PlatformImeData.InputLineHeight = ImGui::GetTextLineHeight();

Implementing a Custom Backend IME Hook

For custom backends, implement the callback and register it during setup:

void MyBackend_SetImeData(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data)
{
    MyNativeWindow* window = (MyNativeWindow*)viewport->PlatformHandle;
    
    // Convert ImGui screen coordinates to native window coordinates
    NativeSetCompositionWindow(window, data->InputPos.x, data->InputPos.y, data->InputLineHeight);
    NativeShowIme(data->WantVisible);
}

// During initialization
ImGuiIO& io = ImGui::GetIO();
io.Platform_SetImeDataFn = MyBackend_SetImeData;

Advanced IME Handling Scenarios

Several situations require manual intervention in the IME data.

Conditional Visibility for Password Fields Set WantVisible = false to hide the IME candidate window while still receiving composed characters. This is useful for password inputs where you want to prevent on-screen character previews:

ImGui::InputText("Password", pass, sizeof(pass), ImGuiInputTextFlags_Password);
io.PlatformImeData.WantVisible = false;

Multi-Viewport Support When using multiple viewports with ImGuiConfigFlags_ViewportsEnable, the ViewportId field in ImGuiPlatformImeData indicates which native window should receive the IME data. Custom backends must forward the IME position to the correct window handle associated with that viewport ID.

Summary

  • IME support in Dear ImGui relies on the ImGuiPlatformImeData struct and Platform_SetImeDataFn callback to communicate with the OS.
  • No application code is required when using official backends like Win32 or SDL, provided SDL applications set SDL_HINT_IME_SHOW_UI to "1".
  • Cursor positioning is handled automatically in imgui.cpp around line 5810, but can be overridden manually via io.PlatformImeData.
  • Custom backends must implement the Platform_SetImeDataFn hook to call native IME APIs such as ImmSetCompositionWindow or SDL_SetTextInputRect.
  • Advanced features like hiding the IME UI for password fields or supporting multi-viewport setups require modifying the WantVisible and ViewportId fields respectively.

Frequently Asked Questions

Does Dear ImGui support Chinese, Japanese, and Korean input out of the box?

Yes, Dear ImGui fully supports CJK input through the IME mechanism described in ImGuiPlatformImeData. As long as your platform backend implements the Platform_SetImeDataFn callback (as seen in imgui_impl_win32.cpp and the SDL backends), users can compose international text in InputText widgets without additional application code.

Why isn't the IME candidate window showing in my SDL2 application?

SDL2 requires the SDL_HINT_IME_SHOW_UI hint to be set to "1" before window creation. Without this hint, SDL suppresses the IME composition UI even though it still sends text events. Add SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); before calling SDL_CreateWindow(), as demonstrated in the official SDL2 examples in the Dear ImGui repository.

How do I hide the IME UI for password fields while still receiving input?

Set io.PlatformImeData.WantVisible = false immediately after the InputText widget with the ImGuiInputTextFlags_Password flag. This prevents the operating system from displaying the character composition window while still allowing the user to type and confirm their input. Note that you should only modify this field when the widget is active to avoid affecting other text inputs.

Where is the IME callback actually invoked in the Dear ImGui source code?

The Platform_SetImeDataFn callback is invoked in imgui.cpp around line 5810, inside the ImGui::EndFrame() function. This occurs after all widgets have been processed, ensuring that g.PlatformImeData contains the final cursor position for the active text input widget for the current frame.

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 →