Inputs, IO: reworked ImGuiMod_Shortcut to redirect to Ctrl/Super at runtime instead of compile-time. (#5923, #456)

This commit is contained in:
ocornut 2022-11-29 18:11:09 +01:00
parent 969af7c773
commit 1a497c2499
7 changed files with 27 additions and 18 deletions

View File

@ -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..) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features: // Implemented features:

View File

@ -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..) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features: // Implemented features:

View File

@ -57,6 +57,9 @@ Other changes:
frame (and associated lower-level functions e.g. ScrollToRectEx()) from not centering item. (#5902) 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 - Inputs: fixed moving a window or drag and dropping from preventing input-owner-unaware code
from accessing keys. (#5888, #4921, #456) 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) - 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 - 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) inside a collapsed/culled window and IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. (#5548, #5911)

View File

@ -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: fix AddRemapChar() to work before atlas has been built.
- font: (api breaking) remove "TTF" from symbol names. also because it now supports OTF. - 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: 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: 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) ! nav: never clear NavId on some setup (e.g. gamepad centric)

View File

@ -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(&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::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)); // 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. // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data.
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
@ -4241,7 +4242,6 @@ static void ImGui::UpdateKeyboardInputs()
#undef NAV_MAP_KEY #undef NAV_MAP_KEY
} }
#endif #endif
#endif #endif
// Synchronize io.KeyMods with individual modifiers io.KeyXXX bools, update aliases // 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]; 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) void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size)
{ {
ImGuiContext& g = *GImGui; 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", ImFormatString(out_buf, (size_t)out_buf_size, "%s%s%s%s%s",
(key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "", (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "",
(key_chord & ImGuiMod_Shift) ? "Shift+" : "", (key_chord & ImGuiMod_Shift) ? "Shift+" : "",
@ -8037,6 +8040,8 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable;
ImGuiKeyRoutingData* routing_data; ImGuiKeyRoutingData* routing_data;
if (key_chord & ImGuiMod_Shortcut)
key_chord = ConvertShortcutMod(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)
@ -8154,7 +8159,7 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id) bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id)
{ {
const ImGuiID routing_id = GetRoutingIdFromOwnerId(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; 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)) if (!SetShortcutRouting(key_chord, owner_id, flags))
return false; 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_); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
if (g.IO.KeyMods != mods) if (g.IO.KeyMods != mods)
return false; return false;
// Special storage location for mods // Special storage location for mods
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
if (key == ImGuiKey_None) if (key == ImGuiKey_None)
key = ConvertSingleModFlagToKey(mods); 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(). // 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 // 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. // 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. // while still correctly asserting on mid-frame key press events.
const ImGuiKeyChord key_mods = GetMergedModsFromBools(); 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"); IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");

14
imgui.h
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.2 WIP" #define IMGUI_VERSION "1.89.2 WIP"
#define IMGUI_VERSION_NUM 18911 #define IMGUI_VERSION_NUM 18912
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
/* /*
@ -1431,7 +1431,7 @@ enum ImGuiKey : int
ImGuiKey_GamepadRStickUp, // [Analog] ImGuiKey_GamepadRStickUp, // [Analog]
ImGuiKey_GamepadRStickDown, // [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. // - 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, 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_Shift = 1 << 13,
ImGuiMod_Alt = 1 << 14, // Option/Menu ImGuiMod_Alt = 1 << 14, // Option/Menu
ImGuiMod_Super = 1 << 15, // Cmd/Super/Windows ImGuiMod_Super = 1 << 15, // Cmd/Super/Windows
ImGuiMod_Mask_ = 0xF000, ImGuiMod_Shortcut = 1 << 11, // [Internal, read-only] Alias of ImGuiMod_Super (macOS) or ImGuiMod_Ctrl (otherwise), decided by io.ConfigMacOSXBehaviors.
#if defined(__APPLE__) ImGuiMod_Mask_ = 0xF800, // 5-bits
ImGuiMod_Shortcut = ImGuiMod_Super,
#else
ImGuiMod_Shortcut = ImGuiMod_Ctrl,
#endif
// [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array. // [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) // 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 bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows
// Other state maintained from data above + IO function calls // 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. 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. 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) ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)

View File

@ -1295,7 +1295,7 @@ typedef ImS16 ImGuiKeyRoutingIndex;
struct ImGuiKeyRoutingData struct ImGuiKeyRoutingData
{ {
ImGuiKeyRoutingIndex NextEntryIndex; 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) ImU8 RoutingNextScore; // Lower is better (0: perfect score)
ImGuiID RoutingCurr; ImGuiID RoutingCurr;
ImGuiID RoutingNext; ImGuiID RoutingNext;
@ -2864,18 +2864,21 @@ namespace ImGui
// Inputs // Inputs
// FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. // 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 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 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 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 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 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 ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key) inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key)
{ {
ImGuiContext& g = *GImGui;
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;
if (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper; if (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper;
if (key == ImGuiMod_Shortcut) return (g.IO.ConfigMacOSXBehaviors ? ImGuiKey_ReservedForModSuper : ImGuiKey_ReservedForModCtrl);
return key; return key;
} }