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

Detect if RmlUi need use my inputs #124

Closed
rafadsm opened this issue Sep 25, 2020 · 12 comments
Closed

Detect if RmlUi need use my inputs #124

rafadsm opened this issue Sep 25, 2020 · 12 comments
Labels
discussion Meta talk and feedback enhancement New feature or request

Comments

@rafadsm
Copy link

rafadsm commented Sep 25, 2020

Would it be possible to detect if RmlUi needs to use my entries? Because I would like to prevent other components from being affected by the inputs if RmlUi uses them.
Thank you for your attention.

@mikke89
Copy link
Owner

mikke89 commented Sep 25, 2020

Yes, this is already possible. The input functions Context::Process...() return a boolean to indicate whether or not it was used by RmlUi.

@mikke89 mikke89 added the discussion Meta talk and feedback label Sep 25, 2020
@rafadsm
Copy link
Author

rafadsm commented Sep 25, 2020

Cursor events are not boolean, just keyboard

@rokups
Copy link
Contributor

rokups commented Sep 25, 2020

Funny, i had same dilemma recently. It would be very useful. Events returning bools are ok, but they fall short of delivering. This would be extremely useful when combining multiple UI solutions, as well as handling game input. For example if we have a character jump function bound to a character, we would like character to not jump when we are typing text into UI.

Also this would serve as a good hint for managing input focus between multiple Rml::Context instances. Say i have multiple UIs rendered on to multiple 3D objects in the game, each of them is their own Rml::Context. Rml::Context::WantsKeyboardInput() would be a useful indicator to help decide which of these contexts should unfocus their focused elements so they do not capture input. Likewise Rml::Context::WantsMouseInput() (returns true when dragging something for example) would also be helpful.

@mikke89
Copy link
Owner

mikke89 commented Sep 25, 2020

I think a lot of the functionality can already be made in the application logic.

Some things that work well for me:

  • Set exclusive input when focusing on a text input field (capture EventId::Focus and EventId::Blur or get the current focus element).
  • Detect whether or not I hover over the UI. This determines whether mouse clicks are sent on to the game. I have several elements that I make exceptions for and set an attribute on these.
  • When I initiate a mouse down on some context, I will send the subsequent mouse move and mouse up only to the same context, and never to the game.

See also Context::GetHoverElement() and Context::GetFocusElement() which will be be useful for implementing similar functionality.

I'm a bit worried that making some kind of built-in feature for such behavior would not be general enough to actually be useful. There will always be special cases for most applications. I don't think the library can do anything special in this regard, except perhaps make some common patterns easier to do.

What do you think?

@rokups
Copy link
Contributor

rokups commented Sep 26, 2020

Right, you are correct, and this is pretty much what i do now. My general beef with this approach is that there is no easy way to tell if a particular Element wants to take input. Now i do this:

bool RmlUI::IsInputCapturedInternal() const
{
    if (Rml::Element* element = rmlContext_->GetFocusElement())
    {
        const ea::string& tag = element->GetTagName();
        return tag == "input" || tag == "textarea" || tag == "select";
    }
    return false;
}

Which is not a very good approach. If i added a new element that takes keyboard focus i would need to update a completely unrelated spot, which will most likely be forgotten and result in a bug. If Element could tell us whether it wants keyboard input (like textarea/input) or it wants mouse input (like slider knob being dragged) then we could implement rest of input management on our own.

@mikke89
Copy link
Owner

mikke89 commented Sep 26, 2020

@rokups
I feel like it's tricky for the library to make the decision for which elements should have exclusive focus. For example, input.range can respond to keyboard input, however, you may want to submit unused keys elsewhere even if it has focus. I think only the application can make this decision. Which elements do you suggest this function should return true for?

I don't actually think your solution is that bad, there are quite a limited number of relevant elements. And this approach is much more flexible than any library solution.

