On 20/09/2024 23:31, Thiago Milczarek Sayão wrote:
Hi,
I feel shy to add any thoughts on this. So don't mind if I don't make
sense of it:
I don't think all key bindings qualify as "navigation", but pressing
ESCAPE on a text input control will eat the key even if there's no
edit to cancel.
Yeah, there are more keys with problems in this regard. Navigation keys
are also often dual purposes -- ie. cursor keys are used by Text
controls for moving the cursor, which has nothing to do with focus
traversal -- similarly, ScrollPane uses them to pan the view, which also
has nothing to do with focus traversal.
So if you bind ESCAPE on the Scene as a shortcut (for closing the
window for example) and you are on a text input control with no edit
to cancel, it will eat the event.
I think this logic should be applied:
If the key event applies any change to the control, it should be
consumed. If it does not change any control state, it should propagate.
That's exactly right, and that's what annoys me as well. KeyEvents only
should be consumed when they're used. The problem stems from the "auto
consume" feature in InputMap. Too many controls have this set to true,
while their logic is conditional.
So on a ScrollPane, if the user presses UP to the top and there's
nothing more to scroll, it should not consume the key event.
Same for text input. If the user presses ESCAPE, and there's nothing
to edit (no control state change), let it propagate.
Yes, it should do this too, but it should also only consume keys
targetted at it (ie. it has the ":focused" style so users know where
keys are going), not keys that bubble up to it IMHO.
I haven't found any real life non-FX controls that consume keys as
scroll events when the scrollpane/bar wasn't specifically focused. It
would be very annoying I think if they did.
--John
I hope it makes sense :)
Em qui., 19 de set. de 2024 às 12:38, John Hendrikx
<john.hendr...@gmail.com> escreveu:
I've been looking into how exactly navigation keys are being used
in FX,
and who is responsible for handling them:
- Controls can choose to install navigational keys directly in their
input map (using FocusTraversalInputMap::getFocusTraversalMappings)
- Controls can choose to do nothing and leave navigation keys to
bubble
up to Scene, at which point Scene will act on any unconsumed
navigation
keys (in the same was as the traversal mappings would)
Scene basically is capable of almost all navigation you could
possibly
want out of the box. Any control that does not install navigation
keys,
and leaves said keys to bubble up gets navigation for **free**.
This is
almost all controls in JavaFX, and it makes sense as Controls
should not
care about navigation, they should only care about key presses that
affect them directly. Navigation should be a concern somewhere
higher
up in the hierarchy.
So why do some controls install their own navigation keys?
There are two answers:
1. For some controls, navigation is conditional. A Spinner only
allows
directional navigation for the left/right keys, or up/down keys
depending on its orientation.
2. There is an unfortunate choice in ScrollPane that consumes
directional keys for scrolling purposes, and so if such keys were
left
to bubble up, they would not end up at Scene. Any control supporting
directional navigation therefore must **specifically** install these
bindings directly, even though navigation is not their concern (a
Button
cares about being pressed, not about activating unrelated controls
nearby).
The ScrollPane eating directional keys is an odd choice. In order
for it
to do so one of the following must be true:
- A control inside it has focus that should act on directional
navigation, but forgot to install navigation bindings (a custom
control). Such a control would work perfectly when not part of a
ScrollPane (as Scene would then handle directional navigation), but
break when placed inside it. Note that all JavaFX controls do this
"properly". I couldn't find any controls that would leave
directional
keys to bubble up for a ScrollPane to consume.
- The ScrollPane itself has focus; this can only happen when directly
selected with the mouse (or focus traversable is set to true) and no
specific control inside the pane was selected. The ScrollPane
receives
the ":focused" style, clearly indicating that it is the target for
keyboard events to the user.
In short, ScrollPane is making navigation a lot more complex
within FX
than it needs to be. Especially custom controls that do not have
access
(currently) to install navigational bindings will suffer from
this, and
will have to resort to their own navigation implementation for
directional keys when placed inside a ScrollPane.
# Proposal
I think ScrollPane violates what I think should be a fundamental
rule.
Keys should only be consumed by what the user perceives as the
focused
control (ie. the one outlined with a highlighted border), with the
only
exceptions being short cuts (from a menu) or mnemonics. Containers
such
controls happen to be placed in should NOT consume key events -- the
container is not the control with the focus, and so would confuse the
user. Only ScrollPane is violating this currently. Note that if the
ScrollPane has focus itself (and it has the :focused highlight)
then it
is perfectly fine and expected for it to consume keys as much as
it wants.
This is why I think we should modify ScrollPane to not consume the
directional keys, unless it specifically has the focus. All other
controls can then remove their navigational bindings and leave
them to
bubble up to Scene, cleaning up their behaviors so they can focus on
other concerns. Custom controls would no longer need to install
navigational bindings either, and would not need to worry about being
placed inside a ScrollPane and having their directional navigation
broken.
Optional, but recommended, controls like Spinner should only act
on the
directional keys intended for them, and leave the ones they can't
use to
bubble up. So a vertical spinner would consume up/down for
changing the
spinner value, but would leave left/right untouched for Scene to
handle. Controls that install a full set of navigational keys (like
Button, ListView and TitledPane) don't need to do so anymore.
I think I will file a ticket for this soon, but I'm curious what
others
think of this analysis.
Note that by solving this problem, the need to make navigation
functionality available to custom controls severely diminishes as one
can simple leave the KeyEvents responsible for standard navigation to
bubble up (recommended as this may be different for each platform).
--John