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

How to handle key events properly. #7490

Open
audetto opened this issue Apr 12, 2024 · 7 comments
Open

How to handle key events properly. #7490

audetto opened this issue Apr 12, 2024 · 7 comments
Labels

Comments

@audetto
Copy link

audetto commented Apr 12, 2024

Version/Branch of Dear ImGui:

1.90.5

Back-ends:

imgui_impl_sdl2.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

gcc 13, Ubuntu 23.10

Full config/build information:

No response

Details:

For the first time, I am trying to handle key events in ImGui.

I would like to handle some key combinations when a certain widget (or its children) is selected.
At the same time I use io.WantCaptureKeyboard not to pass events to my application when it is True.

This works only halfway

    if (ImGui::Begin("window"))
    {
      if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
      {
        if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Space))
        {
          // do something
        }
      }

I say 50/50 because

  1. it gets triggered correctly only when the relevant widgets are focused
  2. but io.WantCaptureKeyboard does not become true and so I still pass the event to my app.

I think I am missing something bing here. Who is supposed to set io.WantCaptureKeyboard?

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

No response

@cfillion
Copy link
Contributor

cfillion commented Apr 12, 2024

Who is supposed to set io.WantCaptureKeyboard?

Active text input fields, or via ImGui::SetNextFrameWantCaptureKeyboard(true). See Demo > Inputs & Focus > WantCapture override.

@ocornut ocornut added the inputs label Apr 13, 2024
@audetto
Copy link
Author

audetto commented Apr 13, 2024

Yes, that does it and the right place to put it seems to be

          if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
          {
            ImGui::SetNextFrameWantCaptureKeyboard(true);  // << GOOD LOCATION
            if (ImGui::IsKeyChordPressed(ImGuiKey_Space | ImGuiMod_Ctrl))
            {
               // DO NOT PUT IT HERE!
               //
               // handle keypress

I looked at InputText and it seems to use a different system (g.ActiveId), but I think it is beyond the scope of the issue to understand the difference.

Instead I wanted to ask: imagine a child of the above widget is already handling key events (via the same method or like InputText): how to I filter this case to only capture residual key events? In a more traditional widget system, when an event is accepted it stops being propagated. Is it possible here?

@audetto
Copy link
Author

audetto commented Apr 14, 2024

Don't know if I should open a new issue or continue here.

This is about selecting widgets using TAB.
I see it is already enable for InputText and this can be controlled via PushTabStop.

But for TabItems, is it possible to cycle through the selected tab using TAB?

@ocornut
Copy link
Owner

ocornut commented Apr 19, 2024

Instead I wanted to ask: imagine a child of the above widget is already handling key events (via the same method or like InputText): how to I filter this case to only capture residual key events? In a more traditional widget system, when an event is accepted it stops being propagated. Is it possible here?

The current mechanism which I am pushing for but isn't fully documented is a mix of setting and testing for key ownership and/or registering shortcut routes (the later register key ownership when the mods matches).

If you call Shortcut(ImGuiKey_Space | ImGuiMod_Ctrl) in both parent and child location, you'll find that only the deep most one gets the shortcut. It's a rather complex multi-faceted problem that doesn't have a single answer, but if you want to detail your use case I may be able to suggest a direction.

Unfortunately this mechanism doesn't necessarily set io.WantCaptureKeyboard for the "background" application to use.
Technically your key handler could also check if a key is owned (if (ImGui::GetKeyOwner(ImGuiKey_XXXX) == ImGuiKeyOwner_None) and use that as a secondary filter to not pass keys to background application. However this would only work for code that is setting key ownership correctly. Some randomly placed IsKeyPressed(ImGuiKey_XXX) unless SetKeyOwner() is also called, which standard widgets do, and which e.g. Shortcut() will do indirectly do.

This is about selecting widgets using TAB.
I see it is already enable for InputText and this can be controlled via PushTabStop.
But for TabItems, is it possible to cycle through the selected tab using TAB?

I don't understand what you are saying here. It looks like a different topic, is it? If it a different topic please open a new issue and provide more details.

@audetto
Copy link
Author

audetto commented Apr 20, 2024

Thank you for the explanation. I was not aware of Shortcut, nor KeyOwner.

I see them in imgui_internal.h. I will look to see if I understand them, but I fear that until they land in the Demo I will have a hard time.

For the time being, I have rearranged a bit the hierarchy to remove the ambiguity, but I will keep an eye on further developments.

@ocornut
Copy link
Owner

ocornut commented Apr 20, 2024

Sorry I meant to add there is a public branch with a bunch of demos for those functions as well. I can’t merge the demos before i move those public to api realm, but i think most are pretty stable now. My main bother is that outside of just using Shortcut(), the system can be a bit confusing

@ocornut
Copy link
Owner

ocornut commented Apr 22, 2024

The demos are here:
master...features/demo_input_owner_and_routing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants