From e55a0ef107c97f61266c9ab7dd7449edfa91430d Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Mar 2023 14:25:34 +0100 Subject: [PATCH] IO: avoid changing context in AddKeyAnalogEvent(). Amend 7269498. (#6199, #6256, #4921, #5856) --- imgui.cpp | 40 ++++++++++++++++++++-------------------- imgui.h | 2 +- imgui_internal.h | 9 +++++---- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c86e04087..43d2d9dac 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1370,6 +1370,8 @@ static ImGuiInputEvent* FindLatestInputEvent(ImGuiContext* ctx, ImGuiInputEventT // - 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. // - float analog_value: 0.0f..1.0f +// IMPORTANT: THIS FUNCTION AND OTHER "ADD" GRABS THE CONTEXT FROM OUR INSTANCE. +// WE NEED TO ENSURE THAT ALL FUNCTION CALLS ARE FULLFILLING THIS, WHICH IS WHY GetKeyData() HAS AN EXPLICIT CONTEXT. void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) { //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); } @@ -1378,7 +1380,7 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) return; ImGuiContext& g = *Ctx; IM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API. - IM_ASSERT(!ImGui::IsAliasKey(key)); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events. + IM_ASSERT(ImGui::IsAliasKey(key) == false); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events. IM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself) // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data. @@ -1394,10 +1396,7 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed) const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key); - ImGuiContext* prev_ctx = GImGui; - ImGui::SetCurrentContext(Ctx); - const ImGuiKeyData* key_data = ImGui::GetKeyData(key); - ImGui::SetCurrentContext(prev_ctx); + const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, 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) @@ -7729,13 +7728,13 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) // - Shortcut() [Internal] //----------------------------------------------------------------------------- -ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key) +ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key) { - ImGuiContext& g = *GImGui; + ImGuiContext& g = *ctx; // Special storage location for mods if (key & ImGuiMod_Mask_) - key = ConvertSingleModFlagToKey(key); + key = ConvertSingleModFlagToKey(ctx, key); #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END); @@ -7784,22 +7783,22 @@ IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames)); const char* ImGui::GetKeyName(ImGuiKey key) { + ImGuiContext& g = *GImGui; #ifdef IMGUI_DISABLE_OBSOLETE_KEYIO IM_ASSERT((IsNamedKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); #else if (IsLegacyKey(key)) { - ImGuiIO& io = GetIO(); - if (io.KeyMap[key] == -1) + if (g.IO.KeyMap[key] == -1) return "N/A"; - IM_ASSERT(IsNamedKey((ImGuiKey)io.KeyMap[key])); - key = (ImGuiKey)io.KeyMap[key]; + IM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key])); + key = (ImGuiKey)g.IO.KeyMap[key]; } #endif if (key == ImGuiKey_None) return "None"; if (key & ImGuiMod_Mask_) - key = ConvertSingleModFlagToKey(key); + key = ConvertSingleModFlagToKey(&g, key); if (!IsNamedKey(key)) return "Unknown"; @@ -7894,7 +7893,7 @@ static void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt) // Apply routing to owner if there's no owner already (RoutingCurr == None at this point) if (routing_entry->Mods == g.IO.KeyMods) { - ImGuiKeyOwnerData* owner_data = ImGui::GetKeyOwnerData(key); + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); if (owner_data->OwnerCurr == ImGuiKeyOwner_None) owner_data->OwnerCurr = routing_entry->RoutingCurr; } @@ -7931,7 +7930,7 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord) ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); if (key == ImGuiKey_None) - key = ConvertSingleModFlagToKey(mods); + key = ConvertSingleModFlagToKey(&g, mods); IM_ASSERT(IsNamedKey(key)); // Get (in the majority of case, the linked list will have one element so this should be 2 reads. @@ -8801,7 +8800,7 @@ ImGuiID ImGui::GetKeyOwner(ImGuiKey key) return ImGuiKeyOwner_None; ImGuiContext& g = *GImGui; - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); ImGuiID owner_id = owner_data->OwnerCurr; if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any) @@ -8825,7 +8824,7 @@ bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id) if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END) return false; - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); if (owner_id == ImGuiKeyOwner_Any) return (owner_data->LockThisFrame == false); @@ -8853,7 +8852,8 @@ void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) IM_ASSERT(IsNamedKeyOrModKey(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it) IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function! - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); + ImGuiContext& g = *GImGui; + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); owner_data->OwnerCurr = owner_data->OwnerNext = owner_id; // We cannot lock by default as it would likely break lots of legacy code. @@ -8902,7 +8902,7 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags // Special storage location for mods ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); if (key == ImGuiKey_None) - key = ConvertSingleModFlagToKey(mods); + key = ConvertSingleModFlagToKey(&g, mods); if (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateMask_)))) return false; @@ -13728,7 +13728,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) { for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); if (owner_data->OwnerCurr == ImGuiKeyOwner_None) continue; Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr, diff --git a/imgui.h b/imgui.h index a2522aef6..6c05effc9 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.5 WIP" -#define IMGUI_VERSION_NUM 18942 +#define IMGUI_VERSION_NUM 18943 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index d74b89ed3..714544f34 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2897,9 +2897,9 @@ namespace ImGui inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; } inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; } inline ImGuiKeyChord ConvertShortcutMod(ImGuiKeyChord key_chord) { ImGuiContext& g = *GImGui; IM_ASSERT_PARANOID(key_chord & ImGuiMod_Shortcut); return (key_chord & ~ImGuiMod_Shortcut) | (g.IO.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl); } - inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key) + inline ImGuiKey ConvertSingleModFlagToKey(ImGuiContext* ctx, ImGuiKey key) { - ImGuiContext& g = *GImGui; + ImGuiContext& g = *ctx; if (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl; if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift; if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt; @@ -2908,7 +2908,8 @@ namespace ImGui return key; } - IMGUI_API ImGuiKeyData* GetKeyData(ImGuiKey key); + IMGUI_API ImGuiKeyData* GetKeyData(ImGuiContext* ctx, ImGuiKey key); + inline ImGuiKeyData* GetKeyData(ImGuiKey key) { ImGuiContext& g = *GImGui; return GetKeyData(&g, key); } IMGUI_API void GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size); inline ImGuiKey MouseButtonToKey(ImGuiMouseButton button) { IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); return (ImGuiKey)(ImGuiKey_MouseLeft + button); } IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); @@ -2934,7 +2935,7 @@ namespace ImGui IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0); IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags = 0); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id); // Test that key is either not owned, either owned by 'owner_id' - inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); IM_ASSERT(IsNamedKey(key)); return &GImGui->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; } + inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(ctx, key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; } // [EXPERIMENTAL] High-Level: Input Access functions w/ support for Key/Input Ownership // - Important: legacy IsKeyPressed(ImGuiKey, bool repeat=true) _DEFAULTS_ to repeat, new IsKeyPressed() requires _EXPLICIT_ ImGuiInputFlags_Repeat flag.