IO: avoid changing context in AddKeyAnalogEvent(). Amend 7269498. (#6199, #6256, #4921, #5856)

This commit is contained in:
ocornut 2023-03-21 14:25:34 +01:00
parent 7269498ecc
commit e55a0ef107
3 changed files with 26 additions and 25 deletions

View File

@ -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) // - 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.
// - float analog_value: 0.0f..1.0f // - 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) 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); } //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; return;
ImGuiContext& g = *Ctx; 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::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) 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. // 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) // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed)
const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key); const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key);
ImGuiContext* prev_ctx = GImGui; const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key);
ImGui::SetCurrentContext(Ctx);
const ImGuiKeyData* key_data = ImGui::GetKeyData(key);
ImGui::SetCurrentContext(prev_ctx);
const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down; 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; const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue;
if (latest_key_down == down && latest_key_analog == analog_value) 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] // - 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 // Special storage location for mods
if (key & ImGuiMod_Mask_) if (key & ImGuiMod_Mask_)
key = ConvertSingleModFlagToKey(key); key = ConvertSingleModFlagToKey(ctx, key);
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END); 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) const char* ImGui::GetKeyName(ImGuiKey key)
{ {
ImGuiContext& g = *GImGui;
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO #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."); 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 #else
if (IsLegacyKey(key)) if (IsLegacyKey(key))
{ {
ImGuiIO& io = GetIO(); if (g.IO.KeyMap[key] == -1)
if (io.KeyMap[key] == -1)
return "N/A"; return "N/A";
IM_ASSERT(IsNamedKey((ImGuiKey)io.KeyMap[key])); IM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key]));
key = (ImGuiKey)io.KeyMap[key]; key = (ImGuiKey)g.IO.KeyMap[key];
} }
#endif #endif
if (key == ImGuiKey_None) if (key == ImGuiKey_None)
return "None"; return "None";
if (key & ImGuiMod_Mask_) if (key & ImGuiMod_Mask_)
key = ConvertSingleModFlagToKey(key); key = ConvertSingleModFlagToKey(&g, key);
if (!IsNamedKey(key)) if (!IsNamedKey(key))
return "Unknown"; 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) // Apply routing to owner if there's no owner already (RoutingCurr == None at this point)
if (routing_entry->Mods == g.IO.KeyMods) 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) if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
owner_data->OwnerCurr = routing_entry->RoutingCurr; owner_data->OwnerCurr = routing_entry->RoutingCurr;
} }
@ -7931,7 +7930,7 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
if (key == ImGuiKey_None) if (key == ImGuiKey_None)
key = ConvertSingleModFlagToKey(mods); key = ConvertSingleModFlagToKey(&g, mods);
IM_ASSERT(IsNamedKey(key)); IM_ASSERT(IsNamedKey(key));
// Get (in the majority of case, the linked list will have one element so this should be 2 reads. // 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; return ImGuiKeyOwner_None;
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
ImGuiID owner_id = owner_data->OwnerCurr; ImGuiID owner_id = owner_data->OwnerCurr;
if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any) 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) if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END)
return false; return false;
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
if (owner_id == ImGuiKeyOwner_Any) if (owner_id == ImGuiKeyOwner_Any)
return (owner_data->LockThisFrame == false); 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(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! 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; owner_data->OwnerCurr = owner_data->OwnerNext = owner_id;
// We cannot lock by default as it would likely break lots of legacy code. // 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 // Special storage location for mods
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
if (key == ImGuiKey_None) if (key == ImGuiKey_None)
key = ConvertSingleModFlagToKey(mods); key = ConvertSingleModFlagToKey(&g, mods);
if (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateMask_)))) if (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateMask_))))
return false; 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)) 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) if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
continue; continue;
Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr, Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr,

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.5 WIP" #define IMGUI_VERSION "1.89.5 WIP"
#define IMGUI_VERSION_NUM 18942 #define IMGUI_VERSION_NUM 18943
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
/* /*

View File

@ -2897,9 +2897,9 @@ namespace ImGui
inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; } 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 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 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_Ctrl) return ImGuiKey_ReservedForModCtrl;
if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift; if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift;
if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt; if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt;
@ -2908,7 +2908,8 @@ namespace ImGui
return key; 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); 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); } 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); 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 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 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' 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 // [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. // - Important: legacy IsKeyPressed(ImGuiKey, bool repeat=true) _DEFAULTS_ to repeat, new IsKeyPressed() requires _EXPLICIT_ ImGuiInputFlags_Repeat flag.