<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Hi,<br>
    </p>
    <p>The InputMap is a user of the event system.  It is basically a
      configurable event handler for a limited number of event types. 
      You could write one right now, expose it, and configure mappings,
      and in fact, to save on event handlers, this is exactly how many
      handlers already work.  Introducing it as an integral part of say
      Control immediately raises concerns; is InputMap going to be yet
      another event handler that users will have to fight when they
      install their own?  At most I see this as part of a public
      Behavior API, where the Behavior can install (default) handlers,
      that then delegate to an accessible input map for that Behavior. 
      Swing doesn't have a Control/Behavior/Skin split, but FX does, and
      I think we should remain committed to that instead of making some
      Swing/QT/Compose Frankenstein hybrid here by copying features
      without thinking about the bigger picture and how they really fit
      into FX. <br>
    </p>
    <p>Furthermore, the current private InputMap implementation is, to
      put it midly, insanely inefficient, and so I find it incredibly
      hard to justify using even parts of that design. Everything in it
      is Observable, but nobody will be able to monitor it all for
      changes as that would entail installing hundreds of handlers for
      the average TextField input map.  What's also inefficient is that
      this input map gets recreated for each control, leading to several
      kilobytes of overhead for every TextField in your application.
      There is just no reason to duplicate input maps like this as
      they're all going to be same 99.999% of the time. <br>
    </p>
    <p>If we want InputMaps, then I think we need to solve the
      Skin/Behavior split first -- this alone will be a huge win for FX,
      as reskinning then becomes trivial, finally fulfilling the promise
      that FX has made for easily reskinnable controls, as you no longer
      lose the default platform behavior.  Then with Behaviors also
      being replaceable, one can much easier allow for custom behaviors
      that expose fancy things like a fully customizable InputMap
      (although please, let's not make it observable, and let's
      de-duplicate them).</p>
    <p>--John<br>
    </p>
    <br>
    <div class="moz-cite-prefix">On 13/01/2026 18:35, Andy Goryachev
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:DS0PR10MB72717B582C952C065CDA955AE58EA@DS0PR10MB7271.namprd10.prod.outlook.com">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        I agree with Martin that this issue is mostly limited to
        Controls because of the skins.  What was the main objection to
        the InputMap idea I proposed?</div>
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        <br>
      </div>
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        I do want to ask Martin one thing though: what do you mean by
        "The only obvious gap in the public API is that there’s no way
        for a handler or filter to communicate with the dispatcher that
        invoked it."  Can you give an example?</div>
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        <br>
      </div>
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        Thanks!</div>
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        <br>
      </div>
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        -andy</div>
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        <br>
      </div>
      <div dir="ltr"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
        <br>
      </div>
      <div id="mail-editor-reference-message-container">
        <div class="ms-outlook-mobile-reference-message skipProofing"
