Skip to content
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

Escape to close popup menu #2517

Closed
haferburg opened this issue Apr 27, 2019 · 12 comments
Closed

Escape to close popup menu #2517

haferburg opened this issue Apr 27, 2019 · 12 comments
Labels
focus nav keyboard/gamepad navigation popups

Comments

@haferburg
Copy link

haferburg commented Apr 27, 2019

I'm using ImGui to display a popup menu. Normally, Escape closes my application, i. e. if !ImGui::GetIO().WantCaptureKeyboard.

I have enabled keyboard navigation with io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard in order to make Escape close the menu. That works, but unfortunately WantCaptureKeyboard is still true afterwards. So if I hit Escape again, my application won't close.

This is not the case when I click next to the menu. In this case, the menu closes and WantCaptureKeyboard becomes false.

Another problem is that WantCaptureKeyboard is true when my application starts.

So maybe I misunderstand something. I would think that navigation only requests the keyboard if any ImGui window or popup is active. As far as I know, that is not the case when the application starts, or after the popup menu is closed.

I've tried to also set ImGuiConfigFlags_NavNoCaptureKeyboard, but then the application would always close, even if I intend to close the popup.

Tested with 1.69 on Windows.

@ocornut ocornut added the nav keyboard/gamepad navigation label Apr 27, 2019
@ocornut
Copy link
Owner

ocornut commented Apr 27, 2019

So maybe I misunderstand something. I would think that navigation only requests the keyboard if any ImGui window or popup is active. As far as I know, that is not the case when the application starts, or after the popup menu is closed.

I am not sure what you mean by "Active", in dear imgui terminology a Window is "Active" when it has been submitted during the current frame, leading to it being visible.

Navigation requests the keyboard when any window is Focused. This is the case when starting the application and when closing a popup. If you click on the void area not handled by dear imgui, all windows will be unfocused.

I understand your problem but I am not sure what the solution is yet. We may need more granularity as to how Navigation capture keyboard but I don't yet know what design would be satisfactory. When navigation is enabled you can always use the arrow keys/space/etc. to manipulate imgui so it seems to make sense to request Keyboard Capture then.

@haferburg
Copy link
Author

haferburg commented Apr 27, 2019

Thanks for the clarification. After digging a bit deeper, I discovered ShowMetricsWindow to display the current NavWindow. When my application has focus (NavWindow is 0), and I then trigger the popup and press Escape, ImGui switches the focus to Debug#Default. I would expect the focus to go back to my application.

I was able to hack it by changing ClosePopupToLevel.

    if (focus_window->ParentWindow == NULL) {
      focus_window = NULL;
    }
    FocusWindow(focus_window);

What is the purpose of the Debug#Default window? Is it necessary that this window ever has focus?

@ocornut ocornut added the focus label Apr 28, 2019
@ocornut
Copy link
Owner

ocornut commented Apr 28, 2019

and I then trigger the popup and press Escape, ImGui switches the focus to Debug#Default. I would expect the focus to go back to my application.

Correct, this is a bug then and should be fixed.
I will look into it.

I assume that your popup is called outside of a Begin/End call ?
The Debug##Default window sits a the bottom of the window stack and is automatically hidden when unused. In this situation it appears there is an incorrect relationship between the popup and the window on the top of the stack at the time of opening the popup, and focus is restored to it when closing the popup.

Fixing that bug will fix that scenario you mentioned in the last message.

(As a separate thing, we could possibly also want to decide that pressing Escape when there's no widget active would unfocus the current window.)

@ocornut
Copy link
Owner

ocornut commented Apr 28, 2019

It would be useful if you provided a repro as requested by the issue template.
My current assumption is that you are doing something like this:

        ImGui::NewFrame();

        if (ImGui::BeginPopupContextVoid())
        {
            ImGui::MenuItem("This is a popup");
            ImGui::EndPopup();
        }

@ocornut ocornut added the popups label Apr 28, 2019
@haferburg
Copy link
Author

After testing it some more I think this is a deeper issue.

My application basically consists of one GL viewport, similar to Maya with a maximized viewport. I interact with it with the mouse and the keyboard. Most of the time, no other window is visible. But sometimes I do want windows, e. g. the popup I described earlier. If I enable ImGuiConfigFlags_NavEnableKeyboard, it is an all or nothing kind of deal. From my perspective, ImGui now blocks user interaction, even in cases when it doesn't do anything with the keys.

What I would prefer is events like in Qt. For example normally I use keys like W or E as hotkeys. But if a line edit has focus, e. g. when I enter a file name, I want that line edit to consume these keys. In Qt, the line edit would be the widget with the focus, receive an event, and mark it as accepted. But if it doesn't care about those keys, the event is propagated to the parent. The top-most parent would then handle the global shortcuts.

ImGui already has something like this for text edits, but there is no global solution.

Another aspect: We have Ctrl+Tab now. But there's no way for me to add my viewport to the list of Ctrl+Tab targets, right?

So I think the two open questions are: How can ImGui share focus with the application? And how can ImGui pass the focus back to the application?

@haferburg
Copy link
Author

It would be useful if you provided a repro as requested by the issue template.

Sure, sorry.

    static bool MainMenu = false;
    if (App.TriggerMainMenu) {
      ImGui::OpenPopup("mainmenu");
      App.TriggerMainMenu = false;
      ProcessImGuiEvent = true;
    }

    if (ImGui::BeginPopup("mainmenu")) {
      MainMenu = true;
      ImGui::MenuItem("Hi there");
      ImGui::EndPopup();
    } else if (MainMenu) {
      MainMenu = false;
      // Draw an additional frame if the menu is hidden so that ImGui will realize that it
      // no longer wants the mouse.
      ProcessImGuiEvent = true;
    }

@ocornut
Copy link
Owner

ocornut commented Apr 28, 2019

From my perspective, ImGui now blocks user interaction,

It does if an imgui window is focused and keyboard navigation is enabled, unless you set ImGuiConfigFlags_NavNoCaptureKeyboard.

Right now you reported a bug where an imgui window is erroneously marked as focused, requesting inputs. This should be fixed and i'll be looking into it.

What I would prefer is events like in Qt.

I think there's case for something like you describe, and as we transition to storing events instead of levels for all aspect of the input system, we could imagine that a consumer would mark one as consumed and leave it to the caller to process it on return. That would be acceptable if you are ready to poll keyboard from the same events/structure you submitted to imgui and after submitting all your imgui contents, but that's a constraint more than anything if your input is the application and not actual UI code. This technique would probably be ideal for global shortcuts, but probaby not the ideal solution if your consumer is the game and not actual UI stuff. In all likehood from a gamey application point of view you want to be able to access your inputs early in the frame?

Enabling keyboard navigation means you can control the entirely of dear imgui with the keyboard (using arrows, space, etc.) and in the future we could imagine interactions to be tied to local shortcuts (e.g. in a menu you would press E to trigger an item caled `Execute'). So having inputs selectively be dispatched to the UI or your game based on what the UI is showing up at a certain point in time is going to be very confusing and dangerous. Someone needs to be owning the focus and inputs. Right now keyboard navigation means that focused imgui window are consuming inputs.

A stateful toggle generally work, you'll need the bug fix mentioned above, and then let the user click back on background/game, or maybe use global hotkey if we want to stop using imgui.

So I think the two open questions are: How can ImGui share focus with the application? And how can ImGui pass the focus back to the application?

It's a perfectly fine topic for discussion but as presented the questions are too vague and wide reaching, we ought to be working on specific problem to solve.

Another aspect: We have Ctrl+Tab now. But there's no way for me to add my viewport to the list of Ctrl+Tab targets, right?

Please open a separate issue for that. I don't know what you mean by "viewport" here. Do you mean ImGuiViewport ? Or do you mean you would like Ctrl+Tab to be able to target a state where no imgui window is focused, relinquishing full inputs to your underlying app? If so that's an interesting idea we could design and implement (in a separate thread).

// Draw an additional frame if the menu is hidden so that ImGui will realize that it no longer wants the mouse.

I think you should use a counter, that would make your code simpler.
MarkUiAsAlive() { frame_counter = 3; } // Will keep processing events for 3 frames.
Even so I am not sure why you are doing this at all unless you want whole app to go idle and only resume on inputs (in which case your wakeup triggers would be tied to inputs rather than display of actual ui). If you have a 3D viewport of some sort presumably you are already running a main loop at interactive refresh rate?

@haferburg
Copy link
Author

Yea. Sorry that this got so confusing. All I wanted in my life was for Escape to close that popup menu. Then I enabled ImGuiConfigFlags_NavEnableKeyboard, which did that, but also introduced other issues so that I've since disabled it again.

I've implemented a solution that calls CloseCurrentPopup() on Escape. I wouldn't mind if you closed this issue.

@ocornut
Copy link
Owner

ocornut commented Apr 28, 2019

I've implemented a solution that calls CloseCurrentPopup() on Escape. I wouldn't mind if you closed this issue.

If you don't need any other keyboard control that would work as a workaround, yes.

I'll look into fixing the bug either way. Unsurprisingly the code in ClosePopupToLevel() has a large comment that state that the focus restoring code is currently completely wrong and I'd like to tackle that.

As for Ctrl+Tab toward giving back full inputs to your underlying game. It didn't come up before because many people just render their game content in an imgui window. But then I realize you can just do that as well:

ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(io.DisplaySize);
ImGui::Begin("My Game", NULL, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::End();

Then you can CTRL+Tab into the background and because that window has the ImGuiWindowFlags_NoNavInputs flag it won't request keyboard at all.

ocornut added a commit that referenced this issue Apr 28, 2019
…he time of the popup opening, instead of restoring the window that was in the window stack at the time of the OpenPopup call. (#2517)

Among other things, this allows opening a popup while no window are focused, and pressing Escape to clear the focus again.
@ocornut
Copy link
Owner

ocornut commented Apr 28, 2019

FYI I have pushed the fix for NavWindow not being restored to NULL in the situation you described.

@ocornut
Copy link
Owner

ocornut commented Apr 29, 2019

Closing this as afaik

  • The original bug reported is fixed.
  • Ctrl+Tabbing to clear focus is possible with suggested blurb.

I understand this is a wider topic and I'm happy to get back to any discussion/features regarding different ways to share inputs between imgui side and app side, so feel free to comment it (and I can reopen this) or create new issue if something arise.

@ocornut ocornut closed this as completed Apr 29, 2019
@haferburg
Copy link
Author

@ocornut Thanks, Omar!

ocornut added a commit that referenced this issue Oct 11, 2021
…ested menus (broken in 1.83). (#4640)

Broken since 936f532
Weirdly chain-reaction caused by the fact following #4640 repro, the SourceWindow assignment in OpenPopupEx() picks Menu_04 before its closure. Value of SourceWindow since bda2cde #2517
ocornut pushed a commit that referenced this issue Sep 1, 2022
… WIP) (#2517, #5614, noticed in #5546)

Amend bda2cde
Fixes the case where following menu hover sequence results in incorrect RestoreNavWindow (previously SourceWindow) pointing to opened sub-menu:
1. Hover "Menu -> Options" - Open ##Menu_01 window
2. Hover "Menu -> Colors"  - SourceWindow incorrectly points to ##Menu_01 window
ocornut added a commit that referenced this issue Oct 14, 2024
…vMoveSetMousePos, ImGuiConfigFlags_NavNoCaptureKeyboard -> ConfigNavCaptureKeyboard. (#2517, #2009)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
focus nav keyboard/gamepad navigation popups
Projects
None yet
Development

No branches or pull requests

2 participants