<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Aptos;
panose-1:2 11 0 4 2 2 2 2 2 4;}
@font-face
{font-family:"Iosevka Fixed SS16";
panose-1:2 0 5 9 3 0 0 0 0 4;}
@font-face
{font-family:"Times New Roman \(Body CS\)";
panose-1:2 11 6 4 2 2 2 2 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:10.0pt;
font-family:"Aptos",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
span.EmailStyle18
{mso-style-type:personal-reply;
font-family:"Iosevka Fixed SS16";
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;
mso-ligatures:none;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style>
</head>
<body lang="EN-US" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Dear Thiago:<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">You might be describing
<a href="https://bugs.openjdk.org/browse/JDK-8320557">https://bugs.openjdk.org/browse/JDK-8320557</a> . You are absolutely right, the event should not be consumed if it effected no change in the control.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">I was planning to address it after the InputMap feature is in, but unfortunately, we ran into the same "better is the enemy of good" situation with that proposal too. Personally,
I would prefer us to make gradual progress, even if the solution might seem to some less than perfect, but your voice and voice of everyone else counts, so please don't be shy in expressing your opinion.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Cheers,<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<div id="mail-editor-reference-message-container">
<div>
<div>
<div style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="margin-bottom:12.0pt"><b><span style="font-size:12.0pt;color:black">From:
</span></b><span style="font-size:12.0pt;color:black">openjfx-dev <openjfx-dev-retn@openjdk.org> on behalf of Thiago Milczarek Sayão <thiago.sayao@gmail.com><br>
<b>Date: </b>Friday, September 20, 2024 at 14:31<br>
<b>To: </b>John Hendrikx <john.hendrikx@gmail.com><br>
<b>Cc: </b>openjfx-dev@openjdk.org <openjfx-dev@openjdk.org><br>
<b>Subject: </b>Re: How navigation currently works in FX, and an enhancement proposal<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Hi,<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">I feel shy to add any thoughts on this. So don't mind if I don't make sense of it:<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">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.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">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.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">I think this logic should be applied:<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">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.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">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.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Same for text input. If the user presses ESCAPE, and there's nothing to edit (no control state change), let it propagate.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">I hope it makes sense :)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Em qui., 19 de set. de 2024 às 12:38, John Hendrikx <<a href="mailto:john.hendrikx@gmail.com">john.hendrikx@gmail.com</a>> escreveu:<o:p></o:p></span></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt">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<o:p></o:p></span></p>
</blockquote>
</div>
</div>
</div>
</div>
</div>
</body>
</html>