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

Proper Method For Input Testing #703

Closed
atom0s opened this issue Jun 17, 2016 · 15 comments
Closed

Proper Method For Input Testing #703

atom0s opened this issue Jun 17, 2016 · 15 comments

Comments

@atom0s
Copy link

atom0s commented Jun 17, 2016

Just recently got into using ImGui and so far love it. However, I do have a question about how input is handled. In the examples, input is just force given to ImGui and not handled in a real-world environment where input going to the actual application / game is still happening.

What would be the proper method of checking if ImGui is going to handle input? I want to be able to allow ImGui have first dibs at input, and if nothing happens in the ui, allow it to continue to the actual application as it should.

@Cthutu
Copy link

Cthutu commented Jun 17, 2016

After you've called ImGui::Render(), you can test the value of
WantCaptureKeyboard in your ImGuiIO structure. If it is false, then your
application should handle it as ImGui doesn't require it.

On Fri, 17 Jun 2016 at 16:35 atom0s [email protected] wrote:

Just recently got into using ImGui and so far love it. However, I do have
a question about how input is handled. In the examples, input is just force
given to ImGui and not handled in a real-world environment where input
going to the actual application / game is still happening.

What would be the proper method of checking if ImGui is going to handle
input? I want to be able to allow ImGui have first dibs at input, and if
nothing happens in the ui, allow it to continue to the actual application
as it should.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#703, or mute the thread
https://github.com/notifications/unsubscribe/AAVRxg1XEuPNLPFIXuEwP9_yar2OdSxoks5qMwUEgaJpZM4I4tXu
.

@Cthutu
Copy link

Cthutu commented Jun 17, 2016

BTW, I recommend you read through all the comments in imgui.h and the
comments at the top of imgui.cpp

On Fri, 17 Jun 2016 at 16:40 Matt Davies [email protected] wrote:

After you've called ImGui::Render(), you can test the value of
WantCaptureKeyboard in your ImGuiIO structure. If it is false, then your
application should handle it as ImGui doesn't require it.

On Fri, 17 Jun 2016 at 16:35 atom0s [email protected] wrote:

Just recently got into using ImGui and so far love it. However, I do have
a question about how input is handled. In the examples, input is just force
given to ImGui and not handled in a real-world environment where input
going to the actual application / game is still happening.

What would be the proper method of checking if ImGui is going to handle
input? I want to be able to allow ImGui have first dibs at input, and if
nothing happens in the ui, allow it to continue to the actual application
as it should.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#703, or mute the thread
https://github.com/notifications/unsubscribe/AAVRxg1XEuPNLPFIXuEwP9_yar2OdSxoks5qMwUEgaJpZM4I4tXu
.

@ocornut
Copy link
Owner

ocornut commented Jun 17, 2016

As said above, but after ::Update().
There is a flag for the mouse and a flag for keyboard.

Most typically ImGui request usage of the mouse when the cursor is hovering a window, but it handle other cases (whether a widget is active) and track clicks ownership so clicking in "void" and dragging over a window leaves the inputs to you.

@atom0s
Copy link
Author

atom0s commented Jun 17, 2016

So far it seems that WantCaptureKeyboard / WantCaptureMouse never return true in my instance.

My setup is an injected hook into games where the use of ImGui is not standardly built into the application. Instead I am hooking the rendering device and forcing my own code into the game etc.

For that, I am hooking IDirect3DDevice8 and IDirect3DDevice9 (depending on the game) and using:

  • BeginScene (I call ImGui::NewFrame() here.)
  • EndSCene (I call ImGui::Render() here.)

I have a window message hook in place via SetWindowLongPtr to intercept the window messages for input and allow ImGui to attempt to use it but it does not seem to work. Checking if either keyboard/mouse wants to be captured returns false and input is never handled. If I don't check them and just let both ImGui an the app fight over the input it works but then both are processing the input.

@atom0s
Copy link
Author

atom0s commented Jun 17, 2016

My previous UI implementation uses AnTweakBar which includes a function:

  • TwKeyTest(...)

This lets me test if the UI is going to handle keys at the current moment if any are passed to it. Does ImGui offer something like this?

@atom0s
Copy link
Author

atom0s commented Jun 18, 2016

After reviewing the code more I have input working now. Sorry for the over-asked question, felt like I was doing something wrong in the first place vs. a bug etc. Got things working great now.

