IO: Filter duplicate input events during the AddXXX() calls. (#5599, #4921)

This commit is contained in:
ocornut 2022-09-29 21:59:32 +02:00
parent fac8295d6e
commit cc5058e5d7
3 changed files with 54 additions and 17 deletions

View File

@ -130,6 +130,7 @@ Other Changes:
- IO: Added ImGuiMod_Shortcut which is ImGuiMod_Super on Mac and ImGuiMod_Ctrl otherwise. (#456) - 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 - IO: Added ImGuiKey_MouseXXX aliases for mouse buttons/wheel so all operations done on ImGuiKey
can apply to mouse data as well. (#4921) 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. - 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 Among other things, it would accidentally break part of the closing heuristic logic when moving
towards a sub-menu. (#2517, #5614). [@rokups] towards a sub-menu. (#2517, #5614). [@rokups]

View File

@ -1282,11 +1282,13 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
} }
} }
// FIXME: Perhaps we could clear queued events as well?
void ImGuiIO::ClearInputCharacters() void ImGuiIO::ClearInputCharacters()
{ {
InputQueueCharacters.resize(0); InputQueueCharacters.resize(0);
} }
// FIXME: Perhaps we could clear queued events as well?
void ImGuiIO::ClearInputKeys() void ImGuiIO::ClearInputKeys()
{ {
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
@ -1302,6 +1304,23 @@ void ImGuiIO::ClearInputKeys()
KeyMods = ImGuiMod_None; 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. // 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) // - 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. // - 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)) if (ImGui::IsGamepadKey(key))
BackendUsingLegacyNavInputArray = false; 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) // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed)
ImGuiKeyData* key_data = ImGui::GetKeyData(key); const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Key, (int)key);
if (key_data->Down == down && key_data->AnalogValue == analog_value) const ImGuiKeyData* key_data = ImGui::GetKeyData(key);
{ const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down;
bool found = false; const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue;
for (int n = g.InputEventsQueue.Size - 1; n >= 0 && !found; n--) if (latest_key_down == down && latest_key_analog == analog_value)
if (g.InputEventsQueue[n].Type == ImGuiInputEventType_Key && g.InputEventsQueue[n].Key.Key == key) return;
found = true;
if (!found)
return;
}
// Add event // Add event
ImGuiInputEvent e; ImGuiInputEvent e;
@ -1395,11 +1410,20 @@ void ImGuiIO::AddMousePosEvent(float x, float y)
if (!AppAcceptingEvents) if (!AppAcceptingEvents)
return; 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; ImGuiInputEvent e;
e.Type = ImGuiInputEventType_MousePos; e.Type = ImGuiInputEventType_MousePos;
e.Source = ImGuiInputSource_Mouse; e.Source = ImGuiInputSource_Mouse;
e.MousePos.PosX = x; e.MousePos.PosX = pos.x;
e.MousePos.PosY = y; e.MousePos.PosY = pos.y;
g.InputEventsQueue.push_back(e); g.InputEventsQueue.push_back(e);
} }
@ -1411,6 +1435,12 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
if (!AppAcceptingEvents) if (!AppAcceptingEvents)
return; 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; ImGuiInputEvent e;
e.Type = ImGuiInputEventType_MouseButton; e.Type = ImGuiInputEventType_MouseButton;
e.Source = ImGuiInputSource_Mouse; e.Source = ImGuiInputSource_Mouse;
@ -1424,7 +1454,9 @@ void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context."); 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; return;
ImGuiInputEvent e; ImGuiInputEvent e;
@ -1440,6 +1472,12 @@ void ImGuiIO::AddFocusEvent(bool focused)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context."); 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; ImGuiInputEvent e;
e.Type = ImGuiInputEventType_Focus; e.Type = ImGuiInputEventType_Focus;
e.AppFocused.Focused = focused; 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 // Trickling Rule: Stop processing queued events if we already handled a mouse button change
ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY); 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)) if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted))
break; break;
io.MousePos = event_pos; io.MousePos = event_pos;

View File

@ -23,7 +23,7 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') // (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 "1.89 WIP"
#define IMGUI_VERSION_NUM 18827 #define IMGUI_VERSION_NUM 18828
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
/* /*