From 5aa7d61139b8857f413d72ada13618e0a9e9dc55 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Mar 2026 20:33:18 +0100 Subject: [PATCH] InputText: reworked so that io.ConfigInputTextEnterKeepActive reactivate in order for e.g. IsItemDeactivatedAfterEdit() to work. Amends. (#9001, #9115) Rework. Fixes dangling InputTextReactivateId in case of field being hidden on activation. --- imgui.cpp | 4 +++- imgui.h | 2 +- imgui_demo.cpp | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 16 ++++------------ 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b88ff1d80..3638f6bfb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4281,7 +4281,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) MouseStationaryTimer = 0.0f; InputTextPasswordFontBackupFlags = ImFontFlags_None; - InputTextReactivateID = 0; + InputTextReactivateId = 0; TempInputId = 0; memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue)); BeginMenuDepth = BeginComboDepth = 0; @@ -5573,6 +5573,8 @@ void ImGui::NewFrame() g.ActiveIdIsJustActivated = false; if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) g.TempInputId = 0; + if (g.InputTextReactivateId != 0 && g.InputTextReactivateId != g.DeactivatedItemData.ID) + g.InputTextReactivateId = 0; if (g.ActiveId == 0) { g.ActiveIdUsingNavDirMask = 0x00; diff --git a/imgui.h b/imgui.h index eca23ac18..cc82c5f3d 100644 --- a/imgui.h +++ b/imgui.h @@ -2428,7 +2428,7 @@ struct ImGuiIO bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). - bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). + bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only). bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index da8a78f81..d7dc0b028 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -526,7 +526,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); - ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); + ImGui::SameLine(); HelpMarker("Pressing Enter will reactivate item and select all text (single-line only)."); ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); diff --git a/imgui_internal.h b/imgui_internal.h index 3cfac423f..c54040747 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2461,7 +2461,7 @@ struct ImGuiContext ImGuiInputTextDeactivatedState InputTextDeactivatedState; ImFontBaked InputTextPasswordFontBackupBaked; ImFontFlags InputTextPasswordFontBackupFlags; - ImGuiID InputTextReactivateID; // ID of InputText to reactivate on next frame (for ConfigInputTextEnterKeepActive behavior) + ImGuiID InputTextReactivateId; // ID of InputText to reactivate on next frame (for io.ConfigInputTextEnterKeepActive behavior) ImGuiID TempInputId; // Temporary text input when using Ctrl+Click on a slider, etc. ImGuiDataTypeStorage DataTypeZeroValue; // 0 for all data types int BeginMenuDepth; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 355b63a77..78fae523b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4761,12 +4761,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ wrap_width = ImMax(1.0f, GetContentRegionAvail().x + (draw_window->ScrollbarY ? 0.0f : -g.Style.ScrollbarSize)); const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); - - // Check if this InputText should be reactivated (for ConfigInputTextEnterKeepActive) - const bool input_requested_by_reactivate = (g.InputTextReactivateID == id); - if (input_requested_by_reactivate) - g.InputTextReactivateID = 0; // Clear the flag - + const bool input_requested_by_reactivate = (g.InputTextReactivateId == id); // for io.ConfigInputTextEnterKeepActive const bool user_clicked = hovered && io.MouseClicked[0]; const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); @@ -5114,16 +5109,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ bool is_new_line = is_multiline && !is_gamepad_validate && (is_shift_enter || (is_enter && !ctrl_enter_for_new_line) || (is_ctrl_enter && ctrl_enter_for_new_line)); if (!is_new_line) { - validated = true; + validated = clear_active_id = true; if (io.ConfigInputTextEnterKeepActive && !is_multiline) { - // Deactivate for one frame to trigger IsItemDeactivatedAfterEdit(), then reactivate + // Queue reactivation, so that e.g. IsItemDeactivatedAfterEdit() will work. (#9001) state->SelectAll(); // No need to scroll - clear_active_id = true; - g.InputTextReactivateID = id; // Mark for reactivation on next frame + g.InputTextReactivateId = id; // Mark for reactivation on next frame } - else - clear_active_id = true; } else if (!is_readonly) {