I do still want to know if there is a key test method or possibly a chance of one being added It is very helpful for input systems that rely on things other than the window messages (WM_KEYDOWN/WM_KEYUP/WM_CHAR) to ensure proper input handling. (For example, DirectInput.)

@Cthutu
Copy link

Cthutu commented Jun 18, 2016

It's up to the user to hand I/O and feed the relevant data into ImGuiIO.
ImGui's sole purpose is to render draw lists and commands based on the I/O
that is fed it. When you realise this, you'll understand ImGui better.

On Sat, 18 Jun 2016 at 02:04 atom0s [email protected] wrote:

After reviewing the code more I have input working now. Sorry for the
over-asked question, felt like I was doing something wrong in the first
place vs. a bug etc. Got things working great now.

I do still want to know if there is a key test method or possibly a chance
of one being added It is very helpful for input systems that rely on things
other than the window messages (WM_KEYDOWN/WM_KEYUP/WM_CHAR) to ensure
proper input handling. (For example, DirectInput.)


You are receiving this because you commented.

Reply to this email directly, view it on GitHub
#703 (comment), or mute
the thread
https://github.com/notifications/unsubscribe/AAVRxu0WV2uyf7BRVbsWj6UFN8lxc9ptks5qM4p1gaJpZM4I4tXu
.

@atom0s
Copy link
Author

atom0s commented Jun 18, 2016

I understand that, but having a way to test if a key is going to be processed by ImGui for the frame would be helpful for blocking on a per-key basis. In my situation, I do not have just window messages being handled for input that I have to block for.

When I setup input for ImGui, I have to be able to tell if it is going to process certain keys from within DirectInput to know if I should tell DirectInput to stop passing keys forward to the game.

The game is old and uses a mixture of both DirectInput and WM_ messages from the WNDPROC of the window. I can give ImGui all the input information from the WNDPROC and make it work fine for input, however the game uses DirectInput for character movement and some other things as well, which in turn causes me to have to be able to detect input blocking for ImGui in two separate locations.

This causes problems with certain things such as pressing enter in a text input box that is not multiline, for example, the Console example in the ImGui test window. Pressing enter here causes enter to still get sent to the game because checking io.WantCaptureKeyboard is false for this key press.

A work-around I had to do was forcefully check if there was a window that had focus at all in ImGui (which the built-in function for that does not work properly).

This is why I was wondering if there was an input testing method or the chance of one being added to test if ImGui is in a state where it would handle a key. As I said above, AnTweakBar has this feature via 'TwKeyTest', see this for more info:
http://anttweakbar.sourceforge.net/doc/tools:anttweakbar:twkeytest

@ocornut
Copy link
Owner

ocornut commented Jun 18, 2016

This causes problems with certain things such as pressing enter in a text input box that is not multiline, for example, the Console example in the ImGui test window. Pressing enter here causes enter to still get sent to the game because checking io.WantCaptureKeyboard is false for this key press.

This really shouldn't be the case. It is a issue that would have been noticed already if there was actually a bug. I suspect your code may not be doing things in the right order. Please provide pseudo-code or a repro for it.

@atom0s
Copy link
Author

atom0s commented Jun 18, 2016

It's hard to give example code because this is a closed source project. I'll share what I can though.
https://gist.github.com/atom0s/8e1f502625b51dd007e42e5f1ae87cd8

Comments are to explain what is going on.

@ocornut
Copy link
Owner

ocornut commented Jun 19, 2016

However, in a single line textbox (such as a console for input of a command) when enter is pressed and input focus is removed, it seems that WantsCaptureKeyboard is being set to false. Enter is both being handled by ImGui and still getting to my game because of the return of false.

As a very dumb test I have tried this:

