<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">JavaFX doesn’t have many ways of prioritizing key event handling. On Windows and Mac there are mechanisms in place specifically to ensure ESC gets channeled to a dialog’s default cancel button. These mechanisms also prioritize menu accelerators before other uses. In JavaFX key events have to bubble up to the Scene unconsumed for accelerators to work which means they’re effectively prioritized last.<div><br></div><div>The fix for <a href="https://bugs.openjdk.org/browse/JDK-8320557">https://bugs.openjdk.org/browse/JDK-8320557</a> is trivial but writing up a unit test is not. I’ll go see if there’s any existing tests I can extend.</div><div><div><br><blockquote type="cite"><div>On Sep 21, 2024, at 12:14 AM, John Hendrikx <john.hendrikx@gmail.com> wrote:</div><br class="Apple-interchange-newline"><div>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<div><p><br>
</p>
<div class="moz-cite-prefix">On 20/09/2024 23:31, Thiago Milczarek
Sayão wrote:<br>
</div>
<blockquote type="cite" cite="mid:CAAP_wu=7kKvyX3ob29XO3x9_wks4iNGBH+vWs-83WC+22R7wew@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="ltr">Hi,
<div><br>
</div>
<div>I feel shy to add any thoughts on this. So don't mind if I
don't make sense of it:</div>
<div><br>
</div>
<div>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.</div>
</div>
</blockquote>
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.<br>
<blockquote type="cite" cite="mid:CAAP_wu=7kKvyX3ob29XO3x9_wks4iNGBH+vWs-83WC+22R7wew@mail.gmail.com">
<div dir="ltr">
<div><br>
</div>
<div>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.</div>
<div><br>
</div>
<div>I think this logic should be applied:</div>
<div><br>
</div>
<div>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.</div>
</div>
</blockquote><p>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.</p>
<blockquote type="cite" cite="mid:CAAP_wu=7kKvyX3ob29XO3x9_wks4iNGBH+vWs-83WC+22R7wew@mail.gmail.com">
<div dir="ltr">
<div><br>
</div>
<div>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.</div>
<div>Same for text input. If the user presses ESCAPE, and
there's nothing to edit (no control state change), let it
propagate.</div>
</div>
</blockquote><p>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.</p><p>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.</p><p>--John<br>
</p><p><br>
</p>
<blockquote type="cite" cite="mid:CAAP_wu=7kKvyX3ob29XO3x9_wks4iNGBH+vWs-83WC+22R7wew@mail.gmail.com">
<div dir="ltr">
<div><br>
</div>
<div>I hope it makes sense :)</div>
<div><br>
</div>
<div><br>
</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">Em qui., 19 de set. de 2024 às
12:38, John Hendrikx <<a href="mailto:john.hendrikx@gmail.com" moz-do-not-send="true" class="moz-txt-link-freetext">john.hendrikx@gmail.com</a>>
escreveu:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I've
been looking into how exactly navigation keys are being used
in FX, <br>
and who is responsible for handling them:<br>
<br>
- Controls can choose to install navigational keys directly in
their <br>
input map (using
FocusTraversalInputMap::getFocusTraversalMappings)<br>
- Controls can choose to do nothing and leave navigation keys
to bubble <br>
up to Scene, at which point Scene will act on any unconsumed
navigation <br>
keys (in the same was as the traversal mappings would)<br>
<br>
Scene basically is capable of almost all navigation you could
possibly <br>
want out of the box. Any control that does not install
navigation keys, <br>
and leaves said keys to bubble up gets navigation for
**free**. This is <br>
almost all controls in JavaFX, and it makes sense as Controls
should not <br>
care about navigation, they should only care about key presses
that <br>
affect them directly. Navigation should be a concern
somewhere higher <br>
up in the hierarchy.<br>
<br>
So why do some controls install their own navigation keys?<br>
<br>
There are two answers:<br>
<br>
1. For some controls, navigation is conditional. A Spinner
only allows <br>
directional navigation for the left/right keys, or up/down
keys <br>
depending on its orientation.<br>
2. There is an unfortunate choice in ScrollPane that consumes
<br>
directional keys for scrolling purposes, and so if such keys
were left <br>
to bubble up, they would not end up at Scene. Any control
supporting <br>
directional navigation therefore must **specifically** install
these <br>
bindings directly, even though navigation is not their concern
(a Button <br>
cares about being pressed, not about activating unrelated
controls nearby).<br>
<br>
The ScrollPane eating directional keys is an odd choice. In
order for it <br>
to do so one of the following must be true:<br>
<br>
- A control inside it has focus that should act on directional
<br>
navigation, but forgot to install navigation bindings (a
custom <br>
control). Such a control would work perfectly when not part
of a <br>
ScrollPane (as Scene would then handle directional
navigation), but <br>
break when placed inside it. Note that all JavaFX controls do
this <br>
"properly". I couldn't find any controls that would leave
directional <br>
keys to bubble up for a ScrollPane to consume.<br>
<br>
- The ScrollPane itself has focus; this can only happen when
directly <br>
selected with the mouse (or focus traversable is set to true)
and no <br>
specific control inside the pane was selected. The ScrollPane
receives <br>
the ":focused" style, clearly indicating that it is the target
for <br>
keyboard events to the user.<br>
<br>
In short, ScrollPane is making navigation a lot more complex
within FX <br>
than it needs to be. Especially custom controls that do not
have access <br>
(currently) to install navigational bindings will suffer from
this, and <br>
will have to resort to their own navigation implementation for
<br>
directional keys when placed inside a ScrollPane.<br>
<br>
# Proposal<br>
<br>
I think ScrollPane violates what I think should be a
fundamental rule. <br>
Keys should only be consumed by what the user perceives as the
focused <br>
control (ie. the one outlined with a highlighted border), with
the only <br>
exceptions being short cuts (from a menu) or mnemonics.
Containers such <br>
controls happen to be placed in should NOT consume key events
-- the <br>
container is not the control with the focus, and so would
confuse the <br>
user. Only ScrollPane is violating this currently. Note that
if the <br>
ScrollPane has focus itself (and it has the :focused
highlight) then it <br>
is perfectly fine and expected for it to consume keys as much
as it wants.<br>
<br>
This is why I think we should modify ScrollPane to not consume
the <br>
directional keys, unless it specifically has the focus. All
other <br>
controls can then remove their navigational bindings and leave
them to <br>
bubble up to Scene, cleaning up their behaviors so they can
focus on <br>
other concerns. Custom controls would no longer need to
install <br>
navigational bindings either, and would not need to worry
about being <br>
placed inside a ScrollPane and having their directional
navigation broken.<br>
<br>
Optional, but recommended, controls like Spinner should only
act on the <br>
directional keys intended for them, and leave the ones they
can't use to <br>
bubble up. So a vertical spinner would consume up/down for
changing the <br>
spinner value, but would leave left/right untouched for Scene
to <br>
handle. Controls that install a full set of navigational keys
(like <br>
Button, ListView and TitledPane) don't need to do so anymore.<br>
<br>
I think I will file a ticket for this soon, but I'm curious
what others <br>
think of this analysis.<br>
<br>
Note that by solving this problem, the need to make navigation
<br>
functionality available to custom controls severely diminishes
as one <br>
can simple leave the KeyEvents responsible for standard
navigation to <br>
bubble up (recommended as this may be different for each
platform).<br>
<br>
--John<br>
<br>
</blockquote>
</div>
</blockquote>
</div>
</div></blockquote></div><br></div></body></html>