diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 622bb289..f0a2fb5a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -130,6 +130,7 @@ Other Changes: - IO: Added ImGuiMod_Shortcut which is ImGuiMod_Super on Mac and ImGuiMod_Ctrl otherwise. (#456) - IO: Added ImGuiKey_MouseXXX aliases for mouse buttons/wheel so all operations done on ImGuiKey can apply to mouse data as well. (#4921) +- IO: Filter duplicate input events during the AddXXX() calls. (#5599, #4921) - Menus: Fixed incorrect sub-menu parent association when opening a menu by closing another. Among other things, it would accidentally break part of the closing heuristic logic when moving towards a sub-menu. (#2517, #5614). [@rokups] diff --git a/imgui.cpp b/imgui.cpp index 4390d158..1304170d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1282,11 +1282,13 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) } } +// FIXME: Perhaps we could clear queued events as well? void ImGuiIO::ClearInputCharacters() { InputQueueCharacters.resize(0); } +// FIXME: Perhaps we could clear queued events as well? void ImGuiIO::ClearInputKeys() { #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO @@ -1302,6 +1304,23 @@ void ImGuiIO::ClearInputKeys() KeyMods = ImGuiMod_None; } +static ImGuiInputEvent* FindLatestInputEvent(ImGuiInputEventType type, int arg = -1) +{ + ImGuiContext& g = *GImGui; + for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--) + { + ImGuiInputEvent* e = &g.InputEventsQueue[n]; + if (e->Type != type) + continue; + if (type == ImGuiInputEventType_Key && e->Key.Key != arg) + continue; + if (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg) + continue; + return e; + } + return NULL; +} + // Queue a new key down/up event. // - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) // - bool down: Is the key down? use false to signify a key release. @@ -1327,17 +1346,13 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) if (ImGui::IsGamepadKey(key)) BackendUsingLegacyNavInputArray = false; - // Partial filter of duplicates (not strictly needed, but makes data neater in particular for key mods and gamepad values which are most commonly spmamed) - ImGuiKeyData* key_data = ImGui::GetKeyData(key); - if (key_data->Down == down && key_data->AnalogValue == analog_value) - { - bool found = false; - for (int n = g.InputEventsQueue.Size - 1; n >= 0 && !found; n--) - if (g.InputEventsQueue[n].Type == ImGuiInputEventType_Key && g.InputEventsQueue[n].Key.Key == key) - found = true; - if (!found) - return; - } + // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed) + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Key, (int)key); + const ImGuiKeyData* key_data = ImGui::GetKeyData(key); + const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down; + const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue; + if (latest_key_down == down && latest_key_analog == analog_value) + return; // Add event ImGuiInputEvent e; @@ -1395,11 +1410,20 @@ void ImGuiIO::AddMousePosEvent(float x, float y) if (!AppAcceptingEvents) return; + // Apply same flooring as UpdateMouseInputs() + ImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y); + + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MousePos); + const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos; + if (latest_pos.x == pos.x && latest_pos.y == pos.y) + return; + ImGuiInputEvent e; e.Type = ImGuiInputEventType_MousePos; e.Source = ImGuiInputSource_Mouse; - e.MousePos.PosX = x; - e.MousePos.PosY = y; + e.MousePos.PosX = pos.x; + e.MousePos.PosY = pos.y; g.InputEventsQueue.push_back(e); } @@ -1411,6 +1435,12 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) if (!AppAcceptingEvents) return; + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MouseButton, (int)mouse_button); + const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button]; + if (latest_button_down == down) + return; + ImGuiInputEvent e; e.Type = ImGuiInputEventType_MouseButton; e.Source = ImGuiInputSource_Mouse; @@ -1424,7 +1454,9 @@ void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) { ImGuiContext& g = *GImGui; IM_ASSERT(&g.IO == this && "Can only add events to current context."); - if ((wheel_x == 0.0f && wheel_y == 0.0f) || !AppAcceptingEvents) + + // Filter duplicate (unlike most events, wheel values are relative and easy to filter) + if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f)) return; ImGuiInputEvent e; @@ -1440,6 +1472,12 @@ void ImGuiIO::AddFocusEvent(bool focused) ImGuiContext& g = *GImGui; IM_ASSERT(&g.IO == this && "Can only add events to current context."); + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Focus); + const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost; + if (latest_focused == focused) + return; + ImGuiInputEvent e; e.Type = ImGuiInputEventType_Focus; e.AppFocused.Focused = focused; @@ -8123,8 +8161,6 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) { // Trickling Rule: Stop processing queued events if we already handled a mouse button change ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY); - if (IsMousePosValid(&event_pos)) - event_pos = ImVec2(ImFloorSigned(event_pos.x), ImFloorSigned(event_pos.y)); // Apply same flooring as UpdateMouseInputs() if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted)) break; io.MousePos = event_pos; diff --git a/imgui.h b/imgui.h index 33270458..acdb73ed 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') #define IMGUI_VERSION "1.89 WIP" -#define IMGUI_VERSION_NUM 18827 +#define IMGUI_VERSION_NUM 18828 #define IMGUI_HAS_TABLE /*