@rafadsm
What would be the expected behavior for a boolean for mouse input in your case? Perhaps we could eg. return true if it is hovering over a document in the context, or while the mouse is dragging? I think this could be helpful for some common cases.

@rokups
Copy link
Contributor

rokups commented Sep 26, 2020

Each element which reacts to keyboard input when focused should return true for WantCaptureKeyboard. Likewise each element that is currently active and reacts to mouse input should return true for WantCaptureMouse. Note that this would be completely opt-in, as elements would only provide a hint they want exclusive input, but it would be user's responsibility to act on it or not. In case of range element, say it is at the start of range and user presses left arrow. There is no place to move to the left and user may pass this input to other game systems for processing, and yet range element should return true as it does want keyboard input and is focused. User may do additional checking and pass input or not, depending on range element value and pressed key. Basically these hints would not introduce any limitations, only enable us to better manage input, or do nothing and keep current behavior, of we chose to.

@mikke89
Copy link
Owner

mikke89 commented Sep 26, 2020

Okay I just had a look. The current behavior is that input.text always returns false for key and text input. This should actually already give it "exclusive" access, if the user acts on the return value.

On the other hand input.range always returns true. I'd consider this a bug, it should return false if the arrow keys are pressed at the very least (regardless of whether or not it's at the edge). So let's say we correct that bug, then I think the return value is what users generally would expect.

Such a function also raises many questions. Should it return true for a button? What about a checker-box? Anything that can be tabbed? Anything that can be clicked? I don't know, I feel like a WantCaptureKeyboard function is too abstract, and sounds more confusing than what it could be helpful for. Considering that this behavior can already be emulated, I'm not convinced.

For mouse input on the other hand, I think we can come up with better solutions. But here as well I think a boolean return value should suffice.

@rokups
Copy link
Contributor

rokups commented Sep 27, 2020

What you say makes sense. My only problem is that it does not work quite well with event-driven input systems (like mine). Main issue is that in such cases we need a strict order of event processing. Something like imgui -> [some other UI solution] -> [any number of Rml::Context] -> game input. If order is not guaranteed then bool result after event is processed is not very useful, especially if that order can change when some Rml::Context instance gets removed. This would happen if event subscribers are stored in a hashmap without order guarantee (like in my case). Basically bool result alone creates some non-obvious requirements for user's systems.

With that said, i also think such ordered event processing is a good idea in general, and lack of it is a shortcoming of input processing system which i should correct on my end. I suppose my particular case where i have three different UI systems at play, with multiple contexts of one of them, is a very special case.. But we could certainly use a bool result from mouse processing events, including mouse movement. For example if we drag a slider knob and mouse goes out of window bounds, we still would like Rml::Context to capture mouse movement events as long as mouse button is not released.

@mikke89
Copy link
Owner

mikke89 commented Sep 27, 2020

I understand your problem better now. Generally, I would say a well-defined, strict ordering for input handling is absolutely necessary.

In terms of mouse input, I agree. What do you think about the following. Context functions MouseMove, MouseUp, and MouseDown should return true if any of the following conditions are met:

  • The mouse is hovering over any (non-root) element.
  • We have an active element (that is, left mouse button was just pressed on some element)
    • In the case of MouseUp: We had an active element just before the call to it.
    • I think this should effectively cover the case of dragging as well.

Elements with pointer-events: none should be ignored, I think this is already the case if we use the context's active and hover elements as indicators.

Anything we are missing then, or edge cases? I guess we'll have to just try and test it.

@rokups
Copy link
Contributor

rokups commented Sep 27, 2020

That should be good. Cant think of anything why any of this would cause any issues.

mikke89 added a commit that referenced this issue Sep 30, 2020
…te whether the mouse is interacting with any elements in the context. See #124.
@mikke89
Copy link
Owner

mikke89 commented Sep 30, 2020

Alright, I made a stab at it. Please let me know if any of this can be improved :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Meta talk and feedback enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants