mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-24 05:19:02 +08:00
Shortcut: ImGuiInputFlags_RouteFocused policy can filter Shortcuts conflicting with character input when an item is active. (#456)
This commit is contained in:
parent
80d5cb1ab1
commit
5fdcdf7080
48
imgui.cpp
48
imgui.cpp
@ -3596,6 +3596,14 @@ void ImGui::Initialize()
|
||||
g.Viewports.push_back(viewport);
|
||||
g.TempBuffer.resize(1024 * 3 + 1, 0);
|
||||
|
||||
// Build KeysMayBeCharInput[] lookup table (1 bool per named key)
|
||||
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
|
||||
if ((key >= ImGuiKey_0 && key <= ImGuiKey_9) || (key >= ImGuiKey_A && key <= ImGuiKey_Z) || (key >= ImGuiKey_Keypad0 && key <= ImGuiKey_Keypad9)
|
||||
|| key == ImGuiKey_Tab || key == ImGuiKey_Space || key == ImGuiKey_Apostrophe || key == ImGuiKey_Comma || key == ImGuiKey_Minus || key == ImGuiKey_Period
|
||||
|| key == ImGuiKey_Slash || key == ImGuiKey_Semicolon || key == ImGuiKey_Equal || key == ImGuiKey_LeftBracket || key == ImGuiKey_RightBracket || key == ImGuiKey_GraveAccent
|
||||
|| key == ImGuiKey_KeypadDecimal || key == ImGuiKey_KeypadDivide || key == ImGuiKey_KeypadMultiply || key == ImGuiKey_KeypadSubtract || key == ImGuiKey_KeypadAdd || key == ImGuiKey_KeypadEqual)
|
||||
g.KeysMayBeCharInput.SetBit(key);
|
||||
|
||||
#ifdef IMGUI_HAS_DOCK
|
||||
#endif
|
||||
|
||||
@ -8308,13 +8316,11 @@ 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)
|
||||
key = ConvertSingleModFlagToKey(&g, mods);
|
||||
IM_ASSERT(IsNamedKey(key));
|
||||
IM_ASSERT(IsNamedKey(key) && (key_chord & ImGuiMod_Shortcut) == 0); // Please call ConvertShortcutMod() in calling function.
|
||||
|
||||
// Get (in the majority of case, the linked list will have one element so this should be 2 reads.
|
||||
// Subsequent elements will be contiguous in memory as list is sorted/rebuilt in NewFrame).
|
||||
@ -8378,6 +8384,24 @@ static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInput
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We need this to filter some Shortcut() routes when an item e.g. an InputText() is active
|
||||
// e.g. ImGuiKey_G won't be considered a shortcut when item is active, but ImGuiMod|ImGuiKey_G can be.
|
||||
static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord)
|
||||
{
|
||||
// Mimic 'ignore_char_inputs' logic in InputText()
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
// When the right mods are pressed it cannot be a char input so we won't filter the shortcut out.
|
||||
ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
|
||||
const bool ignore_char_inputs = ((mods & ImGuiMod_Ctrl) && !(mods & ImGuiMod_Alt)) || (g.IO.ConfigMacOSXBehaviors && (mods & ImGuiMod_Super));
|
||||
if (ignore_char_inputs)
|
||||
return false;
|
||||
|
||||
// Return true for A-Z, 0-9 and other keys associated to char inputs. Other keys such as F1-F12 won't be filtered.
|
||||
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
|
||||
return g.KeysMayBeCharInput.TestBit(key);
|
||||
}
|
||||
|
||||
// Request a desired route for an input chord (key + mods).
|
||||
// Return true if the route is available this frame.
|
||||
// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state.
|
||||
@ -8392,9 +8416,11 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
|
||||
flags |= ImGuiInputFlags_RouteGlobalHigh; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut()
|
||||
else
|
||||
IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used
|
||||
if (key_chord & ImGuiMod_Shortcut)
|
||||
key_chord = ConvertShortcutMod(key_chord);
|
||||
|
||||
// [DEBUG] Debug break requested by user
|
||||
if (g.DebugBreakInShortcutRouting != 0 && g.DebugBreakInShortcutRouting == ConvertShortcutMod(key_chord))
|
||||
if (g.DebugBreakInShortcutRouting == key_chord)
|
||||
IM_DEBUG_BREAK();
|
||||
|
||||
if (flags & ImGuiInputFlags_RouteUnlessBgFocused)
|
||||
@ -8408,6 +8434,18 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
|
||||
return true;
|
||||
}
|
||||
|
||||
// Specific culling for shortcuts with no modifiers when there's an active id.
|
||||
// e.g. Shortcut(ImGuiKey_G) also generates 'g' character, should not trigger when InputText() is active.
|
||||
// but Shortcut(Ctrl+G) should generally trigger when InputText() is active.
|
||||
// TL;DR: lettered shortcut with no mods or with only Alt mod will not trigger while an item reading text input is active.
|
||||
// (We cannot filter based on io.InputQueueCharacters[] contents because of trickling and key<>chars submission order are undefined)
|
||||
if ((flags & ImGuiInputFlags_RouteFocused) && (g.ActiveId != 0 && g.ActiveId != owner_id))
|
||||
if (g.IO.WantTextInput && IsKeyChordPotentiallyCharInput(key_chord))
|
||||
{
|
||||
IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, owner_id=0x%08X, flags=%04X) -> filtered as potential char input\n", GetKeyChordName(key_chord), owner_id, flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int score = CalcRoutingScore(g.CurrentFocusScopeId, owner_id, flags);
|
||||
IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, owner_id=0x%08X, flags=%04X) -> score %d\n", GetKeyChordName(key_chord), owner_id, flags, score);
|
||||
if (score == 255)
|
||||
@ -8435,6 +8473,8 @@ 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);
|
||||
if (key_chord & ImGuiMod_Shortcut)
|
||||
key_chord = ConvertShortcutMod(key_chord);
|
||||
ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry.
|
||||
return routing_data->RoutingCurr == routing_id;
|
||||
}
|
||||
|
2
imgui.h
2
imgui.h
@ -24,7 +24,7 @@
|
||||
// Library Version
|
||||
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
|
||||
#define IMGUI_VERSION "1.90.2 WIP"
|
||||
#define IMGUI_VERSION_NUM 19012
|
||||
#define IMGUI_VERSION_NUM 19013
|
||||
#define IMGUI_HAS_TABLE
|
||||
|
||||
/*
|
||||
|
@ -1974,6 +1974,7 @@ struct ImGuiContext
|
||||
double LastKeyModsChangeTime; // Record the last time key mods changed (affect repeat delay when using shortcut logic)
|
||||
double LastKeyModsChangeFromNoneTime; // Record the last time key mods changed away from being 0 (affect repeat delay when using shortcut logic)
|
||||
double LastKeyboardKeyPressTime; // Record the last time a keyboard key (ignore mouse/gamepad ones) was pressed.
|
||||
ImBitArrayForNamedKeys KeysMayBeCharInput; // Lookup to tell if a key can emit char input, see IsKeyChordPotentiallyCharInput(). sizeof() = 20 bytes
|
||||
ImGuiKeyOwnerData KeysOwnerData[ImGuiKey_NamedKey_COUNT];
|
||||
ImGuiKeyRoutingTable KeysRoutingTable;
|
||||
ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it)
|
||||
|
Loading…
Reference in New Issue
Block a user