Unconsumed event handlers

Andy Goryachev andy.goryachev at oracle.com
Tue Nov 12 17:31:57 UTC 2024


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 *reliably*.

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:

- application event filters
- application event handlers
- event handlers set by the skin
- ifUnconsumed-like handlers set by the skin
- ifUnconsumed-like handlers set by the application

Please refer to the table in the "InputMap" section in this document:
https://github.com/andy-goryachev-oracle/Test/blob/main/doc/InputMap/InputMapV3.md

(it has more levels due to the desire to define additional levels specific for key mappings, but it's the same idea).

Now, this was proposed in assumption that we only have this problem at the controls level.  I've asked for any examples that suggest otherwise, so far received none, but let's wait a bit more.

My point is that prioritized event handlers solve the issue reliably.  Whether this is implemented in an FX-wide manner, or via the InputMap is less important at this stage.

At this stage, I think it's more important to eliminate the approaches that are guaranteed not to work, and outline the ideas that might work.

What do you think?

-andy



From: openjfx-dev <openjfx-dev-retn at openjdk.org> on behalf of Michael Strauß <michaelstrau2 at gmail.com>
Date: Saturday, November 9, 2024 at 23:13
To: openjfx-dev <openjfx-dev at openjdk.org>
Subject: Unconsumed event handlers
In JavaFX, user code and skins share the same event system. Since
invocation order is fundamentally important for events, this leads to
a lot of problems when skins add event handlers to their controls.
Assume user code adds an event handler to a control, and _then_ sets a
skin that also adds an event handler for the same event. In this case,
the user-provided handler is invoked first. If the skin is set
_first_, the skin gets the first chance to handle the event (see also
https://bugs.openjdk.org/browse/JDK-8231245).

Prioritized event handlers might be a solution for this problem, but
they are quite difficult to get right. Instead, I think we can get
almost all of the benefits using a much simpler solution: unconsumed
event handlers.

We add a new method to the `Event` class:

    <E extends Event> void ifUnconsumed(EventHandler<E> handler)

When an event filter or an event handler receives an event, it calls
the `ifUnconsumed` method with another event handler. Then, after both
phases of event delivery have completed, the list of unconsumed event
handlers associated with the event is invoked in sequence. Once an
unconsumed event handler consumes the event, further propagation is
stopped.

Skins and their behaviors would then always use the unconsumed form of
event handlers:

    // inside a skin/behavior
    control.addEventHandler(
        KeyEvent.KEY_PRESSED,
        e -> e.ifUnconsumed(event -> {
            // act on the event
        }));

This allows user code to see an event during both the capture and
bubble phases without any inteference of the skin or behavior. If user
code doesn't consume the event, the skin or behavior gets to act on
it.

In addition to that, we add a second new method to the `Event` class:

    void discardUnconsumedEventHandlers()

Calling this method in an event handler allows user code to discard
any unconsumed event handlers that have been registered prior. Let's
consider an example where user code wants to prevent a control skin
from acting on the ENTER key event, but it also doesn't want to
consume the event. Adding an event handler to the control, and then
calling `discardUnconsumedEventHandlers()` inside of the event handler
achieves exactly that: it allows the ENTER key event to flow freely
through the control without interacting with it, since its unconsumed
event handlers will never be called.

Here is the PR for this proposal: https://github.com/openjdk/jfx/pull/1633
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20241112/5e5e56aa/attachment-0001.htm>


More information about the openjfx-dev mailing list