<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=utf-8">
<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:"Yu Gothic";
        panose-1:2 11 4 0 0 0 0 0 0 0;}
@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;}
@font-face
        {font-family:"\@Yu Gothic";
        panose-1:2 11 4 0 0 0 0 0 0 0;}
/* 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.EmailStyle20
        {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";color:#212121">OK, let's backtrack a bit.</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">consider this example</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"><a href="https://github.com/andy-goryachev-oracle/Test/blob/main/src/goryachev/research/ComboBox_Events.java" title="https://github.com/andy-goryachev-oracle/Test/blob/main/src/goryachev/research/ComboBox_Events.java"><span style="color:#0078D7">https://github.com/andy-goryachev-oracle/Test/blob/main/src/goryachev/research/ComboBox_Events.java</span></a></span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">it's a single combo box with application-level filters and handlers attached to scene, combo box, and the combo box editor.</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">pressing and releasing a key, we get the following output:</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">> user presses 'a' key</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">1. stage filter: KEY_PRESSED h=913  target=876</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">2. combobox filter: KEY_PRESSED h=457  target=876</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">3. stage filter: KEY_PRESSED h=487  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">4. combobox filter: KEY_PRESSED h=123  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">5. editor filter: KEY_PRESSED h=372  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">6. editor handler: KEY_PRESSED h=372 consumed! target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">7. stage filter: KEY_TYPED h=424  target=876</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">8. combobox filter: KEY_TYPED h=271  target=876</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">9. stage filter: KEY_TYPED h=432  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">10. combobox filter: KEY_TYPED h=535  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">11. editor filter: KEY_TYPED h=208  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">12. editor handler: KEY_TYPED h=208 consumed! target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">13. stage filter: KEY_RELEASED h=336  target=876</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">14. combobox filter: KEY_RELEASED h=242  target=876</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">15. stage filter: KEY_RELEASED h=740  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">16. combobox filter: KEY_RELEASED h=901  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">17. editor filter: KEY_RELEASED h=508  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">18. editor handler: KEY_RELEASED h=508  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">19. combobox handler: KEY_RELEASED h=955  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">20. stage handler: KEY_RELEASED h=232  target=553</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;font-family:"Iosevka Fixed SS16";color:black">ComboBox.onValueChanged: a</span><span style="font-size:12.0pt;color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">This output is very puzzling, please help me understand it.</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">- with the exception of events logged from the editor, the events being sent are all different instances (h= prints the event's hashCode)</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">- where did the duplicate event in step 3 come from?  step 9?  step 15?</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">- why a consumed event is being dispatched to the editor in line 6?  line 12?</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Maybe we should ask the question why in this case the Scene.focusOwner is the ComboBox, and not its editor, the TextField?  Having the actual component that receives
 the input events to be the focus owner would eliminate the need for hacks in the skin to send events, wouldn't it?</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Or, if we say that's the grand design of javafx - that the skins must forward event copies to the skin constituents, then adding a handler to the top level control
 (combo box in this case) should result in that handler to be called before the skin's one, right?</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">This, I think, brings us again to the discussion of event handling priority.  BTW, you never responded to my questions in</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"><a href="https://mail.openjdk.org/pipermail/openjfx-dev/2024-November/050655.html" title="https://mail.openjdk.org/pipermail/openjfx-dev/2024-November/050655.html"><span style="color:#0078D7">https://mail.openjdk.org/pipermail/openjfx-dev/2024-November/050655.html</span></a></span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Cheers,</span><span style="color:#212121"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">-andy</span><span style="color:#212121"><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">Andy Goryachev <andy.goryachev@oracle.com><br>
<b>Date: </b>Friday, December 6, 2024 at 11:16<br>
<b>To: </b>Michael Strauß <michaelstrau2@gmail.com><br>
<b>Cc: </b>openjfx-dev <openjfx-dev@openjdk.org><br>
<b>Subject: </b>Re: Focus delegation API<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Returning to this discussion.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Consider the following scenario: a compound control such as ComboBox, which has an editable TextField control as a part of its skin.  It might be expected that the ComboBox
 shows the focused border instead of its TextField even when the latter has the input focus.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">When the user presses and releases a key, the key events are first dispatched to the input focus owner which is the TextField.  This part is correct.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">The issue we seem to be struggling with is that, unlike the case when TextField is used as a top level control, now it is a part of a ComboBox.  Which means it should not handle
 some keys/events, instead delegating them to the top level control - there should be a single "controller" (in MVC parlance), instead of two fighting each other.  This statement applies to built-in controls as well as the custom controls.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">One way to accomplish that is to register a bunch of event
<b>filters</b> with the top level control, to prevent the events to arrive at the inner control, forwarding these events to the top level controller, which in JavaFX case is the behavior.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">The other way which I think will be easier, is to use the proposed InputMap to remove the undesired mappings from the inner control.  Doing so does not involve subclassing
 of the inner controls, since the input map and the mappings will be a public API.  With the mappings disabled (or remapped to the functions provided by the top level control), there is no contention between the two anymore.  The top level
<i>control</i>'s <i>controller</i> is in full <i>control</i>, it can do anything that's required to the inner controls - setting pseudo styles, inserting text, etc.  As an example - the right arrow key in the combo box's text field can be remapped to a function
 which checks if the caret is at the last position and then move the focus to the button, if so desired.  And if the caret is not at the last position, the default function of text area is invoked - all that enabled by the InputMap.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">What do you think?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></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 Michael Strauß <michaelstrau2@gmail.com><br>
<b>Date: </b>Wednesday, November 20, 2024 at 14:42<br>
<b>To: </b><br>
<b>Cc: </b>openjfx-dev <openjfx-dev@openjdk.org><br>
<b>Subject: </b>Re: Focus delegation API</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt">I don't see how these problems are at all related.<br>
<br>
My proposal solves the focus delegation problem that is inherent with<br>
composite controls, which is not even addressed by the InputMap<br>
proposal.<br>
<br>
It also solves an artifact of the event system, namely that key events<br>
are delivered to the focused node, which cannot simultaneously be the<br>
Spinner and its TextField. The ugly hack to make this work is to<br>
duplicate the event entirely, so that if you'd observe Spinner and<br>
listen for key events, you will see duplicated key presses. This is<br>
also not solved in any meaningful way by InputMap.<br>
<br>
<br>
<br>
On Wed, Nov 13, 2024 at 8:33</span><span style="font-size:11.0pt;font-family:"Arial",sans-serif"> </span><span style="font-size:11.0pt">PM Andy Goryachev<br>
<andy.goryachev@oracle.com> wrote:<br>
><br>
> I feel this is going in a wrong direction: the root cause of the issues we are observing, in my opinion, is that the top-level Control is fighting for control with the inner control, and the inner control's behaves as if it is a top-level control.<br>
><br>
> What should happen instead is to provide a way for the top-level Control to disable those aspects of the inner control behavior (event handlers, key bindings) that are not needed anymore, and replace them with the new logic.<br>
> Continuing the Spinner example, it is ok for the TextField (Spinner.editor) to receive events, but the handling of certain key combinations should be disabled and instead bubbled up to the Spinner behavior.<br>
><br>
> I propose to use the InputMap <a href="https://github.com/andy-goryachev-oracle/Test/blob/main/doc/InputMap/InputMapV3.md">
https://github.com/andy-goryachev-oracle/Test/blob/main/doc/InputMap/InputMapV3.md</a> for this purpose.<br>
><br>
> -andy</span><o:p></o:p></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>