Kaynağa Gözat

Backends: SDL3: Fixed an issue with missing characters events when an already active text field changes viewports. (#9054)

Always use SDL_GetKeyboardFocus().
(tried to defer ImGui_ImplSDL3_PlatformSetImeData() processing for when OS-window is available but it didn't actually work because we don't systemetically OS-focus new viewports and SDL3 only sent characters to keyboard focused window.)
ocornut 3 ay önce
ebeveyn
işleme
e674f57bb6
3 değiştirilmiş dosya ile 35 ekleme ve 11 silme
  1. 32 10
      backends/imgui_impl_sdl3.cpp
  2. 2 0
      docs/CHANGELOG.txt
  3. 1 1
      imgui.cpp

+ 32 - 10
backends/imgui_impl_sdl3.cpp

@@ -20,6 +20,7 @@
 
 // CHANGELOG
 // (minor and older changes stripped away, please see git history for details)
+//  2025-11-05: Fixed an issue with missing characters events when an already active text field changes viewports. (#9054)
 //  2025-10-22: Fixed Platform_OpenInShellFn() return value (unused in core).
 //  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: Call platform_io.ClearPlatformHandlers() on shutdown.
@@ -112,6 +113,8 @@ struct ImGui_ImplSDL3_Data
 
     // IME handling
     SDL_Window*             ImeWindow;
+    ImGuiPlatformImeData    ImeData;
+    bool                    ImeDirty;
 
     // Mouse handling
     Uint32                  MouseWindowID;
@@ -139,6 +142,9 @@ static ImGui_ImplSDL3_Data* ImGui_ImplSDL3_GetBackendData()
     return ImGui::GetCurrentContext() ? (ImGui_ImplSDL3_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
 }
 
+// Forward Declarations
+static void ImGui_ImplSDL3_UpdateIme();
+
 // Functions
 static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*)
 {
@@ -154,16 +160,38 @@ static void ImGui_ImplSDL3_SetClipboardText(ImGuiContext*, const char* text)
     SDL_SetClipboardText(text);
 }
 
-static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data)
+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()
 {
     ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
-    SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle;
-    SDL_Window* window = SDL_GetWindowFromID(window_id);
+    ImGuiPlatformImeData* data = &bd->ImeData;
+    SDL_Window* window = SDL_GetKeyboardFocus();
+
+    // Stop previous input
     if ((!(data->WantVisible || data->WantTextInput) || bd->ImeWindow != window) && bd->ImeWindow != nullptr)
     {
         SDL_StopTextInput(bd->ImeWindow);
         bd->ImeWindow = nullptr;
     }
+    if ((!bd->ImeDirty && bd->ImeWindow == window) || (window == NULL))
+        return;
+
+    // Start/update current input
+    bd->ImeDirty = false;
     if (data->WantVisible)
     {
         SDL_Rect r;
@@ -340,13 +368,6 @@ static void ImGui_ImplSDL3_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
     io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & SDL_KMOD_GUI) != 0);
 }
 
-
-static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id)
-{
-    ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
-    return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr;
-}
-
 // 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.
@@ -835,6 +856,7 @@ void ImGui_ImplSDL3_NewFrame()
 
     ImGui_ImplSDL3_UpdateMouseData();
     ImGui_ImplSDL3_UpdateMouseCursor();
+    ImGui_ImplSDL3_UpdateIme();
 
     // Update game controllers (if enabled and available)
     ImGui_ImplSDL3_UpdateGamepads();

+ 2 - 0
docs/CHANGELOG.txt

@@ -86,6 +86,8 @@ Other Changes:
     are not available. (#9024, #8969, #8921, #8920) [@jagot]
   - SDL3: fixed Platform_OpenInShellFn() return value (the return value
     was unused in core but might be used by a direct caller). (#9027) [@achabense]
+  - SDL3: fixed an issue with missing characters events when an already active text
+    field changes viewports. (#9054)
   - Vulkan: added IMGUI_IMPL_VULKAN_VOLK_FILENAME to configure path to
     Volk (default to "volk.h"). (#9008, #7722, #6582, #4854) [@mwlasiuk]
   - WebGPU: added various internal/optional helpers to wrap some of the

+ 1 - 1
imgui.cpp

@@ -5870,9 +5870,9 @@ void ImGui::EndFrame()
     ImGuiPlatformImeData* ime_data = &g.PlatformImeData;
     if (g.PlatformIO.Platform_SetImeDataFn != NULL && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0)
     {
-        IMGUI_DEBUG_LOG_IO("[io] Calling Platform_SetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y);
         IM_ASSERT(ime_data->ViewportId == IMGUI_VIEWPORT_DEFAULT_ID); // master branch
         ImGuiViewport* viewport = GetMainViewport();
+        IMGUI_DEBUG_LOG_IO("[io] Calling Platform_SetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f) for Viewport 0x%08X\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y, viewport->ID);
         g.PlatformIO.Platform_SetImeDataFn(&g, viewport, ime_data);
     }
     g.WantTextInputNextFrame = ime_data->WantTextInput ? 1 : 0;