style="text-align: left; padding: 3pt 0in 0in; border-width: 1pt medium medium; border-style: solid none none; border-color: rgb(181, 196, 223) currentcolor currentcolor; font-family: Aptos; font-size: 12pt; color: black;">
          <b>From: </b>openjfx-dev <a class="moz-txt-link-rfc2396E" href="mailto:openjfx-dev-retn@openjdk.org"><openjfx-dev-retn@openjdk.org></a>
          on behalf of Martin Fox <a class="moz-txt-link-rfc2396E" href="mailto:martinfox656@gmail.com"><martinfox656@gmail.com></a><br>
          <b>Date: </b>Tuesday, January 13, 2026 at 09:00<br>
          <b>To: </b>John Hendrikx <a class="moz-txt-link-rfc2396E" href="mailto:john.hendrikx@gmail.com"><john.hendrikx@gmail.com></a><br>
          <b>Cc: </b>OpenJFX <a class="moz-txt-link-rfc2396E" href="mailto:openjfx-dev@openjdk.org"><openjfx-dev@openjdk.org></a><br>
          <b>Subject: </b>Re: [External] : Re: Default event handlers<br>
          <br>
        </div>
        <div class="ms-outlook-mobile-reference-message skipProofing">I
          didn’t intend to re-open all of these debates. I just wanted
          to point out that JavaFX in general uses dispatchers to
          process events so there’s no existing concept of default
          handlers outside of Control. If Control had implemented
          InputMap using a dispatcher we probably wouldn’t be having
          this conversation.</div>
        <div dir="ltr"
          class="ms-outlook-mobile-reference-message skipProofing"><br>
        </div>
        <div class="ms-outlook-mobile-reference-message skipProofing">I
          still believe this is a local problem for Control and it can
          craft its own solution. It doesn’t even have to involve
          handlers; look at how Scene and Menu handle accelerators.
          Whatever Control wants to do almost all of the tools are
          there. The only obvious gap in the public API is that there’s
          no way for a handler or filter to communicate with the
          dispatcher that invoked it. Rather than add a specialized bit
          like this PR does I thought it might be worth considering a
          more generalized solution (I can think of a few) but I’m
          actually fine with preventDefault() since it’s based on an
          existing standard.</div>
        <div dir="ltr"
          class="ms-outlook-mobile-reference-message skipProofing"><br>
        </div>
        <div class="ms-outlook-mobile-reference-message skipProofing">Martin</div>
        <div dir="ltr"
          class="ms-outlook-mobile-reference-message skipProofing"><br>
        </div>
        <blockquote>
          <div class="ms-outlook-mobile-reference-message skipProofing">On
            Jan 13, 2026, at 4:52 AM, John Hendrikx
            <a class="moz-txt-link-rfc2396E" href="mailto:john.hendrikx@gmail.com"><john.hendrikx@gmail.com></a> wrote:</div>
          <div dir="ltr"
            class="ms-outlook-mobile-reference-message skipProofing"><br>
          </div>
          <p class="ms-outlook-mobile-reference-message skipProofing"><br>
          </p>
          <div class="moz-cite-prefix">On 13/01/2026 00:43, Andy
            Goryachev wrote:</div>
          <blockquote>
            <div dir="ltr"
              class="ms-outlook-mobile-reference-message skipProofing"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt;">
              <br>
            </div>
            <div dir="ltr"
              class="ms-outlook-mobile-reference-message skipProofing"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt;">
              The reason I mentioned #2 is that it is somewhat relevant
              to the discussion, as in "why do we need to write custom
              dispatchers at all?"  There should be only two methods, in
              my opinion, one that dispatches an event that bubbles up
              (with filters and handlers), and one that sends an event
              to a single target Node and nothing else.
               <rant>Somehow, Swing got the Events right - it
              manages to dispatch one (1) event in total, and the
              dispatching stops once the event is consumed.  The FX
              decided it needed to reinvent the wheel and leave multiple
              booby traps in the process.</rant></div>
          </blockquote>
          <p class="ms-outlook-mobile-reference-message skipProofing">Although
            I agree that how FX solved events is sub-optimal, there is a
            real need here to communicate to the EventHandler on which
            object it resides.  EventHandler instances are expensive
            when you need to attach one to every Cell in a TableView,
            and so to re-use a single instance, you need to know which
            Cell the event applies to.  The source field (which is
            supposed to be constant) has been abused for this, making
            events non-constant requiring cloning before they can be
            dispatched to their final target.  This cloning then caused
            the "isConsumed" problem.  Perhaps we should just make the
            source field mutable as well, so the cloning isn't needed.</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">The
            solution to this problem at the time should not have been to
            modify events, but to have made event handlers be
            BiConsumers, with the Event **and** Node being passed to the
            callback (and a "convenience" method that delegates to the
            BiConsumer variant that accepts only Consumer<Event>
            -- we may be able to still do this...)</p>
          <blockquote>
            <div dir="ltr"
              class="ms-outlook-mobile-reference-message skipProofing"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt;">
              <br>
            </div>
            <div dir="ltr"
              class="ms-outlook-mobile-reference-message skipProofing"
