@@ -6,7 +6,7 @@
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
|
||||
// [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]
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: IME support.
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible.
|
||||
// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561)
|
||||
// 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801)
|
||||
// 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set.
|
||||
// 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: 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-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode.
|
||||
@@ -65,6 +69,7 @@
|
||||
|
||||
// SDL
|
||||
#include <SDL3/SDL.h>
|
||||
#include <stdio.h> // for snprintf()
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
@@ -97,6 +102,7 @@ struct ImGui_ImplSDL3_Data
|
||||
SDL_Renderer* Renderer;
|
||||
Uint64 Time;
|
||||
char* ClipboardTextData;
|
||||
char BackendPlatformName[48];
|
||||
|
||||
// IME handling
|
||||
SDL_Window* ImeWindow;
|
||||
@@ -108,6 +114,7 @@ struct ImGui_ImplSDL3_Data
|
||||
SDL_Cursor* MouseLastCursor;
|
||||
int MousePendingLeaveFrame;
|
||||
bool MouseCanUseGlobalState;
|
||||
bool MouseCanUseCapture;
|
||||
|
||||
// Gamepad handling
|
||||
ImVector<SDL_Gamepad*> Gamepads;
|
||||
@@ -132,8 +139,7 @@ static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*)
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
if (bd->ClipboardTextData)
|
||||
SDL_free(bd->ClipboardTextData);
|
||||
const char* sdl_clipboard_text = SDL_GetClipboardText();
|
||||
bd->ClipboardTextData = sdl_clipboard_text ? SDL_strdup(sdl_clipboard_text) : nullptr;
|
||||
bd->ClipboardTextData = SDL_GetClipboardText();
|
||||
return bd->ClipboardTextData;
|
||||
}
|
||||
|
||||
@@ -147,7 +153,7 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle;
|
||||
SDL_Window* window = SDL_GetWindowFromID(window_id);
|
||||
if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != nullptr)
|
||||
if ((!(data->WantVisible || data->WantTextInput) || bd->ImeWindow != window) && bd->ImeWindow != nullptr)
|
||||
{
|
||||
SDL_StopTextInput(bd->ImeWindow);
|
||||
bd->ImeWindow = nullptr;
|
||||
@@ -160,9 +166,10 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view
|
||||
r.w = 1;
|
||||
r.h = (int)data->InputLineHeight;
|
||||
SDL_SetTextInputArea(window, &r, 0);
|
||||
SDL_StartTextInput(window);
|
||||
bd->ImeWindow = window;
|
||||
}
|
||||
if (data->WantVisible || data->WantTextInput)
|
||||
SDL_StartTextInput(window);
|
||||
}
|
||||
|
||||
// Not static to allow third-party code to use that if they want to (but undocumented)
|
||||
@@ -460,28 +467,32 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
|
||||
IM_UNUSED(sdl_gl_context); // Unused in this branch
|
||||
|
||||
// Check and store if we are on a SDL backend that supports global mouse position
|
||||
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
|
||||
bool mouse_can_use_global_state = false;
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
const char* sdl_backend = SDL_GetCurrentVideoDriver();
|
||||
const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
|
||||
for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
|
||||
if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
|
||||
mouse_can_use_global_state = true;
|
||||
#endif
|
||||
const int ver_linked = SDL_GetVersion();
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplSDL3_Data* bd = IM_NEW(ImGui_ImplSDL3_Data)();
|
||||
snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl3 (%u.%u.%u; %u.%u.%u)",
|
||||
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION, SDL_VERSIONNUM_MAJOR(ver_linked), SDL_VERSIONNUM_MINOR(ver_linked), SDL_VERSIONNUM_MICRO(ver_linked));
|
||||
io.BackendPlatformUserData = (void*)bd;
|
||||
io.BackendPlatformName = "imgui_impl_sdl3";
|
||||
io.BackendPlatformName = bd->BackendPlatformName;
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
|
||||
bd->Window = window;
|
||||
bd->WindowID = SDL_GetWindowID(window);
|
||||
bd->Renderer = renderer;
|
||||
bd->MouseCanUseGlobalState = mouse_can_use_global_state;
|
||||
|
||||
// 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
|
||||
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText;
|
||||
@@ -595,12 +606,15 @@ static void ImGui_ImplSDL3_UpdateMouseData()
|
||||
// We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below)
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
// - 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.
|
||||
// - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to migitate the issue we wait until mouse has moved to begin capture.
|
||||
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);
|
||||
// - 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);
|
||||
}
|
||||
|
||||
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||
const bool is_app_focused = (bd->Window == focused_window);
|
||||
@@ -724,9 +738,6 @@ static void ImGui_ImplSDL3_UpdateGamepads()
|
||||
SDL_free(sdl_gamepads);
|
||||
}
|
||||
|
||||
// FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||
return;
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
if (bd->Gamepads.Size == 0)
|
||||
return;
|
||||
@@ -760,24 +771,30 @@ static void ImGui_ImplSDL3_UpdateGamepads()
|
||||
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(SDL_Window* window, ImVec2* out_size, ImVec2* out_framebuffer_scale)
|
||||
{
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)
|
||||
w = h = 0;
|
||||
SDL_GetWindowSizeInPixels(window, &display_w, &display_h);
|
||||
if (out_size != nullptr)
|
||||
*out_size = ImVec2((float)w, (float)h);
|
||||
if (out_framebuffer_scale != nullptr)
|
||||
*out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / w, (float)display_h / h) : ImVec2(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDL3_NewFrame()
|
||||
{
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
SDL_GetWindowSize(bd->Window, &w, &h);
|
||||
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
|
||||
w = h = 0;
|
||||
SDL_GetWindowSizeInPixels(bd->Window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
if (w > 0 && h > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||
// Setup main viewport size (every frame to accommodate for window resizing)
|
||||
ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale);
|
||||
|
||||
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||
// Setup time step (we could also use SDL_GetTicksNS() available since SDL3)
|
||||
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
|
||||
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
Uint64 current_time = SDL_GetPerformanceCounter();
|
||||
|
Reference in New Issue
Block a user