I am using following maven dependency for my project:
Worked nice out of the box.
I have just slightly problems in certain situations
For example following:
→ 3D world is focused, and I press key W (for example) for moving Forward.
→ Now I click in a Java fx Panel, so that jfx container will grab the Focus.
→ Now I release key W.
→ The Event is consumed by JmeFXInputListener. (No further listeners from the InputManager will react)
→ In the General InputManager of the application the Button W is still listed as pressed.
→ So the move Action is still executed (Analog Listeners still react)… Even if Focus is again on 3D world and the button is not actually pressed.
Any idea how this can be solved?
Dirty Hack would be to call:
from my project.
But that seems to be a ugly solution…
It’s my sons birthday today so I’m a little busy but I’ll put some thought into it.
There are certain situations where you’d want the focus to go straight back to JME and some where you wouldn’t, so the best approach would be to give the developer the choice. For example a boost button would want it straight back to JME. A button that brings up a panel wouldn’t.
It would depend on what’s on the panel. If the panel just reveals more buttons, you’d still want JME processing key presses. I believe the way to think about this focus issue is as a component level issue, depending on the type of component.
TextInput, TextArea, TreeView, ListView (I’m sure there’s more) obviously when they get focus, those events shouldn’t travel to JME. Things like a button (inside a panel or not) shouldn’t ever block events JME would be interested in. (Unless you’re supporting accessibility in your game or something.)
Giving the dev the choice here (with sensible defaults) is obviously the safest approach, but how to implement that isn’t immediately obvious. Hopefully there’s another way, but my (quite possibly wrong) feeling is that a bytecode instrumentation approach may be needed to consume events on certain types of components. Which sounds like a lot of work (and messy), unless there’s a good place to intercept them somewhere inside JavaFX event processing.
Alternatively, in some limited cases it might be possible to use a design like Elite Dangerous, which has a similar type of issue.
It’s awkward IMO, but IIRC it’s basically up to the user to focus/defocus the entire UI “panel” with a keypress to switch to a sort of “UI mode”. In this way I guess it’s even able to support keyboard navigation.
Well I’m sure you’ve put more thought into it than I have, so I won’t disagree with that concept. I’m less sure that it’ll be really really simple to implement, otherwise I have to wonder why it hasn’t been done yet, given that Swing and JFX have been used with JME for quite a few years.
I agree, if the UI has not received the Key Pressed event, it should not consume key released event.
I guess this can be changed in:
This would solve my specific example which I described in my initial post.
However, there are also sometimes situations where you’d want the focus to go straight back to JME, when something on FX Panel is clicked. (This is independent of rejecting the release event)
So it would also be nice for the developer to have access to the FX Container, to trigger the lose of the UI focus whenever needed… But I am not sure if there is a better and cleaner approach to handle that whole topic.
Yeah there’s quite a bit of code in there now to cope with event management between JME and JFX. Most looks directed at converting JME events to FX events, but doing so in the other direction, I think is lacking? I’ll wait to see Jayfella’s thoughts before further speculating, maybe there’s an easy fix out there.
Trying to help improve on this if possible has been on my todo list some time, so if there’s some way I can help I’m listening. (Unfortunately my unreliable motivation level tends to vary drastically, almost none lately… ) It’s hard to know if a solution you spend time coming up with will be agreeable to the repo maintainers.
The grabFocus() method will give JavaFx input focus.
This will be useful for situations where a GUI pops up in your game without user input. For example the player walks over and clicks a salesman - which in turn brings up a GUI. To force input to focus on that GUI you would call this method.
The loseFocus() method will give JME input focus.
This can be used in cases where you may have a button that the user can press and resume their input focus instantly back to JME. For example if you have a “boost” button in a racer game.
These changes are not yet official so an official release has not yet been cut. I’m not completely convinced the CrossInputHandler.java code is bullet-proof. Any testing and suggestions are welcome. The code has been pushed to the github repository.
So good testing results so far? I’m still not sure this will solve the entire problem in every case, but I haven’t found the time to look into it at any meaningful level.
One case I’m uncertain about is when you’ve clicked a JFX control which you wouldn’t want to hold focus, such as a button. Ex. click a JFX button, and then press a movement arrow key or whatever that generates events which JME would be interested in, but not the JFX control. This behavior would be control specific because if it were a TextInput or a TextField that was focused, you’d want JFX to process (and consume) your arrow key events rather than JME.
Typically, in a UI if you press a button then it gets locked as the target because if you move off before releasing then it cancels the press.
Users are so used to this stuff that they don’t even notice… until you mess it up and then they wonder why the UI feels broken but then can’t quite put their finger on why.
Edit: I realize after that there might be another way to read your response… but then I can’t make sense out of it since I would hope the JavaFX UIs are not consuming events that don’t get delivered to anything. But maybe it doesn’t know? (that would suck)
Yes I think we’re not connecting here. I need to do some tests of my own first and put together a better description of the problem, unless I find that I’m mistaken or there’s already a solution available.
By default if you click the gui, Jfx has focus. This is expected behaviour. If you don’t want that behaviour you can invoke the JavaFxGUI.getInstance().loseFocus() method in the click event to put the focus back onto jmonkey.
Inversely if a game action requires the user interacts with a gui - for example a merchant brings up a GUI you can .grabFocus() to give jfx focus.
In an RPG where you use the mouse to select things on screen but otherwise use the keyboard to move your character around on screen… JFX would be ill-suited for this sort of UI unless you constantly switch focus back to the app on every button click?
As a user, I’d expect events not consumed by some control to be passed on… but maybe JavaFX doesn’t provide this (like Swing/AWT did).
However, I have found out, that the same problem for mouse pressed/released existed.
So I created a pull request to solve the whole key/mouse-pressed(in JME)/released(in JFX) issue
a little bit different (based on the first solution draft).
For my use cases everthing is now fine.
I can navigate with (WASD) in JME world. Whenever I click on some
FX panel or FX Button, the JFX container will grab focus, and key buttons will not be handed over to JME. (Unless they are release events which needs to be passed to JME).
However, I can call JavaFxUI.getInstance().loseFocus(); if I want to get the focus right back to JME, so that keyboard navigation is working instantly again.
Just for clarification:
It all depends on the implementation of JmeFXInputListener, if Input events should be consumed, or handed over to JME.