-
-
Notifications
You must be signed in to change notification settings - Fork 9.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Input routing / Fine-grained input usage reporting #2637
Comments
Apologies for not answering this earlier. This is an important topic and I will want to address this seriously at some point (i'm just a little overwhelmed at the moment!), but various teams have raised similar questions and I'll come in the agenda. Any other feedback/suggestions welcome in the meanwhile! |
I've been looking at this lately along with other scenarios of input routing, and been working on a system of tracking key ownership (in fact the need to unify some input enums which led to 1.87 came from this). So hopefully I'll come back with some ideas. I realize this is not the right/ideal answer but the issues presented are most often mitigated or worked around by gating input checks behind certain states e.g. |
There is a rather tricky flaw/issue in the solution I have been working on, but I'm still very much exploring this. |
Just wondering here, but should The menubar item has that built-in shortcut string, but I assume that's just cosmetic. I think an interesting possibility would be the registration of key bindings to IDs. Something like this in setup/initialization, and shutdown:
And let ImGui internally check if a widget needs to be triggered (e.g. has focus, io.WantCaptureKeyboard is true, so return true if shortcut pressed). Edit:
|
Yes sorry, that was a leftover of me tweaking things for debugging.
It will become not just cosmetic via the addition of an opt-in flag to BeginMenuBar/BeginMenu to actually enable interpret those shortcuts. When using this flag menu code can eventually run while menu is hidden.
You are described a retained API which will be possible to add on end-user side but is something we would try to avoid in imgui core. The equivalent to your idea of registering to activate a "remote" item would be something like:
Which can also be wrapped as one-liner, and wouldn't require a registration. |
…2891, #3370, #4828, #5108, #5242, #5641) - Added SetKeyOwner(), SetItemKeyOwner(), TestKeyOwner(). - Added new IsKeyXXX IsMouseXXX functions with ImGuID owner_id and flags. - Obsoleted SetItemUsingMouseWheel(). (#2891) - Removed IsKeyPresseedEx() which was a recent internal addition 2022-07-08 deemed to be temporary exactly for this. - Added ImGuiButtonFlags_NoSetKeyOwner, ImGuiButtonFlags_NoTestKeyOwner - Added ImGuiSelectableFlags_NoSetKeyOwner. - Added ImGuiInputFlags_LockThisFrame, ImGuiInputFlags_LockUntilRelease for for SetKeyOwner(), SetItemKeyOwner(). - Added ImGuiInputFlags_CondXXX values for SetItemKeyOwner().
FYI today pushed several commits related to this. The key features answering the things raised by this specific issue is the shortcut routing system. // [EXPERIMENTAL] Shortcut Routing
// - ImGuiKeyChord = a ImGuiKey optionally OR-red with ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super.
// ImGuiKey_C (accepted by functions taking ImGuiKey or ImGuiKeyChord)
// ImGuiKey_C | ImGuiMod_Ctrl (accepted by functions taking ImGuiKeyChord)
// ONLY ImGuiMod_XXX values are legal to 'OR' with an ImGuiKey. You CANNOT 'OR' two ImGuiKey values.
// - When using one of the routing flags (e.g. ImGuiInputFlags_RouteFocused): routes requested ahead of time given a chord (key + modifiers) and a routing policy.
// - Routes are resolved during NewFrame(): if keyboard modifiers are matching current ones: SetKeyOwner() is called + route is granted for the frame.
// - Route is granted to a single owner. When multiple requests are made we have policies to select the winning route.
// - Multiple read sites may use a same owner and will all get the granted route.
// - For routing: when owner_id is 0 we use the current Focus Scope ID as a default owner in order to identify our location.
bool Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0);
bool SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0);
bool TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id);
ImGuiKeyRoutingData* GetShortcutRoutingData(ImGuiKeyChord key_chord); // Routing policies for Shortcut() + low-level SetShortcutRouting()
// - The general idea is that several callers register interest in a shortcut, and only one owner gets it.
// - When a policy (other than _RouteAlways) is set, Shortcut() will register itself with SetShortcutRouting(),
// allowing the system to decide where to route the input among other route-aware calls.
// - Shortcut() uses ImGuiInputFlags_RouteFocused by default: meaning that a simple Shortcut() poll
// will register a route and only succeed when parent window is in the focus stack and if no-one
// with a higher priority is claiming the shortcut.
// - Using ImGuiInputFlags_RouteAlways is roughly equivalent to doing e.g. IsKeyPressed(key) + testing mods.
// - Priorities: GlobalHigh > Focused (when owner is active item) > Global > Focused (when focused window) > GlobalLow.
// - Can select only 1 policy among all available.
ImGuiInputFlags_RouteFocused = 1 << 8, // (Default) Register focused route: Accept inputs if window is in focus stack. Deep-most focused window takes inputs. ActiveId takes inputs over deep-most focused window.
ImGuiInputFlags_RouteGlobalLow = 1 << 9, // Register route globally (lowest priority: unless a focused window or active item registered the route) -> recommended Global priority.
ImGuiInputFlags_RouteGlobal = 1 << 10, // Register route globally (medium priority: unless an active item registered the route, e.g. CTRL+A registered by InputText).
ImGuiInputFlags_RouteGlobalHigh = 1 << 11, // Register route globally (highest priority: unlikely you need to use that: will interfere with every active items)
ImGuiInputFlags_RouteAlways = 1 << 12, // Do not register route, poll keys directly.
ImGuiInputFlags_RouteUnlessBgFocused= 1 << 13, // Global routes will not be applied if underlying background/void is focused (== no Dear ImGui windows are focused). Useful for overlay applications. I re-read original message from @avoroshilov and afaik this + input owner systems should solves most cases. Demos See other message #456 (comment) |
…2637, ocornut#2620, ocornut#2891, ocornut#3370, ocornut#4828, ocornut#5108, ocornut#5242, ocornut#5641) - Added SetKeyOwner(), SetItemKeyOwner(), TestKeyOwner(). - Added new IsKeyXXX IsMouseXXX functions with ImGuID owner_id and flags. - Obsoleted SetItemUsingMouseWheel(). (ocornut#2891) - Removed IsKeyPresseedEx() which was a recent internal addition 2022-07-08 deemed to be temporary exactly for this. - Added ImGuiButtonFlags_NoSetKeyOwner, ImGuiButtonFlags_NoTestKeyOwner - Added ImGuiSelectableFlags_NoSetKeyOwner. - Added ImGuiInputFlags_LockThisFrame, ImGuiInputFlags_LockUntilRelease for for SetKeyOwner(), SetItemKeyOwner(). - Added ImGuiInputFlags_CondXXX values for SetItemKeyOwner().
Note the removed comments (hence not squashing) Amend 4448d97 (ocornut#456, ocornut#2637, ocornut#2620, ocornut#2891, ocornut#3370,, ocornut#4828, ocornut#5108, ocornut#5242, ocornut#5641)
…ed policy, SetShortcutRouting(). (ocornut#456, ocornut#2637, ocornut#3724) - InputText() uses Shortcut().
…#3724) - and ImGuiInputFlags_RouteUnlessBgFocused - will be useful for blind menu handlers.
…ocornut#456, ocornut#2637, ocornut#3724) One idea being that this value can be easily locked (for blind menus) or manipulated (for queries from outside).
…utFlags in public API + Demo." (ocornut#456, ocornut#2637) This reverts commit 0949acb. # Conflicts: # imgui.h
…nputFlags_RepeatUntilKeyModsChange, ImGuiInputFlags_RepeatUntilKeyModsChangeFromNone, ImGuiInputFlags_RepeatUntilOtherKeyPress. (#456, #2637) Took a while to come to this design, but it is flexible and lightweight and allow all decision to be taken a polling location. All three policies are useful.
…versions of IsKeyPressed(), IsKeyChordPressed(), IsMouseClicked(). (#456) For several reasons those changes makes sense. They are being made because making some of those API public. Only past users of imgui_internal.h with the extra parameters will be affected. Added asserts for valid flags in various functions to detect _some_ misuses, BUT NOT ALL. Amend 4448d97 (#456, #2637, #2620, #2891, #3370, #4828, #5108, #5242, #5641)
Hello!
I am not sure yet if it is a feature request or my misunderstanding of the intended usage of the dear imgui input system.
I am on version
1.70 WIP
,docking
branch - sorry, I failed to find answers in the FAQ/demowindow code, and neither I've seen similar things in the issues (although it somewhat relates toshortcuts API
#456, but probably more broad). The problem I am looking at is using dear imgui in the complex input scenarios, including allowing windows (and child windows) to have their own hotkeys and allowing keyboard navigation and whatnot. But the problem I've encountered is that imgui only providesWantCaptureKeyboard
without specifying which inputs did it process.To illustrate the usage scenario: there is a window with background global hotkeys (for example, WASD for camera, or some other state switches if viewport is in a subwindow), and there are children windows which are more like "subspaces" - i.e. each have associated logic which have the associated set of hotkeys (for example when
Subwindow1
is active, hotkeyN
shows debug normals; and whenSubwindow2
is active,M
spawns mesh, andN
does nothing, or something other from whenSubwindow1
is active). Theoretically this also can have multiple nested levels. These subwindows naturally can contain elements like input boxes, checkboxes and other elements which may be modified or navigated between using keyboard too.Couple of straightforward ways of doing this that I can see would be a) prioritized input events subscription queue, which can consume input events if required (and block further propagation), and build this queue based on the activity of the elements - this effectively means running imgui first to fill the state or one frame lag; and b) polling the event queue when drawing elements to see if the element was active this frame and consuming/rerouting the input to the next frame - necessarily frame lag, and possible problems with the
io
internal buffers flushing and guarding from events going to another element - unless adding function to determine whether the element to be drawn is active is not considered a bad practice.The way b is more imgui-friendly, but both approaches seem to share common set of problems.
What's more important, there is no way to tell which input exactly was consumed by the imgui, which can matter in cases with input box (wants to consume any alphanumeric and some more) vs check box (wants to consume spacebar/enter to change state) - or if that was simple navigational event (some subwindows/containers may block navigational events to use hotkeys for their own purpose - but that can probably be achieved using
io.NavActive
to some extent).Thus my question is what is recommended in cases like that when using dear imgui, and maybe if that's not what currently easily achievable, we need to devise a minimum set of features (requests) required to implement this.
Thank you!
Edit: added comment about active ids.
The text was updated successfully, but these errors were encountered: