2025-01-20 14:30:40 +01:00
// dear imgui: Platform Backend for SDL3
// This needs to be used along with a Renderer (e.g. SDL_GPU, DirectX11, OpenGL3, Vulkan..)
2023-02-07 13:26:24 +01:00
// (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
2024-07-02 11:37:18 +02:00
2023-02-07 13:26:24 +01:00
// Implemented features:
// [X] Platform: Clipboard support.
2023-04-04 19:43:51 +02:00
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
2024-11-06 16:56:51 +01:00
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
2025-03-21 15:42:47 +01:00
// [X] Platform: Gamepad support.
2024-12-05 12:43:04 +01:00
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: IME support.
2023-02-07 13:26:24 +01:00
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
2023-09-11 13:47:08 +02:00
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
2023-02-07 13:26:24 +01:00
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
2026-01-15 16:07:07 +01:00
// 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168)
2025-11-05 18:54:47 +01:00
// 2025-11-05: Fixed an issue with missing characters events when an already active text field changes viewports. (#9054)
2025-10-22 13:33:36 +02:00
// 2025-10-22: Fixed Platform_OpenInShellFn() return value (unused in core).
2025-09-24 14:48:33 +02:00
// 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_EVENT_MOUSE_MOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786)
2025-09-18 16:22:24 +02:00
// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown.
2025-09-15 15:16:42 +02:00
// 2025-09-15: Use SDL_GetWindowDisplayScale() on Mac to output DisplayFrameBufferScale. The function is more reliable during resolution changes e.g. going fullscreen. (#8703, #4414)
2025-06-24 23:30:38 +03:00
// 2025-06-27: IME: avoid calling SDL_StartTextInput() again if already active. (#8727)
2025-04-22 11:21:02 +02:00
// 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible.
2025-04-09 14:56:54 +02:00
// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561)
2025-03-29 21:04:17 +01:00
// 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801)
2025-03-21 15:42:47 +01:00
// 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set.
2025-03-10 16:29:59 +01:00
// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468)
2025-02-26 15:34:31 +01:00
// 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650)
2025-02-22 11:36:41 +01:00
// 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode.
2025-02-18 18:52:08 +01:00
// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
2025-02-10 12:09:44 +01:00
// 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler.
2025-01-20 15:24:46 +01:00
// 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array.
2024-10-24 14:47:07 +02:00
// 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten.
2024-08-25 13:07:10 -04:00
// 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807)
2024-08-22 17:50:10 +02:00
// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
2024-08-22 16:55:14 +02:00
// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn
2024-08-19 14:07:25 +02:00
// 2024-08-19: Storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*.
2024-08-19 13:57:08 +02:00
// 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853)
2024-07-22 10:49:22 +02:00
// 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807)
// 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801)
2024-07-18 14:02:17 +02:00
// 2024-07-15: Update for SDL3 api changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794)
2024-07-02 11:32:46 +02:00
// 2024-07-02: Update for SDL3 api changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762).
2024-06-30 16:28:53 -06:00
// 2024-07-01: Update for SDL3 api changes: SDL_SetTextInputRect() changed to SDL_SetTextInputArea().
2024-06-26 14:41:21 +02:00
// 2024-06-26: Update for SDL3 api changes: SDL_StartTextInput()/SDL_StopTextInput()/SDL_SetTextInputRect() functions signatures.
// 2024-06-24: Update for SDL3 api changes: SDL_EVENT_KEY_DOWN/SDL_EVENT_KEY_UP contents.
// 2024-06-03; Update for SDL3 api changes: SDL_SYSTEM_CURSOR_ renames.
// 2024-05-15: Update for SDL3 api changes: SDLK_ renames.
2024-03-28 21:05:44 +01:00
// 2024-04-15: Inputs: Re-enable calling SDL_StartTextInput()/SDL_StopTextInput() as SDL3 no longer enables it by default and should play nicer with IME.
2024-02-14 11:37:18 +01:00
// 2024-02-13: Inputs: Fixed gamepad support. Handle gamepad disconnection. Added ImGui_ImplSDL3_SetGamepadMode().
2023-11-13 16:20:38 +01:00
// 2023-11-13: Updated for recent SDL3 API changes.
2023-10-05 21:26:07 +02:00
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
2023-05-04 17:06:36 +02:00
// 2023-05-04: Fixed build on Emscripten/iOS/Android. (#6391)
2023-04-11 11:20:29 +02:00
// 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306)
2023-04-04 19:43:51 +02:00
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702)
2023-02-23 13:06:07 +01:00
// 2023-02-23: Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. (#6189, #6114, #3644)
2023-02-07 13:26:24 +01:00
// 2023-02-07: Forked "imgui_impl_sdl2" into "imgui_impl_sdl3". Removed version checks for old feature. Refer to imgui_impl_sdl2.cpp for older changelog.
# include "imgui.h"
2023-07-13 11:27:52 +02:00
# ifndef IMGUI_DISABLE
2023-02-07 13:26:24 +01:00
# include "imgui_impl_sdl3.h"
2023-03-23 18:17:45 +01:00
// Clang warnings with -Weverything
# if defined(__clang__)
# pragma clang diagnostic push
2025-06-20 14:46:32 +02:00
# pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
2023-03-23 18:17:45 +01:00
# pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
# endif
2023-02-07 13:26:24 +01:00
// SDL
2023-02-07 13:49:37 +01:00
# include <SDL3/SDL.h>
2025-05-13 15:48:00 +02:00
# include <stdio.h> // for snprintf()
2023-02-07 13:26:24 +01:00
# if defined(__APPLE__)
# include <TargetConditionals.h>
# endif
2023-11-13 16:20:38 +01:00
# ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
# endif
2023-02-07 13:26:24 +01:00
2023-02-07 13:49:37 +01:00
# if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
2023-02-07 13:26:24 +01:00
# define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
# else
# define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
# endif
2024-05-15 14:18:48 +02:00
// FIXME-LEGACY: remove when SDL 3.1.3 preview is released.
# ifndef SDLK_APOSTROPHE
# define SDLK_APOSTROPHE SDLK_QUOTE
# endif
# ifndef SDLK_GRAVE
# define SDLK_GRAVE SDLK_BACKQUOTE
# endif
2023-02-07 13:26:24 +01:00
// SDL Data
struct ImGui_ImplSDL3_Data
{
2024-02-13 15:49:49 +01:00
SDL_Window * Window ;
2024-08-19 13:57:08 +02:00
SDL_WindowID WindowID ;
2024-02-13 15:49:49 +01:00
SDL_Renderer * Renderer ;
Uint64 Time ;
char * ClipboardTextData ;
2025-05-15 15:36:42 +02:00
char BackendPlatformName [ 48 ] ;
2024-02-13 15:49:49 +01:00
2024-06-26 14:41:21 +02:00
// IME handling
SDL_Window * ImeWindow ;
2025-11-05 18:54:47 +01:00
ImGuiPlatformImeData ImeData ;
bool ImeDirty ;
2024-06-26 14:41:21 +02:00
2024-02-13 15:49:49 +01:00
// Mouse handling
Uint32 MouseWindowID ;
int MouseButtonsDown ;
SDL_Cursor * MouseCursors [ ImGuiMouseCursor_COUNT ] ;
SDL_Cursor * MouseLastCursor ;
int MousePendingLeaveFrame ;
bool MouseCanUseGlobalState ;
2025-04-09 14:56:54 +02:00
bool MouseCanUseCapture ;
2023-02-07 13:26:24 +01:00
2024-02-14 11:37:18 +01:00
// Gamepad handling
ImVector < SDL_Gamepad * > Gamepads ;
ImGui_ImplSDL3_GamepadMode GamepadMode ;
bool WantUpdateGamepadsList ;
2023-02-07 13:26:24 +01:00
ImGui_ImplSDL3_Data ( ) { memset ( ( void * ) this , 0 , sizeof ( * this ) ) ; }
} ;
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
static ImGui_ImplSDL3_Data * ImGui_ImplSDL3_GetBackendData ( )
{
return ImGui : : GetCurrentContext ( ) ? ( ImGui_ImplSDL3_Data * ) ImGui : : GetIO ( ) . BackendPlatformUserData : nullptr ;
}
2025-11-05 18:54:47 +01:00
// Forward Declarations
static void ImGui_ImplSDL3_UpdateIme ( ) ;
2023-02-07 13:26:24 +01:00
// Functions
2024-08-22 17:50:10 +02:00
static const char * ImGui_ImplSDL3_GetClipboardText ( ImGuiContext * )
2023-02-07 13:26:24 +01:00
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
if ( bd - > ClipboardTextData )
SDL_free ( bd - > ClipboardTextData ) ;
2026-01-15 16:07:07 +01:00
if ( SDL_HasClipboardText ( ) )
bd - > ClipboardTextData = SDL_GetClipboardText ( ) ;
else
bd - > ClipboardTextData = nullptr ;
2023-02-07 13:26:24 +01:00
return bd - > ClipboardTextData ;
}
2024-08-22 17:50:10 +02:00
static void ImGui_ImplSDL3_SetClipboardText ( ImGuiContext * , const char * text )
2023-02-07 13:26:24 +01:00
{
SDL_SetClipboardText ( text ) ;
}
2025-11-05 18:54:47 +01:00
static ImGuiViewport * ImGui_ImplSDL3_GetViewportForWindowID ( SDL_WindowID window_id )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
return ( window_id = = bd - > WindowID ) ? ImGui : : GetMainViewport ( ) : nullptr ;
}
static void ImGui_ImplSDL3_PlatformSetImeData ( ImGuiContext * , ImGuiViewport * , ImGuiPlatformImeData * data )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
bd - > ImeData = * data ;
bd - > ImeDirty = true ;
ImGui_ImplSDL3_UpdateIme ( ) ;
}
// We discard viewport passed via ImGuiPlatformImeData and always call SDL_StartTextInput() on SDL_GetKeyboardFocus().
static void ImGui_ImplSDL3_UpdateIme ( )
2023-02-07 18:55:10 +01:00
{
2024-06-26 14:41:21 +02:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2025-11-05 18:54:47 +01:00
ImGuiPlatformImeData * data = & bd - > ImeData ;
SDL_Window * window = SDL_GetKeyboardFocus ( ) ;
// Stop previous input
2025-04-22 11:21:02 +02:00
if ( ( ! ( data - > WantVisible | | data - > WantTextInput ) | | bd - > ImeWindow ! = window ) & & bd - > ImeWindow ! = nullptr )
2024-06-26 14:41:21 +02:00
{
SDL_StopTextInput ( bd - > ImeWindow ) ;
bd - > ImeWindow = nullptr ;
}
2026-01-15 16:08:40 +01:00
if ( ( ! bd - > ImeDirty & & bd - > ImeWindow = = window ) | | ( window = = nullptr ) )
2025-11-05 18:54:47 +01:00
return ;
// Start/update current input
bd - > ImeDirty = false ;
2023-02-07 18:55:10 +01:00
if ( data - > WantVisible )
{
SDL_Rect r ;
r . x = ( int ) data - > InputPos . x ;
r . y = ( int ) data - > InputPos . y ;
r . w = 1 ;
r . h = ( int ) data - > InputLineHeight ;
2024-06-30 16:28:53 -06:00
SDL_SetTextInputArea ( window , & r , 0 ) ;
2024-06-26 14:41:21 +02:00
bd - > ImeWindow = window ;
2023-02-07 18:55:10 +01:00
}
2025-06-24 23:30:38 +03:00
if ( ! SDL_TextInputActive ( window ) & & ( data - > WantVisible | | data - > WantTextInput ) )
2025-04-22 11:21:02 +02:00
SDL_StartTextInput ( window ) ;
2023-02-07 18:55:10 +01:00
}
2024-09-19 14:09:45 +02:00
// Not static to allow third-party code to use that if they want to (but undocumented)
2024-10-24 17:24:47 +02:00
ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey ( SDL_Keycode keycode , SDL_Scancode scancode ) ;
2024-09-19 14:09:45 +02:00
ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey ( SDL_Keycode keycode , SDL_Scancode scancode )
2023-02-07 13:26:24 +01:00
{
2024-07-02 11:32:46 +02:00
// Keypad doesn't have individual key values in SDL3
switch ( scancode )
{
case SDL_SCANCODE_KP_0 : return ImGuiKey_Keypad0 ;
case SDL_SCANCODE_KP_1 : return ImGuiKey_Keypad1 ;
case SDL_SCANCODE_KP_2 : return ImGuiKey_Keypad2 ;
case SDL_SCANCODE_KP_3 : return ImGuiKey_Keypad3 ;
case SDL_SCANCODE_KP_4 : return ImGuiKey_Keypad4 ;
case SDL_SCANCODE_KP_5 : return ImGuiKey_Keypad5 ;
case SDL_SCANCODE_KP_6 : return ImGuiKey_Keypad6 ;
case SDL_SCANCODE_KP_7 : return ImGuiKey_Keypad7 ;
case SDL_SCANCODE_KP_8 : return ImGuiKey_Keypad8 ;
case SDL_SCANCODE_KP_9 : return ImGuiKey_Keypad9 ;
case SDL_SCANCODE_KP_PERIOD : return ImGuiKey_KeypadDecimal ;
case SDL_SCANCODE_KP_DIVIDE : return ImGuiKey_KeypadDivide ;
case SDL_SCANCODE_KP_MULTIPLY : return ImGuiKey_KeypadMultiply ;
case SDL_SCANCODE_KP_MINUS : return ImGuiKey_KeypadSubtract ;
case SDL_SCANCODE_KP_PLUS : return ImGuiKey_KeypadAdd ;
case SDL_SCANCODE_KP_ENTER : return ImGuiKey_KeypadEnter ;
case SDL_SCANCODE_KP_EQUALS : return ImGuiKey_KeypadEqual ;
2024-07-02 12:12:25 +02:00
default : break ;
2024-07-02 11:32:46 +02:00
}
2023-02-07 13:26:24 +01:00
switch ( keycode )
{
case SDLK_TAB : return ImGuiKey_Tab ;
case SDLK_LEFT : return ImGuiKey_LeftArrow ;
case SDLK_RIGHT : return ImGuiKey_RightArrow ;
case SDLK_UP : return ImGuiKey_UpArrow ;
case SDLK_DOWN : return ImGuiKey_DownArrow ;
case SDLK_PAGEUP : return ImGuiKey_PageUp ;
case SDLK_PAGEDOWN : return ImGuiKey_PageDown ;
case SDLK_HOME : return ImGuiKey_Home ;
case SDLK_END : return ImGuiKey_End ;
case SDLK_INSERT : return ImGuiKey_Insert ;
case SDLK_DELETE : return ImGuiKey_Delete ;
case SDLK_BACKSPACE : return ImGuiKey_Backspace ;
case SDLK_SPACE : return ImGuiKey_Space ;
case SDLK_RETURN : return ImGuiKey_Enter ;
case SDLK_ESCAPE : return ImGuiKey_Escape ;
2025-03-10 16:29:59 +01:00
//case SDLK_APOSTROPHE: return ImGuiKey_Apostrophe;
2023-02-07 13:26:24 +01:00
case SDLK_COMMA : return ImGuiKey_Comma ;
2025-03-10 16:29:59 +01:00
//case SDLK_MINUS: return ImGuiKey_Minus;
2023-02-07 13:26:24 +01:00
case SDLK_PERIOD : return ImGuiKey_Period ;
2025-03-10 16:29:59 +01:00
//case SDLK_SLASH: return ImGuiKey_Slash;
2023-02-07 13:26:24 +01:00
case SDLK_SEMICOLON : return ImGuiKey_Semicolon ;
2025-03-10 16:29:59 +01:00
//case SDLK_EQUALS: return ImGuiKey_Equal;
//case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket;
//case SDLK_BACKSLASH: return ImGuiKey_Backslash;
//case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket;
//case SDLK_GRAVE: return ImGuiKey_GraveAccent;
2023-02-07 13:26:24 +01:00
case SDLK_CAPSLOCK : return ImGuiKey_CapsLock ;
case SDLK_SCROLLLOCK : return ImGuiKey_ScrollLock ;
case SDLK_NUMLOCKCLEAR : return ImGuiKey_NumLock ;
case SDLK_PRINTSCREEN : return ImGuiKey_PrintScreen ;
case SDLK_PAUSE : return ImGuiKey_Pause ;
case SDLK_LCTRL : return ImGuiKey_LeftCtrl ;
case SDLK_LSHIFT : return ImGuiKey_LeftShift ;
case SDLK_LALT : return ImGuiKey_LeftAlt ;
case SDLK_LGUI : return ImGuiKey_LeftSuper ;
case SDLK_RCTRL : return ImGuiKey_RightCtrl ;
case SDLK_RSHIFT : return ImGuiKey_RightShift ;
case SDLK_RALT : return ImGuiKey_RightAlt ;
case SDLK_RGUI : return ImGuiKey_RightSuper ;
case SDLK_APPLICATION : return ImGuiKey_Menu ;
case SDLK_0 : return ImGuiKey_0 ;
case SDLK_1 : return ImGuiKey_1 ;
case SDLK_2 : return ImGuiKey_2 ;
case SDLK_3 : return ImGuiKey_3 ;
case SDLK_4 : return ImGuiKey_4 ;
case SDLK_5 : return ImGuiKey_5 ;
case SDLK_6 : return ImGuiKey_6 ;
case SDLK_7 : return ImGuiKey_7 ;
case SDLK_8 : return ImGuiKey_8 ;
case SDLK_9 : return ImGuiKey_9 ;
2024-07-02 11:32:46 +02:00
case SDLK_A : return ImGuiKey_A ;
case SDLK_B : return ImGuiKey_B ;
case SDLK_C : return ImGuiKey_C ;
case SDLK_D : return ImGuiKey_D ;
case SDLK_E : return ImGuiKey_E ;
case SDLK_F : return ImGuiKey_F ;
case SDLK_G : return ImGuiKey_G ;
case SDLK_H : return ImGuiKey_H ;
case SDLK_I : return ImGuiKey_I ;
case SDLK_J : return ImGuiKey_J ;
case SDLK_K : return ImGuiKey_K ;
case SDLK_L : return ImGuiKey_L ;
case SDLK_M : return ImGuiKey_M ;
case SDLK_N : return ImGuiKey_N ;
case SDLK_O : return ImGuiKey_O ;
case SDLK_P : return ImGuiKey_P ;
case SDLK_Q : return ImGuiKey_Q ;
case SDLK_R : return ImGuiKey_R ;
case SDLK_S : return ImGuiKey_S ;
case SDLK_T : return ImGuiKey_T ;
case SDLK_U : return ImGuiKey_U ;
case SDLK_V : return ImGuiKey_V ;
case SDLK_W : return ImGuiKey_W ;
case SDLK_X : return ImGuiKey_X ;
case SDLK_Y : return ImGuiKey_Y ;
case SDLK_Z : return ImGuiKey_Z ;
2023-02-07 13:26:24 +01:00
case SDLK_F1 : return ImGuiKey_F1 ;
case SDLK_F2 : return ImGuiKey_F2 ;
case SDLK_F3 : return ImGuiKey_F3 ;
case SDLK_F4 : return ImGuiKey_F4 ;
case SDLK_F5 : return ImGuiKey_F5 ;
case SDLK_F6 : return ImGuiKey_F6 ;
case SDLK_F7 : return ImGuiKey_F7 ;
case SDLK_F8 : return ImGuiKey_F8 ;
case SDLK_F9 : return ImGuiKey_F9 ;
case SDLK_F10 : return ImGuiKey_F10 ;
case SDLK_F11 : return ImGuiKey_F11 ;
case SDLK_F12 : return ImGuiKey_F12 ;
2023-10-05 20:39:49 +02:00
case SDLK_F13 : return ImGuiKey_F13 ;
case SDLK_F14 : return ImGuiKey_F14 ;
case SDLK_F15 : return ImGuiKey_F15 ;
case SDLK_F16 : return ImGuiKey_F16 ;
case SDLK_F17 : return ImGuiKey_F17 ;
case SDLK_F18 : return ImGuiKey_F18 ;
case SDLK_F19 : return ImGuiKey_F19 ;
case SDLK_F20 : return ImGuiKey_F20 ;
case SDLK_F21 : return ImGuiKey_F21 ;
case SDLK_F22 : return ImGuiKey_F22 ;
case SDLK_F23 : return ImGuiKey_F23 ;
case SDLK_F24 : return ImGuiKey_F24 ;
2023-10-05 21:26:07 +02:00
case SDLK_AC_BACK : return ImGuiKey_AppBack ;
case SDLK_AC_FORWARD : return ImGuiKey_AppForward ;
2024-07-02 12:12:25 +02:00
default : break ;
2023-02-07 13:26:24 +01:00
}
2025-03-10 16:29:59 +01:00
// Fallback to scancode
switch ( scancode )
{
case SDL_SCANCODE_GRAVE : return ImGuiKey_GraveAccent ;
case SDL_SCANCODE_MINUS : return ImGuiKey_Minus ;
case SDL_SCANCODE_EQUALS : return ImGuiKey_Equal ;
case SDL_SCANCODE_LEFTBRACKET : return ImGuiKey_LeftBracket ;
case SDL_SCANCODE_RIGHTBRACKET : return ImGuiKey_RightBracket ;
case SDL_SCANCODE_NONUSBACKSLASH : return ImGuiKey_Oem102 ;
case SDL_SCANCODE_BACKSLASH : return ImGuiKey_Backslash ;
case SDL_SCANCODE_SEMICOLON : return ImGuiKey_Semicolon ;
case SDL_SCANCODE_APOSTROPHE : return ImGuiKey_Apostrophe ;
case SDL_SCANCODE_COMMA : return ImGuiKey_Comma ;
case SDL_SCANCODE_PERIOD : return ImGuiKey_Period ;
case SDL_SCANCODE_SLASH : return ImGuiKey_Slash ;
2025-03-11 12:05:23 +01:00
default : break ;
2025-03-10 16:29:59 +01:00
}
2023-02-07 13:26:24 +01:00
return ImGuiKey_None ;
}
static void ImGui_ImplSDL3_UpdateKeyModifiers ( SDL_Keymod sdl_key_mods )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-02-07 13:49:37 +01:00
io . AddKeyEvent ( ImGuiMod_Ctrl , ( sdl_key_mods & SDL_KMOD_CTRL ) ! = 0 ) ;
io . AddKeyEvent ( ImGuiMod_Shift , ( sdl_key_mods & SDL_KMOD_SHIFT ) ! = 0 ) ;
io . AddKeyEvent ( ImGuiMod_Alt , ( sdl_key_mods & SDL_KMOD_ALT ) ! = 0 ) ;
io . AddKeyEvent ( ImGuiMod_Super , ( sdl_key_mods & SDL_KMOD_GUI ) ! = 0 ) ;
2023-02-07 13:26:24 +01:00
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
bool ImGui_ImplSDL3_ProcessEvent ( const SDL_Event * event )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2024-05-07 16:53:03 +02:00
IM_ASSERT ( bd ! = nullptr & & " Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()? " ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-02-07 13:26:24 +01:00
switch ( event - > type )
{
2023-02-07 13:49:37 +01:00
case SDL_EVENT_MOUSE_MOTION :
2023-02-07 13:26:24 +01:00
{
2024-12-05 12:25:02 +01:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > motion . windowID ) = = nullptr )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:26:24 +01:00
ImVec2 mouse_pos ( ( float ) event - > motion . x , ( float ) event - > motion . y ) ;
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( event - > motion . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
2023-02-07 13:26:24 +01:00
io . AddMousePosEvent ( mouse_pos . x , mouse_pos . y ) ;
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_MOUSE_WHEEL :
2023-02-07 13:26:24 +01:00
{
2024-12-05 12:25:02 +01:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > wheel . windowID ) = = nullptr )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:26:24 +01:00
//IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY);
2023-02-07 13:49:37 +01:00
float wheel_x = - event - > wheel . x ;
float wheel_y = event - > wheel . y ;
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( event - > wheel . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
2023-02-07 13:26:24 +01:00
io . AddMouseWheelEvent ( wheel_x , wheel_y ) ;
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_MOUSE_BUTTON_DOWN :
case SDL_EVENT_MOUSE_BUTTON_UP :
2023-02-07 13:26:24 +01:00
{
2024-12-05 12:25:02 +01:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > button . windowID ) = = nullptr )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:26:24 +01:00
int mouse_button = - 1 ;
if ( event - > button . button = = SDL_BUTTON_LEFT ) { mouse_button = 0 ; }
if ( event - > button . button = = SDL_BUTTON_RIGHT ) { mouse_button = 1 ; }
if ( event - > button . button = = SDL_BUTTON_MIDDLE ) { mouse_button = 2 ; }
if ( event - > button . button = = SDL_BUTTON_X1 ) { mouse_button = 3 ; }
if ( event - > button . button = = SDL_BUTTON_X2 ) { mouse_button = 4 ; }
if ( mouse_button = = - 1 )
break ;
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( event - > button . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
2023-02-07 13:49:37 +01:00
io . AddMouseButtonEvent ( mouse_button , ( event - > type = = SDL_EVENT_MOUSE_BUTTON_DOWN ) ) ;
bd - > MouseButtonsDown = ( event - > type = = SDL_EVENT_MOUSE_BUTTON_DOWN ) ? ( bd - > MouseButtonsDown | ( 1 < < mouse_button ) ) : ( bd - > MouseButtonsDown & ~ ( 1 < < mouse_button ) ) ;
2023-02-07 13:26:24 +01:00
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_TEXT_INPUT :
2023-02-07 13:26:24 +01:00
{
2024-12-05 12:25:02 +01:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > text . windowID ) = = nullptr )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:26:24 +01:00
io . AddInputCharactersUTF8 ( event - > text . text ) ;
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_KEY_DOWN :
case SDL_EVENT_KEY_UP :
2023-02-07 13:26:24 +01:00
{
2024-12-05 12:25:02 +01:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > key . windowID ) = = nullptr )
2024-08-02 00:05:51 +02:00
return false ;
2024-06-23 17:26:52 -05:00
ImGui_ImplSDL3_UpdateKeyModifiers ( ( SDL_Keymod ) event - > key . mod ) ;
2025-01-13 16:46:29 +01:00
//IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n",
// (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod);
2024-07-02 11:32:46 +02:00
ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey ( event - > key . key , event - > key . scancode ) ;
2023-02-07 13:49:37 +01:00
io . AddKeyEvent ( key , ( event - > type = = SDL_EVENT_KEY_DOWN ) ) ;
2025-06-20 14:46:32 +02:00
io . SetKeyEventNativeData ( key , ( int ) event - > key . key , ( int ) event - > key . scancode , ( int ) event - > key . scancode ) ; // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
2023-02-07 13:26:24 +01:00
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_WINDOW_MOUSE_ENTER :
{
2024-12-05 12:25:02 +01:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > window . windowID ) = = nullptr )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:49:37 +01:00
bd - > MouseWindowID = event - > window . windowID ;
2024-02-13 15:49:49 +01:00
bd - > MousePendingLeaveFrame = 0 ;
2023-02-07 13:49:37 +01:00
return true ;
}
// - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
// causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why
// we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details.
// FIXME: Unconfirmed whether this is still needed with SDL3.
case SDL_EVENT_WINDOW_MOUSE_LEAVE :
2023-02-07 13:26:24 +01:00
{
2024-12-05 12:25:02 +01:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > window . windowID ) = = nullptr )
2024-08-02 00:05:51 +02:00
return false ;
2024-02-13 15:49:49 +01:00
bd - > MousePendingLeaveFrame = ImGui : : GetFrameCount ( ) + 1 ;
2023-02-07 13:26:24 +01:00
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_WINDOW_FOCUS_GAINED :
case SDL_EVENT_WINDOW_FOCUS_LOST :
2024-08-19 13:57:08 +02:00
{
2024-12-05 12:25:02 +01:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > window . windowID ) = = nullptr )
2024-08-02 00:05:51 +02:00
return false ;
2024-08-19 13:57:08 +02:00
io . AddFocusEvent ( event - > type = = SDL_EVENT_WINDOW_FOCUS_GAINED ) ;
2023-02-07 13:49:37 +01:00
return true ;
2024-08-19 13:57:08 +02:00
}
2024-02-14 11:37:18 +01:00
case SDL_EVENT_GAMEPAD_ADDED :
case SDL_EVENT_GAMEPAD_REMOVED :
{
bd - > WantUpdateGamepadsList = true ;
return true ;
}
2025-06-20 14:46:32 +02:00
default :
break ;
2023-02-07 13:26:24 +01:00
}
return false ;
}
2023-11-13 16:20:38 +01:00
static void ImGui_ImplSDL3_SetupPlatformHandles ( ImGuiViewport * viewport , SDL_Window * window )
{
2024-08-19 14:07:25 +02:00
viewport - > PlatformHandle = ( void * ) ( intptr_t ) SDL_GetWindowID ( window ) ;
2023-11-13 16:20:38 +01:00
viewport - > PlatformHandleRaw = nullptr ;
2024-07-15 11:17:21 +02:00
# if defined(_WIN32) && !defined(__WINRT__)
2024-07-15 04:34:44 +02:00
viewport - > PlatformHandleRaw = ( HWND ) SDL_GetPointerProperty ( SDL_GetWindowProperties ( window ) , SDL_PROP_WINDOW_WIN32_HWND_POINTER , nullptr ) ;
2025-06-24 16:13:44 +02:00
# elif defined(__APPLE__)
2024-07-15 04:34:44 +02:00
viewport - > PlatformHandleRaw = SDL_GetPointerProperty ( SDL_GetWindowProperties ( window ) , SDL_PROP_WINDOW_COCOA_WINDOW_POINTER , nullptr ) ;
2023-11-13 16:20:38 +01:00
# endif
}
static bool ImGui_ImplSDL3_Init ( SDL_Window * window , SDL_Renderer * renderer , void * sdl_gl_context )
2023-02-07 13:26:24 +01:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-05-13 15:07:13 +02:00
IMGUI_CHECKVERSION ( ) ;
2023-02-07 13:26:24 +01:00
IM_ASSERT ( io . BackendPlatformUserData = = nullptr & & " Already initialized a platform backend! " ) ;
2023-11-13 16:20:38 +01:00
IM_UNUSED ( sdl_gl_context ) ; // Unused in this branch
2026-01-08 14:31:25 +01:00
//SDL_SetHint(SDL_HINT_EVENT_LOGGING, "2");
2023-02-07 13:26:24 +01:00
2025-05-13 15:48:00 +02:00
const int ver_linked = SDL_GetVersion ( ) ;
2023-02-07 13:26:24 +01:00
// Setup backend capabilities flags
ImGui_ImplSDL3_Data * bd = IM_NEW ( ImGui_ImplSDL3_Data ) ( ) ;
2025-06-20 14:46:32 +02:00
snprintf ( bd - > BackendPlatformName , sizeof ( bd - > BackendPlatformName ) , " imgui_impl_sdl3 (%d.%d.%d; %d.%d.%d) " ,
2025-05-13 15:48:00 +02:00
SDL_MAJOR_VERSION , SDL_MINOR_VERSION , SDL_MICRO_VERSION , SDL_VERSIONNUM_MAJOR ( ver_linked ) , SDL_VERSIONNUM_MINOR ( ver_linked ) , SDL_VERSIONNUM_MICRO ( ver_linked ) ) ;
2023-02-07 13:26:24 +01:00
io . BackendPlatformUserData = ( void * ) bd ;
2025-05-13 15:48:00 +02:00
io . BackendPlatformName = bd - > BackendPlatformName ;
2023-02-07 13:49:37 +01:00
io . BackendFlags | = ImGuiBackendFlags_HasMouseCursors ; // We can honor GetMouseCursor() values (optional)
io . BackendFlags | = ImGuiBackendFlags_HasSetMousePos ; // We can honor io.WantSetMousePos requests (optional, rarely used)
2023-02-07 13:26:24 +01:00
bd - > Window = window ;
2024-08-19 13:57:08 +02:00
bd - > WindowID = SDL_GetWindowID ( window ) ;
2023-02-07 13:26:24 +01:00
bd - > Renderer = renderer ;
2025-04-09 14:56:54 +02:00
// Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse()
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
bd - > MouseCanUseGlobalState = false ;
bd - > MouseCanUseCapture = false ;
# if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
const char * sdl_backend = SDL_GetCurrentVideoDriver ( ) ;
const char * capture_and_global_state_whitelist [ ] = { " windows " , " cocoa " , " x11 " , " DIVE " , " VMAN " } ;
for ( const char * item : capture_and_global_state_whitelist )
if ( strncmp ( sdl_backend , item , strlen ( item ) ) = = 0 )
bd - > MouseCanUseGlobalState = bd - > MouseCanUseCapture = true ;
# endif
2023-02-07 13:26:24 +01:00
2024-08-22 16:55:14 +02:00
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
2024-08-22 17:50:10 +02:00
platform_io . Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText ;
platform_io . Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText ;
2024-08-22 16:55:14 +02:00
platform_io . Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData ;
2025-10-22 13:33:36 +02:00
platform_io . Platform_OpenInShellFn = [ ] ( ImGuiContext * , const char * url ) { return SDL_OpenURL ( url ) ; } ;
2023-02-07 13:26:24 +01:00
2024-02-14 11:37:18 +01:00
// Gamepad handling
bd - > GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst ;
bd - > WantUpdateGamepadsList = true ;
2023-02-07 13:26:24 +01:00
// Load mouse cursors
2024-06-03 18:25:58 +02:00
bd - > MouseCursors [ ImGuiMouseCursor_Arrow ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_DEFAULT ) ;
bd - > MouseCursors [ ImGuiMouseCursor_TextInput ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_TEXT ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeAll ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_MOVE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNS ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NS_RESIZE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeEW ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_EW_RESIZE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNESW ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NESW_RESIZE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNWSE ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NWSE_RESIZE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_Hand ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_POINTER ) ;
2025-02-18 18:40:47 +01:00
bd - > MouseCursors [ ImGuiMouseCursor_Wait ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_WAIT ) ;
2025-02-18 18:52:08 +01:00
bd - > MouseCursors [ ImGuiMouseCursor_Progress ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_PROGRESS ) ;
2024-06-03 18:25:58 +02:00
bd - > MouseCursors [ ImGuiMouseCursor_NotAllowed ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NOT_ALLOWED ) ;
2023-02-07 13:26:24 +01:00
// Set platform dependent data in viewport
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
2023-11-13 16:20:38 +01:00
ImGui_ImplSDL3_SetupPlatformHandles ( main_viewport , window ) ;
2023-02-07 13:26:24 +01:00
// From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
2026-01-08 14:31:25 +01:00
// you can ignore SDL_EVENT_MOUSE_BUTTON_DOWN events coming right after a SDL_EVENT_WINDOW_FOCUS_GAINED)
2023-02-07 13:26:24 +01:00
SDL_SetHint ( SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH , " 1 " ) ;
// From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
SDL_SetHint ( SDL_HINT_MOUSE_AUTO_CAPTURE , " 0 " ) ;
return true ;
}
2026-01-08 14:31:25 +01:00
// Should technically be a SDL_GLContext but due to typedef it is sane to keep it void* in public interface.
2023-02-07 13:26:24 +01:00
bool ImGui_ImplSDL3_InitForOpenGL ( SDL_Window * window , void * sdl_gl_context )
{
2023-11-13 16:20:38 +01:00
return ImGui_ImplSDL3_Init ( window , nullptr , sdl_gl_context ) ;
2023-02-07 13:26:24 +01:00
}
bool ImGui_ImplSDL3_InitForVulkan ( SDL_Window * window )
{
2023-11-13 16:20:38 +01:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2023-02-07 13:26:24 +01:00
}
bool ImGui_ImplSDL3_InitForD3D ( SDL_Window * window )
{
# if !defined(_WIN32)
IM_ASSERT ( 0 & & " Unsupported " ) ;
# endif
2023-11-13 16:20:38 +01:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2023-02-07 13:26:24 +01:00
}
bool ImGui_ImplSDL3_InitForMetal ( SDL_Window * window )
{
2023-11-13 16:20:38 +01:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2023-02-07 13:26:24 +01:00
}
bool ImGui_ImplSDL3_InitForSDLRenderer ( SDL_Window * window , SDL_Renderer * renderer )
{
2023-11-13 16:20:38 +01:00
return ImGui_ImplSDL3_Init ( window , renderer , nullptr ) ;
2023-02-07 13:26:24 +01:00
}
2025-01-09 17:07:53 +01:00
bool ImGui_ImplSDL3_InitForSDLGPU ( SDL_Window * window )
{
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
}
2023-08-21 13:12:50 +02:00
bool ImGui_ImplSDL3_InitForOther ( SDL_Window * window )
2023-08-15 12:48:46 +02:00
{
2023-11-13 16:20:38 +01:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2023-08-15 12:48:46 +02:00
}
2024-02-14 11:37:18 +01:00
static void ImGui_ImplSDL3_CloseGamepads ( ) ;
2023-02-07 13:26:24 +01:00
void ImGui_ImplSDL3_Shutdown ( )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
IM_ASSERT ( bd ! = nullptr & & " No platform backend to shutdown, or already shutdown? " ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2025-09-18 16:22:24 +02:00
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
2023-02-07 13:26:24 +01:00
if ( bd - > ClipboardTextData )
SDL_free ( bd - > ClipboardTextData ) ;
for ( ImGuiMouseCursor cursor_n = 0 ; cursor_n < ImGuiMouseCursor_COUNT ; cursor_n + + )
2023-02-07 13:49:37 +01:00
SDL_DestroyCursor ( bd - > MouseCursors [ cursor_n ] ) ;
2024-02-14 11:37:18 +01:00
ImGui_ImplSDL3_CloseGamepads ( ) ;
2023-02-07 13:26:24 +01:00
io . BackendPlatformName = nullptr ;
io . BackendPlatformUserData = nullptr ;
2023-04-17 14:47:15 +02:00
io . BackendFlags & = ~ ( ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad ) ;
2025-09-18 16:22:24 +02:00
platform_io . ClearPlatformHandlers ( ) ;
2023-02-07 13:26:24 +01:00
IM_DELETE ( bd ) ;
}
static void ImGui_ImplSDL3_UpdateMouseData ( )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-04-04 19:43:51 +02:00
// We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below)
2023-02-07 13:26:24 +01:00
# if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
2025-02-26 15:34:31 +01:00
// - SDL_CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside.
2025-04-09 14:56:54 +02:00
// - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to mitigate the issue we wait until mouse has moved to begin capture.
if ( bd - > MouseCanUseCapture )
{
bool want_capture = false ;
for ( int button_n = 0 ; button_n < ImGuiMouseButton_COUNT & & ! want_capture ; button_n + + )
if ( ImGui : : IsMouseDragging ( button_n , 1.0f ) )
want_capture = true ;
SDL_CaptureMouse ( want_capture ) ;
}
2025-02-26 15:34:31 +01:00
2023-02-07 13:26:24 +01:00
SDL_Window * focused_window = SDL_GetKeyboardFocus ( ) ;
const bool is_app_focused = ( bd - > Window = = focused_window ) ;
# else
2023-05-04 17:06:36 +02:00
SDL_Window * focused_window = bd - > Window ;
2023-02-07 13:26:24 +01:00
const bool is_app_focused = ( SDL_GetWindowFlags ( bd - > Window ) & SDL_WINDOW_INPUT_FOCUS ) ! = 0 ; // SDL 2.0.3 and non-windowed systems: single-viewport only
# endif
if ( is_app_focused )
{
2024-10-14 15:28:00 +02:00
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
2023-02-07 13:26:24 +01:00
if ( io . WantSetMousePos )
2023-02-07 13:49:37 +01:00
SDL_WarpMouseInWindow ( bd - > Window , io . MousePos . x , io . MousePos . y ) ;
2023-02-07 13:26:24 +01:00
2025-09-24 14:48:33 +02:00
// (Optional) Fallback to provide unclamped mouse position when focused but not hovered (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured)
2025-09-24 15:00:24 +02:00
// Note that SDL_GetGlobalMouseState() is in theory slow on X11, but this only runs on rather specific cases. If a problem we may provide a way to opt-out this feature.
2025-09-24 14:48:33 +02:00
SDL_Window * hovered_window = SDL_GetMouseFocus ( ) ;
2025-02-22 11:36:41 +01:00
const bool is_relative_mouse_mode = SDL_GetWindowRelativeMouseMode ( bd - > Window ) ;
2026-01-15 16:08:40 +01:00
if ( hovered_window = = nullptr & & bd - > MouseCanUseGlobalState & & bd - > MouseButtonsDown = = 0 & & ! is_relative_mouse_mode )
2023-02-07 13:26:24 +01:00
{
2023-02-07 13:49:37 +01:00
// Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
2025-09-24 14:17:24 +02:00
float mouse_x , mouse_y ;
2023-02-07 13:49:37 +01:00
int window_x , window_y ;
2025-09-24 14:17:24 +02:00
SDL_GetGlobalMouseState ( & mouse_x , & mouse_y ) ;
2023-02-07 13:49:37 +01:00
SDL_GetWindowPosition ( focused_window , & window_x , & window_y ) ;
2025-09-24 14:17:24 +02:00
mouse_x - = window_x ;
mouse_y - = window_y ;
io . AddMousePosEvent ( mouse_x , mouse_y ) ;
2023-02-07 13:26:24 +01:00
}
}
}
static void ImGui_ImplSDL3_UpdateMouseCursor ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
if ( io . ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange )
return ;
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
ImGuiMouseCursor imgui_cursor = ImGui : : GetMouseCursor ( ) ;
if ( io . MouseDrawCursor | | imgui_cursor = = ImGuiMouseCursor_None )
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
2023-02-07 13:49:37 +01:00
SDL_HideCursor ( ) ;
2023-02-07 13:26:24 +01:00
}
else
{
// Show OS mouse cursor
SDL_Cursor * expected_cursor = bd - > MouseCursors [ imgui_cursor ] ? bd - > MouseCursors [ imgui_cursor ] : bd - > MouseCursors [ ImGuiMouseCursor_Arrow ] ;
2024-02-13 15:49:49 +01:00
if ( bd - > MouseLastCursor ! = expected_cursor )
2023-02-07 13:26:24 +01:00
{
SDL_SetCursor ( expected_cursor ) ; // SDL function doesn't have an early out (see #6113)
2024-02-13 15:49:49 +01:00
bd - > MouseLastCursor = expected_cursor ;
2023-02-07 13:26:24 +01:00
}
2023-02-07 13:49:37 +01:00
SDL_ShowCursor ( ) ;
2023-02-07 13:26:24 +01:00
}
}
2024-02-14 11:37:18 +01:00
static void ImGui_ImplSDL3_CloseGamepads ( )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
if ( bd - > GamepadMode ! = ImGui_ImplSDL3_GamepadMode_Manual )
for ( SDL_Gamepad * gamepad : bd - > Gamepads )
SDL_CloseGamepad ( gamepad ) ;
bd - > Gamepads . resize ( 0 ) ;
}
void ImGui_ImplSDL3_SetGamepadMode ( ImGui_ImplSDL3_GamepadMode mode , SDL_Gamepad * * manual_gamepads_array , int manual_gamepads_count )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
ImGui_ImplSDL3_CloseGamepads ( ) ;
if ( mode = = ImGui_ImplSDL3_GamepadMode_Manual )
{
2025-01-20 15:24:46 +01:00
IM_ASSERT ( manual_gamepads_array ! = nullptr | | manual_gamepads_count < = 0 ) ;
2024-02-14 11:37:18 +01:00
for ( int n = 0 ; n < manual_gamepads_count ; n + + )
bd - > Gamepads . push_back ( manual_gamepads_array [ n ] ) ;
}
else
{
IM_ASSERT ( manual_gamepads_array = = nullptr & & manual_gamepads_count < = 0 ) ;
bd - > WantUpdateGamepadsList = true ;
}
bd - > GamepadMode = mode ;
}
static void ImGui_ImplSDL3_UpdateGamepadButton ( ImGui_ImplSDL3_Data * bd , ImGuiIO & io , ImGuiKey key , SDL_GamepadButton button_no )
{
bool merged_value = false ;
for ( SDL_Gamepad * gamepad : bd - > Gamepads )
merged_value | = SDL_GetGamepadButton ( gamepad , button_no ) ! = 0 ;
io . AddKeyEvent ( key , merged_value ) ;
}
static inline float Saturate ( float v ) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v ; }
static void ImGui_ImplSDL3_UpdateGamepadAnalog ( ImGui_ImplSDL3_Data * bd , ImGuiIO & io , ImGuiKey key , SDL_GamepadAxis axis_no , float v0 , float v1 )
{
float merged_value = 0.0f ;
for ( SDL_Gamepad * gamepad : bd - > Gamepads )
{
float vn = Saturate ( ( float ) ( SDL_GetGamepadAxis ( gamepad , axis_no ) - v0 ) / ( float ) ( v1 - v0 ) ) ;
if ( merged_value < vn )
merged_value = vn ;
}
io . AddKeyAnalogEvent ( key , merged_value > 0.1f , merged_value ) ;
}
2023-02-07 13:26:24 +01:00
static void ImGui_ImplSDL3_UpdateGamepads ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-02-14 11:37:18 +01:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2023-02-07 13:26:24 +01:00
2024-02-14 11:37:18 +01:00
// Update list of gamepads to use
if ( bd - > WantUpdateGamepadsList & & bd - > GamepadMode ! = ImGui_ImplSDL3_GamepadMode_Manual )
{
ImGui_ImplSDL3_CloseGamepads ( ) ;
int sdl_gamepads_count = 0 ;
2024-08-25 13:07:10 -04:00
SDL_JoystickID * sdl_gamepads = SDL_GetGamepads ( & sdl_gamepads_count ) ;
2024-02-14 11:37:18 +01:00
for ( int n = 0 ; n < sdl_gamepads_count ; n + + )
if ( SDL_Gamepad * gamepad = SDL_OpenGamepad ( sdl_gamepads [ n ] ) )
{
bd - > Gamepads . push_back ( gamepad ) ;
if ( bd - > GamepadMode = = ImGui_ImplSDL3_GamepadMode_AutoFirst )
break ;
}
bd - > WantUpdateGamepadsList = false ;
2024-08-25 13:07:10 -04:00
SDL_free ( sdl_gamepads ) ;
2024-02-14 11:37:18 +01:00
}
2023-02-07 13:26:24 +01:00
io . BackendFlags & = ~ ImGuiBackendFlags_HasGamepad ;
2024-02-14 11:37:18 +01:00
if ( bd - > Gamepads . Size = = 0 )
2023-02-07 13:26:24 +01:00
return ;
io . BackendFlags | = ImGuiBackendFlags_HasGamepad ;
// Update gamepad inputs
2024-02-14 11:37:18 +01:00
const int thumb_dead_zone = 8000 ; // SDL_gamepad.h suggests using this value.
2024-05-07 16:53:03 +02:00
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadStart , SDL_GAMEPAD_BUTTON_START ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadBack , SDL_GAMEPAD_BUTTON_BACK ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadFaceLeft , SDL_GAMEPAD_BUTTON_WEST ) ; // Xbox X, PS Square
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadFaceRight , SDL_GAMEPAD_BUTTON_EAST ) ; // Xbox B, PS Circle
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadFaceUp , SDL_GAMEPAD_BUTTON_NORTH ) ; // Xbox Y, PS Triangle
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadFaceDown , SDL_GAMEPAD_BUTTON_SOUTH ) ; // Xbox A, PS Cross
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadDpadLeft , SDL_GAMEPAD_BUTTON_DPAD_LEFT ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadDpadRight , SDL_GAMEPAD_BUTTON_DPAD_RIGHT ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadDpadUp , SDL_GAMEPAD_BUTTON_DPAD_UP ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadDpadDown , SDL_GAMEPAD_BUTTON_DPAD_DOWN ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadL1 , SDL_GAMEPAD_BUTTON_LEFT_SHOULDER ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadR1 , SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadL2 , SDL_GAMEPAD_AXIS_LEFT_TRIGGER , 0.0f , 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadR2 , SDL_GAMEPAD_AXIS_RIGHT_TRIGGER , 0.0f , 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadL3 , SDL_GAMEPAD_BUTTON_LEFT_STICK ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadR3 , SDL_GAMEPAD_BUTTON_RIGHT_STICK ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadLStickLeft , SDL_GAMEPAD_AXIS_LEFTX , - thumb_dead_zone , - 32768 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadLStickRight , SDL_GAMEPAD_AXIS_LEFTX , + thumb_dead_zone , + 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadLStickUp , SDL_GAMEPAD_AXIS_LEFTY , - thumb_dead_zone , - 32768 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadLStickDown , SDL_GAMEPAD_AXIS_LEFTY , + thumb_dead_zone , + 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadRStickLeft , SDL_GAMEPAD_AXIS_RIGHTX , - thumb_dead_zone , - 32768 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadRStickRight , SDL_GAMEPAD_AXIS_RIGHTX , + thumb_dead_zone , + 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadRStickUp , SDL_GAMEPAD_AXIS_RIGHTY , - thumb_dead_zone , - 32768 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadRStickDown , SDL_GAMEPAD_AXIS_RIGHTY , + thumb_dead_zone , + 32767 ) ;
2023-02-07 13:26:24 +01:00
}
2025-06-11 16:17:54 +02:00
static void ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale ( SDL_Window * window , ImVec2 * out_size , ImVec2 * out_framebuffer_scale )
{
int w , h ;
SDL_GetWindowSize ( window , & w , & h ) ;
if ( SDL_GetWindowFlags ( window ) & SDL_WINDOW_MINIMIZED )
w = h = 0 ;
2025-09-15 15:16:42 +02:00
# if defined(__APPLE__)
float fb_scale_x = SDL_GetWindowDisplayScale ( window ) ; // Seems more reliable during resolution change (#8703)
float fb_scale_y = fb_scale_x ;
# else
int display_w , display_h ;
2025-06-11 16:17:54 +02:00
SDL_GetWindowSizeInPixels ( window , & display_w , & display_h ) ;
2025-11-18 16:34:35 +01:00
float fb_scale_x = ( w > 0 ) ? ( float ) display_w / ( float ) w : 1.0f ;
float fb_scale_y = ( h > 0 ) ? ( float ) display_h / ( float ) h : 1.0f ;
2025-09-15 15:16:42 +02:00
# endif
2025-06-11 16:17:54 +02:00
if ( out_size ! = nullptr )
* out_size = ImVec2 ( ( float ) w , ( float ) h ) ;
if ( out_framebuffer_scale ! = nullptr )
2025-09-15 15:16:42 +02:00
* out_framebuffer_scale = ImVec2 ( fb_scale_x , fb_scale_y ) ;
2025-06-11 16:17:54 +02:00
}
2023-02-07 13:26:24 +01:00
void ImGui_ImplSDL3_NewFrame ( )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2024-05-07 16:53:03 +02:00
IM_ASSERT ( bd ! = nullptr & & " Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()? " ) ;
2023-02-07 13:26:24 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2025-06-11 16:17:54 +02:00
// Setup main viewport size (every frame to accommodate for window resizing)
ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale ( bd - > Window , & io . DisplaySize , & io . DisplayFramebufferScale ) ;
2023-02-07 13:26:24 +01:00
2025-05-12 19:19:23 +02:00
// Setup time step (we could also use SDL_GetTicksNS() available since SDL3)
2023-02-23 13:06:07 +01:00
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
2023-02-07 13:26:24 +01:00
static Uint64 frequency = SDL_GetPerformanceFrequency ( ) ;
Uint64 current_time = SDL_GetPerformanceCounter ( ) ;
2023-02-23 13:06:07 +01:00
if ( current_time < = bd - > Time )
current_time = bd - > Time + 1 ;
2023-02-07 13:26:24 +01:00
io . DeltaTime = bd - > Time > 0 ? ( float ) ( ( double ) ( current_time - bd - > Time ) / frequency ) : ( float ) ( 1.0f / 60.0f ) ;
bd - > Time = current_time ;
2024-02-13 15:49:49 +01:00
if ( bd - > MousePendingLeaveFrame & & bd - > MousePendingLeaveFrame > = ImGui : : GetFrameCount ( ) & & bd - > MouseButtonsDown = = 0 )
2023-02-07 13:26:24 +01:00
{
bd - > MouseWindowID = 0 ;
2024-02-13 15:49:49 +01:00
bd - > MousePendingLeaveFrame = 0 ;
2023-02-07 13:26:24 +01:00
io . AddMousePosEvent ( - FLT_MAX , - FLT_MAX ) ;
}
ImGui_ImplSDL3_UpdateMouseData ( ) ;
ImGui_ImplSDL3_UpdateMouseCursor ( ) ;
2025-11-05 18:54:47 +01:00
ImGui_ImplSDL3_UpdateIme ( ) ;
2023-02-07 13:26:24 +01:00
// Update game controllers (if enabled and available)
ImGui_ImplSDL3_UpdateGamepads ( ) ;
}
2023-03-23 18:17:45 +01:00
2023-07-13 11:27:52 +02:00
//-----------------------------------------------------------------------------
2023-03-23 18:17:45 +01:00
# if defined(__clang__)
# pragma clang diagnostic pop
# endif
2023-07-13 11:27:52 +02:00
# endif // #ifndef IMGUI_DISABLE