void ImGui_ImplGlFw_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
{
    ImGuiIO& io = ImGui::GetIO();
    if (action == GLFW_PRESS)
    {
        io.KeysDown[key] = true;
        if (!io.WantCaptureKeyboard)
            printf("Keypress for app: %d\n", key);
    }

And I haven't seen the keypress printed when pressing Return on a single-line input field. So that is pretty much enough of a proof that the feature works (the flag is updated every time you call ImGui::NewFrame()).

I'm not sure about your code linked above. There's a lot of code/comments and it is hard to infer all the context.

This is why I am asking for a method to test key input like AnTweakBar. AnTweakBar works flawlessly with this same setup using their TwKeyTest function to test if the UI would handle a key if it was passed to it.

This is what the flag does.

As per your work-around you could also call ImGui::IsAnyItemActive() for now.

@atom0s
Copy link
Author

atom0s commented Jun 20, 2016

Adding debug code to my keyboard setting function (KeyboardProc), I show that:

[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 0000000D -- IsDown: 1 
[10088] Capture: 0 -- ActiveId: 00000000 -- Current Key: 0000000D -- IsDown: 0 

The key down event gets captured by the text box in ImGui but the keyup event does not which gets forwarded to the game and causes the game to think enter was pressed. The same happens with escape, pressing escape in the text box to remove its focus captures the keydown but not the keyup as focus is lost already from the keydown event. This is causing "half-keys" to be forwarded to the game still.

For example typing 'test' then hitting escape in the text box:

[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000054 -- IsDown: 1 (t)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000054 -- IsDown: 0 (t)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000045 -- IsDown: 1 (e)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000045 -- IsDown: 0 (e)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000053 -- IsDown: 1 (s)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000053 -- IsDown: 0 (s)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000054 -- IsDown: 1 (t)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000054 -- IsDown: 0 (t)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 0000001B -- IsDown: 1 (escape)
[10088] Capture: 0 -- ActiveId: 00000000 -- Current Key: 0000001B -- IsDown: 0 (escape)

Edit --

Looking inside of imgui.cpp I saw that InputTextEx handles enter presses on Key Down instead of Key Up which is the problem for me. I changed:

else if (IsKeyPressedMap(ImGuiKey_Enter))

To the following to fix the problem:

else if (IsKeyReleased(GImGui->IO.KeyMap[ImGuiKey_Enter]))

@ocornut
Copy link
Owner

ocornut commented Jun 20, 2016

You are correct about the key up events.
However ImGui can't possibly convey the information you are expecting in a single boolean nor should it make assumption that your app doesn't want the key up events.

If you actually need to ignore the key up event you could maintain an array of bool KeyPressOwnedByImGui[] that you set on keydown based on the WantCaptureKeyboard flag and filter the following keyup based on it.

On 20 Jun 2016, at 20:18, atom0s [email protected] wrote:

Adding debug code to my keyboard setting function (KeyboardProc), I show that:

[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 0000000D -- IsDown: 1
[10088] Capture: 0 -- ActiveId: 00000000 -- Current Key: 0000000D -- IsDown: 0
The key down event gets captured by the text box in ImGui but the keyup event does not which gets forwarded to the game and causes the game to think enter was pressed. The same happens with escape, pressing escape in the text box to remove its focus captures the keydown but not the keyup as focus is lost already from the keydown event. This is causing "half-keys" to be forwarded to the game still.

For example typing 'test' then hitting escape in the text box:

[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000054 -- IsDown: 1 (t)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000054 -- IsDown: 0 (t)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000045 -- IsDown: 1 (e)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000045 -- IsDown: 0 (e)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000053 -- IsDown: 1 (s)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000053 -- IsDown: 0 (s)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000054 -- IsDown: 1 (t)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 00000054 -- IsDown: 0 (t)
[10088] Capture: 1 -- ActiveId: E7862477 -- Current Key: 0000001B -- IsDown: 1 (escape)
[10088] Capture: 0 -- ActiveId: 00000000 -- Current Key: 0000001B -- IsDown: 0 (escape)

You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

@atom0s
Copy link
Author

atom0s commented Jun 20, 2016

You are correct about the key up events.
However ImGui can't possibly convey the information you are expecting in a single boolean nor should it make assumption that your app doesn't want the key up events.

If you actually need to ignore the key up event you could maintain an array of bool KeyPressOwnedByImGui[] that you set on keydown based on the WantCaptureKeyboard flag and filter the following keyup based on it.

I corrected the issue using the edited example above. I'm guessing your email did not get the edited post I made that you quoted.

@ocornut
Copy link
Owner

ocornut commented Jun 20, 2016

It isn't correct/standard behaviour to validate text with KeyUp on Return.
If you need to filter key-up because they have a side effect add the test described above.

I will look into improving the documentation based on this discussion.

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

No branches or pull requests

3 participants