From 1a497c249958ab24fb471216b7747716709db62c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Nov 2022 18:11:09 +0100 Subject: [PATCH] Inputs, IO: reworked ImGuiMod_Shortcut to redirect to Ctrl/Super at runtime instead of compile-time. (#5923, #456) --- backends/imgui_impl_win32.cpp | 2 +- backends/imgui_impl_win32.h | 2 +- docs/CHANGELOG.txt | 3 +++ docs/TODO.txt | 2 +- imgui.cpp | 15 +++++++++++---- imgui.h | 14 +++++--------- imgui_internal.h | 7 +++++-- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index a4660afd..b7b941fd 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -1,4 +1,4 @@ -// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications) +// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // Implemented features: diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h index 082461dd..b74b4387 100644 --- a/backends/imgui_impl_win32.h +++ b/backends/imgui_impl_win32.h @@ -1,4 +1,4 @@ -// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications) +// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // Implemented features: diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 00acc1dd..441b29ee 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,6 +57,9 @@ Other changes: frame (and associated lower-level functions e.g. ScrollToRectEx()) from not centering item. (#5902) - Inputs: fixed moving a window or drag and dropping from preventing input-owner-unaware code from accessing keys. (#5888, #4921, #456) +- Inputs, IO: reworked ImGuiMod_Shortcut to redirect to Ctrl/Super at runtime instead of + compile-time, being consistent with our support for io.ConfigMacOSXBehaviors and making it + easier for bindings generators to process that value. (#5923, #456) - Inputs: fixed moving a window or drag and dropping from capturing mods. (#5888, #4921, #456) - Layout: fixed End()/EndChild() incorrectly asserting if users manipulates cursor position inside a collapsed/culled window and IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. (#5548, #5911) diff --git a/docs/TODO.txt b/docs/TODO.txt index cb7e6be7..b2d35c27 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -294,7 +294,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font: fix AddRemapChar() to work before atlas has been built. - font: (api breaking) remove "TTF" from symbol names. also because it now supports OTF. - font/opt: Considering storing standalone AdvanceX table as 16-bit fixed point integer? - - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16 bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? + - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16-bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? - nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line? how about CTRL+Tab) ! nav: never clear NavId on some setup (e.g. gamepad centric) diff --git a/imgui.cpp b/imgui.cpp index 4eded91d..03ea973d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1343,6 +1343,7 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) IM_ASSERT(&g.IO == this && "Can only add events to current context."); 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(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. #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO @@ -4241,7 +4242,6 @@ static void ImGui::UpdateKeyboardInputs() #undef NAV_MAP_KEY } #endif - #endif // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools, update aliases @@ -7959,9 +7959,12 @@ const char* ImGui::GetKeyName(ImGuiKey key) return GKeyNames[key - ImGuiKey_NamedKey_BEGIN]; } +// ImGuiMod_Shortcut is translated to either Ctrl or Super. void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size) { ImGuiContext& g = *GImGui; + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); ImFormatString(out_buf, (size_t)out_buf_size, "%s%s%s%s%s", (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "", (key_chord & ImGuiMod_Shift) ? "Shift+" : "", @@ -8037,6 +8040,8 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord) ImGuiContext& g = *GImGui; ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; ImGuiKeyRoutingData* routing_data; + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); if (key == ImGuiKey_None) @@ -8154,7 +8159,7 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id) { const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); - ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); + ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry. return routing_data->RoutingCurr == routing_id; } @@ -8645,12 +8650,14 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags if (!SetShortcutRouting(key_chord, owner_id, flags)) return false; - ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); if (g.IO.KeyMods != mods) return false; // Special storage location for mods + ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); if (key == ImGuiKey_None) key = ConvertSingleModFlagToKey(mods); @@ -8766,7 +8773,7 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame(). // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. - // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), + // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), // while still correctly asserting on mid-frame key press events. const ImGuiKeyChord key_mods = GetMergedModsFromBools(); IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); diff --git a/imgui.h b/imgui.h index aa58b32c..ac5fed93 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.2 WIP" -#define IMGUI_VERSION_NUM 18911 +#define IMGUI_VERSION_NUM 18912 #define IMGUI_HAS_TABLE /* @@ -1431,7 +1431,7 @@ enum ImGuiKey : int ImGuiKey_GamepadRStickUp, // [Analog] ImGuiKey_GamepadRStickDown, // [Analog] - // Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) + // Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API. ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY, @@ -1452,12 +1452,8 @@ enum ImGuiKey : int ImGuiMod_Shift = 1 << 13, ImGuiMod_Alt = 1 << 14, // Option/Menu ImGuiMod_Super = 1 << 15, // Cmd/Super/Windows - ImGuiMod_Mask_ = 0xF000, -#if defined(__APPLE__) - ImGuiMod_Shortcut = ImGuiMod_Super, -#else - ImGuiMod_Shortcut = ImGuiMod_Ctrl, -#endif + ImGuiMod_Shortcut = 1 << 11, // [Internal, read-only] Alias of ImGuiMod_Super (macOS) or ImGuiMod_Ctrl (otherwise), decided by io.ConfigMacOSXBehaviors. + ImGuiMod_Mask_ = 0xF800, // 5-bits // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array. // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) @@ -2028,7 +2024,7 @@ struct ImGuiIO bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows // Other state maintained from data above + IO function calls - ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags). Read-only, updated by NewFrame() + ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. DOES NOT CONTAINS ImGuiMod_Shortcut which is pretranslated). Read-only, updated by NewFrame() ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this. bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) diff --git a/imgui_internal.h b/imgui_internal.h index 7fd26e54..9a26f3f1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1295,7 +1295,7 @@ typedef ImS16 ImGuiKeyRoutingIndex; struct ImGuiKeyRoutingData { ImGuiKeyRoutingIndex NextEntryIndex; - ImU16 Mods; // Technically we'd only need 4 bits but for simplify we store ImGuiMod_ values which need 16 bits. + ImU16 Mods; // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits. ImGuiMod_Shortcut is already translated to Ctrl/Super. ImU8 RoutingNextScore; // Lower is better (0: perfect score) ImGuiID RoutingCurr; ImGuiID RoutingNext; @@ -2864,18 +2864,21 @@ namespace ImGui // Inputs // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. inline bool IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; } - inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super; } + inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super || key == ImGuiMod_Shortcut; } inline bool IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; } inline bool IsKeyboardKey(ImGuiKey key) { return key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END; } inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_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 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) { + ImGuiContext& g = *GImGui; if (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl; if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift; if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt; if (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper; + if (key == ImGuiMod_Shortcut) return (g.IO.ConfigMacOSXBehaviors ? ImGuiKey_ReservedForModSuper : ImGuiKey_ReservedForModCtrl); return key; }