<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=us-ascii">
<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;}
@font-face
{font-family:"Segoe UI";
panose-1:2 11 5 2 4 2 4 2 2 3;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:12.0pt;
font-family:"Aptos",sans-serif;}
span.EmailStyle21
{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"">>
</span>I think if we can find a solution that doesn't require priorities that it should by far be preferred<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"">That was exactly my rationale for implementing the prioritization at the Controls level with the InputMap.<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"">But we may be jumping ahead in the discussion. Remember I asked the question of whether the "priority inversion" problem we see with Controls also appears outside of controls?
Because if it does, if the current two-level priority scheme with event filter / event handler duo is insufficient, then we need Michael's idea of explicit prioritization of the event handlers.<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"">Getting into the Controls, there is a need for more priority levels. I tried to explain that in the InputMap proposal earlier, but basically it's<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>
<table class="MsoNormalTable" border="0" cellspacing="0" cellpadding="0" style="background:white;border-collapse:collapse">
<tbody>
<tr>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Highest<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Application<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">InputMap.addEventHandler()<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Event handlers set by the application<o:p></o:p></span></p>
</td>
</tr>
<tr style="box-sizing: border-box;background-color:var(--bgColor-muted, var(--color-canvas-subtle));border-top:var(--borderColor-muted, var(--color-border-muted))">
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Application<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">InputMap.registerKey()<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Key mappings set by the application<o:p></o:p></span></p>
</td>
</tr>
<tr style="box-sizing: border-box;background-color:var(--bgColor-default, var(--color-canvas-default));border-top:var(--borderColor-muted, var(--color-border-muted))">
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Skin<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">SkinInputMap.registerKey()<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Key mappings set by the skin<o:p></o:p></span></p>
</td>
</tr>
<tr style="box-sizing: border-box;background-color:var(--bgColor-muted, var(--color-canvas-subtle));border-top:var(--borderColor-muted, var(--color-border-muted))">
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Skin<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">SkinInputMap.addEventHandler()<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Event handlers set by the skin<o:p></o:p></span></p>
</td>
</tr>
<tr style="box-sizing: border-box;background-color:var(--bgColor-default, var(--color-canvas-default));border-top:var(--borderColor-muted, var(--color-border-muted))">
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Skin<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">SkinInputMap.addEventHandlerLast()<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Event handlers set by the skin<o:p></o:p></span></p>
</td>
</tr>
<tr style="box-sizing: border-box;background-color:var(--bgColor-muted, var(--color-canvas-subtle));border-top:var(--borderColor-muted, var(--color-border-muted))">
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Lowest<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Application<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">InputMap.addEventHandlerLast()<o:p></o:p></span></p>
</td>
<td style="padding:4.5pt 9.75pt 4.5pt 9.75pt;box-sizing: border-box;border:var(--borderColor-default, var(--color-border-default))">
<p class="MsoNormal"><span style="font-family:"Segoe UI",sans-serif;color:#1F2328">Event handlers set by the application<o:p></o:p></span></p>
</td>
</tr>
</tbody>
</table>
<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"">There might be more, if we want to give the application a chance to add a handler before SkinInputMap.addEventHandlerLast(), but it is not important at the moment, the important
thing is that we'll need some number of priority levels to reliably control the event handling between the application and the skins.<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 feel we need to come to a conclusion on the EH prioritization before we can talk about the input maps and the focus.<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 must also say I don't care where we solve the priority issue - at the event dispatch level, or at the input map level. If we decide to do it globally, then the input map
will plug into the global mechanism, or we can resolve the issues for the controls specifically via the input map, but many people seem to dislike this idea on a symmetry-breaking grounds.<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"">What do you think?<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"">-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>
<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="color:black">From:
</span></b><span style="color:black">openjfx-dev <openjfx-dev-retn@openjdk.org> on behalf of John Hendrikx <john.hendrikx@gmail.com><br>
<b>Date: </b>Tuesday, November 12, 2024 at 12:18<br>
<b>To: </b>openjfx-dev@openjdk.org <openjfx-dev@openjdk.org><br>
<b>Subject: </b>Re: Unconsumed event handlers<o:p></o:p></span></p>
</div>
<p><o:p> </o:p></p>
<div>
<p class="MsoNormal">On 12/11/2024 18:31, Andy Goryachev wrote:<o:p></o:p></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">I am not sure this is the best solution, since it does not solve the problem of multiple actors adding their event handlers. I do like the idea of prioritized event handlers,
because it solves the problem *<b>reliably</b>*.</span><span style="font-size:10.0pt"><o:p></o:p></span></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"">I think there is no way around it - we need different priorities. It may be a set or may be a wide range of integers (for the maximum flexibility), but the main idea is that,
at least in controls, we have a situation where there are at least these priorities:</span><o:p></o:p></p>
</div>
</blockquote>
<p>I think if we can find a solution that doesn't require priorities that it should by far be preferred. You have to think more from a user perspective. They have a Button, and they add an Event Handler to do something with the SPACE key. They run their
code, and they find SPACE just disappears and never arrives at their handler. However, if they add the handler in the Constructor of a Button subclass, or before the Skin is applied, then the handler does work. There should not be a difference for the user,
because the Event Handler system does not stipulate that there are internal handlers that are sharing this infrastructure; for the user the system looks like it is available solely for their use.<o:p></o:p></p>
<p>Let's say you now add priorities. What possible reason could a user have for adding an event handler (for SPACE key) that wouldn't work (too low priority) or doesn't work reliably (equal priority)? In other words, the only relevant priority for users is
the one that will make their handler work, which more often than not will be MAX.<o:p></o:p></p>
<p>Now let's say we have a Node, and we add several handlers:<o:p></o:p></p>
<p> Event.ANY (+10)<br>
KeyEvent.KEY_ANY (+20)<br>
KeyEvent.KEY_PRESSED (0)<o:p></o:p></p>
<p>What order are they going to be called? Without priorities that would be KEY_PRESSED, KEY_ANY, ANY<o:p></o:p></p>
<p>Now let's have a hierarchy of Nodes, A -> B -> C -- I add the following handlers:<br>
<br>
A: KeyEvent.KEY_PRESSED (+10)<br>
B: KeyEvent.KEY_PRESSED (0)<br>
C: KeyEvent.KEY_PRESSED (+20)<br>
<br>
Which one gets the event first? Does having a handler higher up the hierarchy trump priorities?<br>
<br>
Providing an alternative solution that doesn't expose the user to a priority system that further complicates an already complicated system would be a big win. If we can simply say to the user your filters/handlers will always go first that's a big win.<o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<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"">- application event filters</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">- application event handlers</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">- event handlers set by the skin</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">- ifUnconsumed-like handlers set by the skin</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">- ifUnconsumed-like handlers set by the application</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>
</blockquote>
<p>Let's say a KeyEvent.KEY_PRESSED is fired at a Control (focusOwner), then the order in which the event can be acted upon is:<br>
<br>
- Scene hotkeys (Cut/Copy/Paste etc)<br>
- Scene filters (set by user, KeyEvent.KEY_PRESSED first, then KeyEvent.ANY, then InputEvent.ANY, then Event.ANY)<br>
- Parent filters (set by user, same order as above...)<br>
- Control filters (set by user)<br>
- Control handlers (set by user)<br>
- Parent handlers (set by user)<br>
- Scene handlers (set by user)<br>
- Scene checks unconsumed status, then processes the unconsumed handlers in order<br>
- Scene default button handling and mnemonic handling (if still unconsumed at this stage)<br>
<br>
The order of the unconsumed handlers is the order they were registered in, which depends on where they were called from:<o:p></o:p></p>
<p>- ifUnconsumed called by Behavior filters set on Control<br>
- ifUnconsumed called by Skin filters set on Control (possibly to forward these events to an inner component although they should only do so when ifUnconsumed calls them back)<br>
- ifUnconsumed called by Behavior handlers set on Control<br>
- ifUnconsumed called by Skin handlers set on Control<br>
<br>
Note that Behavior always has the option to go first (and Skins should install their internal Behaviors early) by installing a filter. Behavior's handlers also go first, but can be overridden by a Skin event filter.<o:p></o:p></p>
<p>Also note: the handlers may still get "mixed up" (user/system handlers), but as all Behavior/Skins will use `ifUnconsumed` and so go last in all cases, this has become irrelevant.<br>
<br>
SO, neither Skin nor Behavior directly act on any incoming event, they only register their interest. No Skin internal components are directly receiving events here. Any event that is directly targeted at a Skin internal component can use regular means to
handle events as there will not be a conflict with user handlers as those components are private to the Skin.<o:p></o:p></p>
<p>--John<o:p></o:p></p>
<p><o:p> </o:p></p>
</div>
</div>
</div>
</div>
</body>
</html>