style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt;">
              This isn't exactly rocket science, we should be able to
              figure something out.  Maybe there is another option that
              will satisfy everyone?</div>
          </blockquote>
          <p class="ms-outlook-mobile-reference-message skipProofing">I
            think the issue isn't so much in event dispatching, but in
            the Skin/Behavior system itself.  Skin/Behaviors in FX is
            like giving root access to every user on your system.  Sure
            it is convenient that everyone can do whatever they want,
            and as long as everyone behaves, everything works great. 
            However one malicious user can interfere with others or
            leave behind hooks that later come to bite you.</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">Controls
            are HOSTS for Skins and Behaviors.  Skins and Behaviors are
            clients.  They should be restricted to a very specific
            subset of functionality that benefits the host and is
            predictable for the host:</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">-
            Skins get ownership of the children list of the Control;
            while a Skin is installed, the host should not be allowed to
            make modifications<br>
            - Skins can monitor properties for changes but this should
            never lead to a direct observable change on the main control
            that a subsequent installed listener may observe; in other
            words, listener order should be irrelevant for what the Skin
            does in order to share the listener infrastructure without
            interference.  Skins are free to directly take action on the
            children (which they own exclusively), just not on the main
            control; such actions should instead be deferred, usually by
            requesting a layout (this is usually already the case, but
            it is good to make this explicit so we can decide what a
            Skin is doing is a bug or not).<br>
            - Behaviors can react to events at the lowest precedence,
            and exclusively only take action when receiving an event;
            this means that blocking all events will automatically mean
            the Behavior no longer does anything, but also that
            selectively blocking events allows some control over
            Behaviors<br>
            - Behaviors can co-modify properties on the Control, but
            this should be clearly documented; controls are free to
            restrict this set (ie. a Behavior has no business modifying
            the "wrapText" property, or things like layout properties --
            most often they do their work through pseudo class changes
            and modifying the value a control represents).</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">That
            should really be all that is needed for a functioning
            Skin/Behavior system; no need for root access.</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">Of
            course, root access to the Control is a ship that has sailed
            a long time ago; but that doesn't mean we can't introduce a
            client API for Skins/Behaviors.  All that really takes is
            passing an object to the Skin/Behavior when it is installed.
            This object is an interface with which the Skin/Behavior can
            do their work. Should they choose to not circumvent this
            API, and do all their work through this API, they can remove
            all their clean-up code, as the Control can now do this
            automatically.  This will greatly simplify skins, and remove
            a whole avenue of potential bugs.</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">All
            work done through this API can be monitored by the Control.
            The control can:<br>
            - Track what is installed (for later clean-up)<br>
            - Reject installation of listeners/handlers it doesn't want
            to expose<br>
            - Ensure that event handlers are installed at lowest
            precedence.  This can be kept internal, so many solutions
            are possible: separate lists, default event handlers
            (internal API), priorities, etc.</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">Everything
            you'd expect a host Control to be able to do, including
            forcefully removing all traces of a previously installed
            Skin, and disallowing it further access should it attempt to
            use the API again after a new Skin is installed. That's
            however not a requirement; all we'd need is that interface,
            and encourage Skins/Behaviors to use it.  Correctly behaved
            Skins/Behaviors then get all the benefits, and will stop
            interfering with user code.  This means of course
            modifications to existing skins, but it is mostly in their
            registration logic (which I think we modified like 5 times
            already).</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">The
            minimum API needed can be fairly small, and does not need to
            include accessors for every property and handler with some
            smart signatures.  For example:</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">   
            <span
style="font-family: Consolas; font-size: 11pt; background-color: rgb(255, 255, 255);">
              <T, P </span><span
style="font-family: Consolas; font-size: 11pt; color: rgb(0, 0, 160); background-color: rgb(255, 255, 255);"><b>extends</b></span><span
style="font-family: Consolas; font-size: 11pt; background-color: rgb(255, 255, 255);"> ReadOnlyProperty<T>>
            </span><span
style="font-family: Consolas; font-size: 11pt; color: rgb(0, 0, 160); background-color: rgb(255, 255, 255);"><b>void</b></span><span
style="font-family: Consolas; font-size: 11pt; background-color: rgb(255, 255, 255);"> addListener(Function<C,
              P> supplier, Consumer<T> subscriber)</span></p>
          <p class="ms-outlook-mobile-reference-message skipProofing">Allows
            installation of a listener by doing:</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">   
            <span
style="font-family: Consolas; font-size: 11pt; background-color: rgb(255, 255, 255);">
              api.addListener(Slider::minProperty, v -> { ... });</span><br>
            <br>
            In this way we can isolate and track what Skins/Behaviors
            are doing, ensure they don't interfere with user operations
            on the Control and also ensure guaranteed clean-up (if they
            refrain from accessing the Control directly).</p>
          <p class="ms-outlook-mobile-reference-message skipProofing">--John</p>
          <p class="ms-outlook-mobile-reference-message skipProofing"><br>
          </p>
        </blockquote>
        <div dir="ltr"
          class="ms-outlook-mobile-reference-message skipProofing"><br>
        </div>
      </div>
    </blockquote>
  </body>
</html>