dear-imgui-winit
Winit platform backend for the dear-imgui-rs Rust crate. It wires winit input/events,
cursor handling and DPI awareness into Dear ImGui. Inspired by
imgui-rs/imgui-winit-support.
Compatibility
| Item | Version |
|---|---|
| Crate | 0.13.0 |
| dear-imgui-rs | 0.13.0 |
| winit | 0.30.13 |
See also: docs/COMPATIBILITY.md for the full workspace matrix.
Quick Start
Minimal flow with winit 0.30 ApplicationHandler-style loops:
use ;
use ;
use ;
APIs of interest:
WinitPlatform::new(&mut Context)WinitPlatform::attach_window(&Window, HiDpiMode, &mut Context)WinitPlatform::handle_window_event(&mut Context, &Window, &WindowEvent)— forApplicationHandler::window_eventWinitPlatform::handle_event(&mut Context, &Window, &Event<T>)— for closure-styleEventLoop::runWinitPlatform::prepare_frame(&Window, &mut Context)WinitPlatform::prepare_render_with_ui(&Ui, &Window)— updates OS cursor from ImGuiWinitPlatform::detach_window(&Window, &mut Context)— clears winit-owned IME hooks before a window is destroyed while the context remains alive
DPI / HiDPI
HiDpiMode controls how the backend derives the framebuffer scale:
Default: use winit’swindow.scale_factor()directly.Rounded: round the winit factor to the nearest integer to avoid blurry scaling.Locked(f64): force a custom factor (e.g. 1.0).
When DPI changes (ScaleFactorChanged), the backend adjusts:
io.display_size,io.display_framebuffer_scale- mouse position (keeping pointer location consistent across scales)
Helpers are provided if you pass winit logical values around and need the same coordinates ImGui uses:
scale_size_from_winit(&Window, LogicalSize<f64>) -> LogicalSize<f64>scale_pos_from_winit(&Window, LogicalPosition<f64>) -> LogicalPosition<f64>scale_pos_for_winit(&Window, LogicalPosition<f64>) -> LogicalPosition<f64>
Input & IME
- Keyboard: press/release is mapped to
dear-imgui::Key. Whenevent.textis present on key press, characters are injected viaio.add_input_character. Coverage includes letters/digits, punctuation (',.-/;=[]\`), function and lock keys, and numpad (0-9, decimal/divide/multiply/subtract/add/equal/enter). - Mouse: buttons, position, wheel.
PixelDeltawheel is mapped to ±1.0 steps (consistent with most ImGui backends);LineDeltauses the provided values. - Modifiers: tracked via
ModifiersChangedand mirrored into left/right variants. - IME: preedit is ignored (no transient injection); committed text is appended.
Touch
Basic touch-to-mouse translation is provided:
- First active finger controls the pointer and Left mouse button.
- Started -> set position + press LMB; Moved -> update position; End/Cancelled -> release LMB.
IME integration
- IME is auto-managed by default:
prepare_render_with_uiinspectsui.io().want_text_input()and togglesWindow::set_ime_allowed(...)accordingly. This means IME (and soft keyboards on mobile) are only enabled while text widgets are active. - You can temporarily override the state with
WinitPlatform::set_ime_allowed(&window, bool). Auto-management may adjust it again on subsequent frames unless you disable it. - To fully opt out and manage IME yourself, call
WinitPlatform::set_ime_auto_management(false). - The backend tracks IME enabled/disabled state internally and exposes it
through
WinitPlatform::ime_enabled(). - If the window is destroyed before the ImGui context, call
WinitPlatform::detach_window(&window, &mut context)first so Dear ImGui no longer holds a raw pointer to that window for IME cursor placement.
Cursor Handling
prepare_render_with_ui(&Ui, &Window) updates the OS cursor from ui.mouse_cursor().
Changes are cached to avoid redundant OS calls. If ConfigFlags::NO_MOUSE_CURSOR_CHANGE
is set, OS cursor updates are skipped. The software-drawn cursor flag is currently not
exposed via our Io wrapper (defaults to OS cursor).
If Dear ImGui requests repositioning (io.want_set_mouse_pos()), prepare_frame
will set the OS cursor position accordingly.
Software Cursor
You can force Dear ImGui to draw the cursor by enabling the software cursor:
// Option 1: via Io directly
imgui_ctx.io_mut.set_mouse_draw_cursor;
// Option 2: helper on the platform
platform.set_software_cursor_enabled;
When software cursor is enabled:
- The platform hides the OS cursor.
- Dear ImGui emits cursor geometry in draw data; ensure your renderer renders the draw lists every frame.
Backend Flags
This backend sets (when appropriate):
BackendFlags::HAS_MOUSE_CURSORSBackendFlags::HAS_SET_MOUSE_POS
For diagnostics, the backend also sets BackendPlatformName to "dear-imgui-winit {version}".
Multi-Viewport (Experimental)
Multi-viewport support is available behind the multi-viewport feature and is
experimental. It follows the upstream backend split:
- The winit platform layer (
dear-imgui-winit/multi-viewport) owns OS windows and routes events for secondary viewports. - A renderer backend must also opt into viewports (e.g.
dear-imgui-wgpu/multi-viewport-winit) to create per-viewport render targets and draw them.
Current support matrix:
- winit + WGPU: experimental native multi-viewport, exercised by the
multi_viewport_wgpuexample.- Enabled on Windows/macOS/Linux; tested on Windows/macOS, Linux untested.
- Example:
cargo run -p dear-imgui-examples --bin multi_viewport_wgpu --features multi-viewport
- winit + OpenGL (glow/glutin): no official multi-viewport stack yet.
If you need multi-viewport OpenGL today, use the SDL3 routes
(
sdl3_opengl_multi_viewportorsdl3_glow_multi_viewport).
Notes & Differences vs imgui-rs
This crate targets the dear-imgui-rs bindings in this repository and its API
surface. It’s intentionally separate from imgui-rs/imgui-winit-support, though
many behaviors are aligned for familiarity.
Known limitations:
- Key mapping covers digits, letters, navigation, modifiers, and function keys. Some punctuation/numpad-specific variants are not mapped yet.