<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=Windows-1252">
<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:Calibri;
panose-1:2 15 5 2 2 2 4 3 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:"Iosevka Fixed SS16 ";
panose-1:2 0 5 9 3 0 0 0 0 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:10.0pt;
font-family:"Calibri",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"">Thank you, John.<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>
<div id="mail-editor-reference-message-container">
<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">John Hendrikx <john.hendrikx@gmail.com><br>
<b>Date: </b>Tuesday, October 31, 2023 at 16:13<br>
<b>To: </b>Andy Goryachev <andy.goryachev@oracle.com>, openjfx-dev@openjdk.org <openjfx-dev@openjdk.org>, Kevin Rushforth <kevin.rushforth@oracle.com><br>
<b>Subject: </b>Re: [External] : Re: Proof of concept pull request for Behavior API (PR 1265)<o:p></o:p></span></p>
</div>
<p>Hi Andy,<o:p></o:p></p>
<p>I'm sorry if you feel I blocked your proposal. Discussions better happen at a stage far before a PR is being reviewed, and instead of having these discussions here, we could have had them on the PR.
<o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt">I'll try and formalize my proposals.<o:p></o:p></span></p>
<p>--John<o:p></o:p></p>
<p><o:p> </o:p></p>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt">On 30/10/2023 20:32, Andy Goryachev wrote:<o:p></o:p></span></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Dear John:</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" style="margin-left:.5in"> I'm unsure what the JEP format would contribute here<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 benefit of JEP format is</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">a) to explicitly state the problem being solved (in the Motivation section)</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">b) to enumerate the public APIs</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" style="margin-left:.5in">I have several proposals, and some are too big for a single proposal (IMHO) which would you like me to focus on?<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 main reason I am asking you to go through the process is because you effectively blocked by InputMap proposal. I keep hearing that my proposal is not good for various
reasons, while there is a much better way for doing things, so let’s see it in full detail. It would be nice to have proof-of-concept code based on a complex control rather than a simple Button, but it is not a requirement, at least initially.</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 "">I still want to see code examples (pseudo code is fine) for my questions:</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 "">Q1. Changing an existing key binding from one key combination to another.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q2. Remapping an existing key binding to a different function.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q3. Unmapping an existing key binding.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q4. Adding a new key binding mapped to a new function.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q5. (Q1...Q4) scenarios, at run time.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q6. How the set behavior handles a change from the default skin to a custom skin with some visual elements that expects input removed, and some added.
</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q7. Once the key binding has been modified, is it possible to invoke the default functionality?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q8. How are the platform-specific key bindings created?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q9. How are the skin-specific (see Q6) handlers removed when changing the skins?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q10. When a key press happens, does it cause a linear search through listeners or just a map lookup?
</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 "">I think it is important to answer all questions during the discussion, as it helps all sides to understand how things work, and possibly make corrections. Since the bulk
of my proposal deals with key bindings and user-/skin- installed handlers, I would like to see how you propose to deal with these problems.</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 "">Another reason I asked you for a JEP is that you seem to brush aside my objections. For example, my objection to the stateless behavior was dealt with by inventing BehaviorContext,
which I basically take as an acknowledgement that behaviors are not stateless. So let’s see exactly you envision things by describing the public API and perhaps the proof of concept code should also have two non-trivial controls, just to see whether BehaviorContext
depends on the control class or not.</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" style="margin-left:.5in">How key bindings are done is IMHO more of an implementation detail of **specific** behaviors,<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 "">I categorically disagree with this statement. As an application developer, I want to be able to set/modify/unmap key bindings via common public mechanism, make sure that
the user mappings and handlers always take precedence over the skin ones, and make sure that skin changes leave the user mappings and handlers in place.</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 "">It is certainly not an implementation detail and not a property of any specific 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 "">Thank you, and I am looking forward to seeing answers to the questions posted earlier.</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>
<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 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">John Hendrikx <a href="mailto:john.hendrikx@gmail.com">
<john.hendrikx@gmail.com></a><br>
<b>Date: </b>Saturday, October 28, 2023 at 12:55<br>
<b>To: </b>Andy Goryachev <a href="mailto:andy.goryachev@oracle.com"><andy.goryachev@oracle.com></a>,
<a href="mailto:openjfx-dev@openjdk.org">openjfx-dev@openjdk.org</a> <a href="mailto:openjfx-dev@openjdk.org">
<openjfx-dev@openjdk.org></a>, Kevin Rushforth <a href="mailto:kevin.rushforth@oracle.com">
<kevin.rushforth@oracle.com></a><br>
<b>Subject: </b>Re: [External] : Re: Proof of concept pull request for Behavior API (PR 1265)</span><o:p></o:p></p>
</div>
<p>Hi Andy,<o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt">On 27/10/2023 19:10, Andy Goryachev wrote:<br>
<br>
<br>
</span><o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Dear John:</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 "">I think our goal is for all of us to agree on a solution which solves the problems. We are still talking, right?</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 "">I have to say - it is very difficult to have a meaningful conversation when questions are not being answered. It is even more difficult to do over email and time zones, as
the context can often be lost.</span><o:p></o:p></p>
</blockquote>
<p>I'm really a bit surprised, as I think I responded quite quickly to a lot of the posts surrounding the proposals, and also answered quite a lot of questions. The mailinglist format seems to have served Java quite well for this purpose for years now, and
if memory serves, earlier FX proposals also were discussed here. I'm unsure what the JEP format would contribute here, given that it does not allow for inline comments or threads, but I'm not unwilling to try my hand at one.<o:p></o:p></p>
<p class="MsoNormal"><br>
<span style="font-size:11.0pt"><br>
<br>
</span><o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<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 "">To reiterate, a proposal in a JEP format would be nice, so we can see the public API.</span><o:p></o:p></p>
</blockquote>
<p>Alright, this will take a bit of time. I have several proposals, and some are too big for a single proposal (IMHO) which would you like me to focus on?<o:p></o:p></p>
<p>1. A public Behavior API with the initial focus on being able to reuse and replace default behaviors<o:p></o:p></p>
<p>This proposal would like to achieve a clear definition of a Behavior and clear separation (to aid in reusability and creation). It would define a Behavior interface, and a clean way of installing/uninstalling a behavior on controls. This would be primarily
the Behavior/BehaviorContext part of my sample PR <a href="https://urldefense.com/v3/__https:/github.com/openjdk/jfx/pull/1265__;!!ACWV5N9M2RV99hQ!LvWBWlmjB-JYcKnpZTbvjYwd1CItXTmycfx2D-BYmkbS7lxG6f4kwt2bmokpBwh63Gg_MNX5JzP747J1wgPuPY6Rq1H1$">
https://github.com/openjdk/jfx/pull/1265</a>, leaving the more controversial event definition parts out for now<o:p></o:p></p>
<p>1.1. A possible extension of the above Behavior API to allow changing high level behavior<o:p></o:p></p>
<p>I'm not sure yet what would be a good approach here. I would probably either lean towards reusing the Event system for this, or doing this with overridable methods; ie. in order to override a function, listen for its event and call different code or trigger
a different event; or, ensure there is an overridable method so it can be overriden directly in code.<o:p></o:p></p>
<p>1.2. An extension to the above behavior API to allow for more user friendly key rebinding<o:p></o:p></p>
<p>The idea here would be to create a custom behavior (allowed by 1.), call into a behavior you want to modify to install its defaults, and then make changes after. There is more than one possible approach here. One I raised earlier was offering more specific
methods on BehaviorContext. Another possiblity is to make it specific to certain behaviors only (MappableBehavior), or behaviors that can somehow provide an InputMap (without entangling everything).<o:p></o:p></p>
<p>2. An improved event handling system (Michael Strauss already did some work there) that would allow users to override or disable default event processing<o:p></o:p></p>
<p>This would be a low-level improvement that would allow 3rd parties to override large parts of JavaFX in a supported manner. It would open the way to a 3rd party behavior system or navigation system, but also simpler things like just changing a key mapping,
even ones claimed by behaviors currently. As it is a low level API, this would be somewhat cumbersome for seemingly simple tasks, and the various platforms would need to be supported manually.<o:p></o:p></p>
<p>In essence the above proposal would allow user installed event handlers to receive any event before a default handler can get to it, so that say remapping the LEFT_ARROW key is actualy possible and doesn't magically disappear (many new users, including me
at the time were/are somewhat surprised that an event handler installed on the control is not receiving all events). The root cause of this is the sharing of the event handling lists on the control with (magically) installed behaviors. The above proposal
would change this (in a backwards compatible way) to work more like how default exception handlers work -- only unconsumed events that bubble up to the root level are considered for default behavior actions.<o:p></o:p></p>
<p>------<o:p></o:p></p>
<p>As you can see, one my problems with answering the key rebinding questions is that IMHO this more of a later extension on a Behavior API; this means to get to the key remapping design, there first would need to be a Behavior API design. How key bindings
are done is IMHO more of an implementation detail of **specific** behaviors, as there are probably more ways to do this. So for my proposals, a somewhat fleshed out Behavior API design is an important prerequisite before offering key rebinding.
<o:p></o:p></p>
<p>If we can advance this design far enough, we may see a way to do this without needing a Behavior API first; for example, we could have a Behavior interface, and a subtype, MappableBehavior; only behaviors of that sub type support key remapping, while general
behaviors don't have to. This would make the key rebinding just something that **some** behaviors support, and not a general feature if it instead was added to say Control, Behavior or BehaviorContext. This may be a short cut that we could take to get to
key rebinding quickly, without closing off a future behavior API.<o:p></o:p></p>
<p>Again, thanks for reading, I look forward to some feedback, and as said, I will try put some time towards writing a JEP. I'm also happy to collaborate on this once a design direction becomes a bit more clear.<o:p></o:p></p>
<p>--John<o:p></o:p></p>
<p class="MsoNormal"><br>
<span style="font-size:11.0pt"><br>
<br>
</span><o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<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 "">Please, if you have time, answer these questions. A short pseudo-code example will be fine.</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 "">Q1. Changing an existing key binding from one key combination to another.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q2. Remapping an existing key binding to a different function.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q3. Unmapping an existing key binding.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q4. Adding a new key binding mapped to a new function.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q5. (Q1...Q4) scenarios, at run time.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q6. How the set behavior handles a change from the default skin to a custom skin with some visual elements that expects input removed, and some added.
</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q7. Once the key binding has been modified, is it possible to invoke the default functionality?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q8. How are the platform-specific key bindings created?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q9. How are the skin-specific (see Q6) handlers removed when changing the skins?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q10. When a key press happens, does it cause a linear search through listeners or just a map lookup?
</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 "">Lastly, I do think prototyping the alternative proposal using simple control like Button is insufficient. TextArea would be much better, as it has a ton of key bindings,
platform-specific logic, various handlers that do and do not consume events by default.</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 "">Thank you</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 "">P.S. I noticed that I switched my PR to Open by mistake. Sorry, it’s back in Draft.</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 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">John Hendrikx <a href="mailto:john.hendrikx@gmail.com">
<john.hendrikx@gmail.com></a><br>
<b>Date: </b>Thursday, October 26, 2023 at 02:15<br>
<b>To: </b>Andy Goryachev <a href="mailto:andy.goryachev@oracle.com"><andy.goryachev@oracle.com></a>,
<a href="mailto:openjfx-dev@openjdk.org">openjfx-dev@openjdk.org</a> <a href="mailto:openjfx-dev@openjdk.org">
<openjfx-dev@openjdk.org></a>, Kevin Rushforth <a href="mailto:kevin.rushforth@oracle.com">
<kevin.rushforth@oracle.com></a><br>
<b>Subject: </b>Re: [External] : Re: Proof of concept pull request for Behavior API (PR 1265)</span><o:p></o:p></p>
</div>
<p>The normal procedure I think is also to first provide a JEP for review, before starting on the implementation...<o:p></o:p></p>
<p>Given the doubts raised, feedback given and potential alternatives proposed, I don't see why you are still moving forward with your own proposal. The critiques I've given have been mostly hand waved with arguments that have no place in JEP evaluation (time
restrictions, existing code already works this way, false equivalency with MVC pattern), and therefore have IMHO not been taken serious at all.<o:p></o:p></p>
<p>This leaves me in the position of putting in a lot of work that will essentially be ignored as I feel an (internal) decision has already been reached, regardless of the feedback on the mailinglist.<o:p></o:p></p>
<p>The (partial) proposal I've made, and also simpler proposals so that 3rd parties could do a keybinding implementation, should be sufficient to reconsider the current proposal that is being moved forward.<o:p></o:p></p>
<p>I'll reiterate my problems with your proposal:<o:p></o:p></p>
<p>- Introduces a lot of API for what is essentially the configuration of internal event handlers<br>
- The proposed API partially overlaps with the existing event handler API, meaning that some keys could be changed with just event handlers, while some can only be changed with the BaseBehavior API; it also provides for creating new functions and assigning
them to keys, essentially a new (very limited) API for what was already possible in the much more flexible event handling API<br>
- Introduces the term "Behavior" in public API without clearly specifying what that is, nor showing enough forethought that may make it possible in the future to have public Behaviors<br>
- Introduces the term "InputMap" in public API, which is just an implementation detail of the internal event handlers<br>
- Doesn't address the real issue IMHO, which is that JavaFX Skins/Behaviors install their Event Handlers directly on Controls, mixing them with user event handlers leading to all sorts of unpredictable behavior due to call order and internal handlers essentially
stealing and consuming events before the user has a chance to look at them (and thus blocking any 3rd party key alterations) which leads to the (false) need to change key bindings and Behaviors directly...<o:p></o:p></p>
<p>So if you want me to work on such a proposal, fully fleshing it out, I would like to know if it will be given consideration. I would also like some more feedback on what is already there, as I think it is sufficient to decide if a full proposal is worth
it or not.<o:p></o:p></p>
<p>My proposals in short:<o:p></o:p></p>
<p>1.<o:p></o:p></p>
<p>- Fix the issues with Events being stolen before users can get a them<br>
- Users should be able to have priority on Events, Michael Strauss already has a PR that fixes the issue in part<br>
- Events should not be consumed when not used (navigation does this) as this precludes the user being able to change their meaning<br>
- Even better would be if internal event handlers were isolated and did not mix themselves with user event handlers at all<o:p></o:p></p>
<p>The above can be done separately, and should already make it possible to do a lot of things that were close to impossible before when it comes to changing key handling, but certainly not everything.<o:p></o:p></p>
<p>- Building on top of the improved event handling system, introduce a flag to indicate an event is not to be consumed by internal event handlers<br>
<br>
These two together can form the basis for a 3rd party Behavior implementation as standard behavior can be prevented from occurring. It leaves platform dependent behavior to be addressed by such a 3rd party / user implementation as it is a very low level API.
Any key remapping logic would be provided by the 3rd party API. <o:p></o:p></p>
<p>2.<o:p></o:p></p>
<p>I also have a more fleshed out alternative proposal that attempts to introduce Behaviors into JavaFX as a first class concept, instead of a potential 3rd party add-on. Recap:<o:p></o:p></p>
<p>- Introduce a Behavior interface with a single method "install" to be called by a Control<br>
- The "install" method is provided a context object, BehaviorContext. This indirects any changes the Behavior can make to a Control, so the Control is fully aware of all changes and can uninstall them without further co-operation from the behavior.<br>
- The BehaviorContext provides low level functions to add/remove event handlers and listeners, but can also provide higher level functions (in perhap a later PR) to allow for some kind of control provided input map system<br>
- Standard Behaviors can be made public and can be easily subclassed or composed as they need not have any state. State is tracked inside the behavorial installed listeners and handlers themselves (either directly or by referring to some shared State object).<br>
- Clear separation of concerns; Behaviors, a resuable concept that can be applied to a control; BehaviorContext, manages behavior lifecycle by abstracting away direct Control access; behavior state management left up to the implementation and created (on demand
and as needed) when "install" is called.<br>
- Indirection from key mapping to semantic meaning is provided by introducing control specific events. These semantic events can be handled, filtered and consumed like all other events, allowing for changing/remapping/blocking or ignoring; this part can be
left out from an initial implementation to further evaluate how such events might interact with Skins that need specific events (there is nothing stopping us from having some of these semantic events be handled by the Control directly, and some by the specific
needs of the Skin)<o:p></o:p></p>
<p>To get at the internal key mappings, you'd need to subclass or compose a Behavior. The Behaviors are setup to allow this easily. To modify the bindings of a Control, one would install such a modified Behavior as a whole; overkill perhaps for one binding
change, but convenient when multiple bindings are changed, and reusable accross controls (the Behavior only need to be created once).<o:p></o:p></p>
<p>The proposal also includes an indirection between Key/Mouse event and its semantic meaning. This is achieved by firing higher level more meaningful events, but that's not the only option; it could also be done with overridable methods on the Behavior, or
a behavior specific interface if the Event based proposal is seen as too audacious.<o:p></o:p></p>
<p>This proposal advocates a clear seperation of the Behavior from the Skin, essentially making them Controller and View, where the View has no knowledge of the Controller. I see no reason why this wouldn't be possible, given that it is a standard pattern.
That existing controls may be difficult to untangle is IMHO irrelevant, especially when this can be done one at a time. I realize that Controllers (Behaviors) may have functions that are sort of View (Skin) specific; this is not an issue, as it should be
fine to trigger a behavior without it being consumed; unconsumed behaviorial events just bubble up. This allows Behaviors to have events specific to a Skin without them interfering if they're unused by an alternative Skin. An alternative Skin that also needs
new behavior will also need to create a new behavior to go along with it (or when paired with the standard one, accept that those new behaviors won't be triggered).<o:p></o:p></p>
<p>Thanks for reading.<o:p></o:p></p>
<p>--John<o:p></o:p></p>
<p> <o:p></o:p></p>
<p> <o:p></o:p></p>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt">On 26/10/2023 00:59, Andy Goryachev wrote:</span><o:p></o:p></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Dear John:</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 "">It is difficult to review the alternative proposal for a number of reasons. A prototype is a good start, but for any proposal to go forward we need a bit more work. Let
me enumerate the steps that we expect:</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 "">1. Provide an overview of the proposal following a JEP outline:</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"><b><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Summary</span></b><o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Goals</span></b><o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Non-Goals</span></b><o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Motivation</span></b><o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Description</span></b><o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Alternatives</span></b><o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Risks and Assumptions</span></b><o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Dependencies</span></b><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 "">2. A draft PR that provides a proof of concept, using, in this case, a few complex controls like TextArea, TableView, ComboBox.</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 "">3. Address the question raised earlier, perhaps by providing code examples (pseudo code is acceptable, I 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 "">More specifically, I’d like to know how the following concerns will be addressed by the new proposal:</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 "">Q1. Changing an existing key binding from one key combination to another.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q2. Remapping an existing key binding to a different function.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q3. Unmapping an existing key binding.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q4. Adding a new key binding mapped to a new function.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q5. (Q1...Q4) scenarios, at run time.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q6. How the set behavior handles a change from the default skin to a custom skin with some visual elements that expects input removed, and some added.
</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q7. Once the key binding has been modified, is it possible to invoke the default functionality?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q8. How are the platform-specific key bindings created?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q9. How are the skin-specific (see Q6) handlers removed when changing the skins?</span><o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 "">Q10. When a key press happens, does it cause a linear search or a map lookup?
</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 "">Thank you</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 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">John Hendrikx <a href="mailto:john.hendrikx@gmail.com">
<john.hendrikx@gmail.com></a><br>
<b>Date: </b>Tuesday, October 24, 2023 at 04:58<br>
<b>To: </b>Andy Goryachev <a href="mailto:andy.goryachev@oracle.com"><andy.goryachev@oracle.com></a>,
<a href="mailto:openjfx-dev@openjdk.org">openjfx-dev@openjdk.org</a> <a href="mailto:openjfx-dev@openjdk.org">
<openjfx-dev@openjdk.org></a><br>
<b>Subject: </b>Re: [External] : Re: Proof of concept pull request for Behavior API (PR 1265)</span><o:p></o:p></p>
</div>
<p> <o:p></o:p></p>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt">On 23/10/2023 23:57, Andy Goryachev wrote:</span><o:p></o:p></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 ""> </span><span style="font-size:11.0pt">
</span><o:p></o:p></p>
<p class="MsoNormal" style="margin-left:.5in">You'd create a new class, `MyBehavior`,<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 "">By “customizing” I also mean at run time. Creating new classes wouldn’t work.
</span><o:p></o:p></p>
</blockquote>
<p>This would also work at runtime, as the class you create can <span style="background:yellow;mso-highlight:yellow">
be instantiated with parameters that control its key binding behavior</span>. Even though the standard Behaviors should probably be singletons (so they can be reused and composed) or have public well documented constructors, a custom behavior created by the
user has no such re-usability restrictions.<o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16 ""> </span><o:p></o:p></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="background:yellow;mso-highlight:yellow">coupling</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 "">I don’t think it is our choice - it is up to the skin designed. If they add a node that needs to take input, or if the behavior is drastically different, it is almost impossible
to create a common interface. So skin and behaviors are coupled, besides we have to design for the worst case (of a totally different skin). The division between S and B comes mostly from the division between V and C in MVC. From a distance, the user does
not see it at all - all they see is a control.</span><o:p></o:p></p>
</blockquote>
<p>JavaFX is not doing MVC.<o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:11.0pt">In MVC, the 3 components are not entangled; Model refers View, Controller refers View and Model, View refers nothing; in JavaFX the View (Skin) creates the Controller (Behavior); the View especially normally
can be created without any dependencies, and can be tested as such; with Skins being tightly coupled to both Behaviors and Controls, that doesn't even come close.</span><o:p></o:p></p>
<p>For it to be MVC you'd need to:<o:p></o:p></p>
<p>- Remove reference from Skin to Control<br>
- Do not let Skins create Behaviors<br>
- Instantation order should be, create a Skin first (with no Control reference), then create the Control (with Skin as parameter or setter), then create a Behavior (with Control as parameter, and one or more Views (Skins))<o:p></o:p></p>
<p>What JavaFX is exactly, I don't know. It doesn't follow MVC (even though it claims to) because in the current setup the Skin is both V and C; that's not MVC. At most it is MS (Model Skin), and so there is no reason to expose anything beyond the Skin then,
as that would just be pretending to be something that it is not.<o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<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 "">This suggest another metric at judging the usefulness of a design - how easy it is to understand and perform 80% of most common tasks.</span><o:p></o:p></p>
</blockquote>
<p class="MsoNormal"><span style="font-size:11.0pt">Now that I explained how key remappings would work, I don't see how this would disqualify the alternative proposal.<br>
<br>
<br>
<br>
<br>
</span><o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<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 "">There are more interesting ideas at the end of the message I am replying to - fxml, css, global changes - these go far beyond the simple input map improvement. I did mention
this already, but neither open source community, nor my employer might have the resources to make such drastic changes.</span><o:p></o:p></p>
</blockquote>
<p class="MsoNormal"><span style="font-size:11.0pt">I didn't mention FXML, but yes, I gave some other things to think about. As for how drastic any of those are, that remains to be seen. Certainly the global changes would not be that hard at all. The CSS
proposal would need some research if there is some will to go there; it assumes that the information needed can be transported in a reasonable manner to the key binding system using the existing CSS infrastructure.<br>
<br>
<br>
<br>
<br>
</span><o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<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 "">So we have to be realistic, I think. We are travelling to a different planet in a small spaceship and we only have so much material and oxygen to play with. A simple improvement
that helps 80% of use cases might be better than a major redesign (I still think the event proposal involves major redesign).</span><o:p></o:p></p>
</blockquote>
<p>I think that if that's the case that we'd better focus on making it possible for 3rd parties to deliver these features, and do the simplest thing that would allow them to do so. That would be prioritized event handlers (so a 3rd party can always intercept
before the Skin/Behavior gets to it) + a flag to skip system event handlers (ala consumed) to allow bubbling up.<o:p></o:p></p>
<p>On top of that any key remapping or behavior change system can be constructed already.<o:p></o:p></p>
<p>--John<o:p></o:p></p>
</div>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</body>
</html>