On Mon, 14 Jul 2025 17:39:50 GMT, Martin Fox <[email protected]> wrote:
> The Mac platform code sends a KeyEvent into the scene graph and if the event
> is not consumed it gets sent on to the system menu. But ComboBox and Spinner
> always consume the original event and fire a copy which the system menu
> ignores.
>
> In the past the platform code sent key events to the system menu even if the
> scene graph consumed them. This caused various bugs and was fixed in PR #1528
> leading to this issue.
>
> One could argue that a ComboBox or Spinner shouldn’t consume all key events
> but one could also argue that the system menu shouldn’t behave so differently
> from a standard MenuBar which will respond to any KeyEvent that reaches the
> top-level Scene no matter where it came from.
>
> This PR installs an event dispatcher which forwards KEY_PRESSED events on to
> the platform so any event bubbling through the dispatch chain can trigger the
> system menu. The dispatcher is placed by the top-level (non-popup) Window
> such that it’s the last dispatcher encountered while bubbling.
>
> In this PR once the key event reaches the GlassSystemMenu it passes the
> JavaFX key code and modifiers into the Mac platform code. This isn’t enough
> information to construct an NSEvent to pass to the main menu. Instead the
> code uses the code and modifiers to verify that the originating key down
> NSEvent (which it retained) should be sent on to NSApp.mainMenu.
>
> (There are other ways this could work. GlassSystemMenu could take the
> KeyEvent and perform its own accelerator matching entirely inside Java. This
> would match the way the standard MenuBar finds accelerators instead of using
> Apple’s matching algorithm. This PR is the more conservative approach,
> basically just shifting the timing of system menu matching without changing
> how it’s done.)
Java part looks like a simple enough change. I can't comment on the native
code.
> One could argue that a ComboBox or Spinner shouldn’t consume all key events
They definitely shouldn't, but I think that's how the poor man's focus/event
delegation is currently implemented in these controls.
modules/javafx.graphics/src/main/java/com/sun/javafx/stage/WindowEventDispatcher.java
line 67:
> 65: if (supported == SupportedState.TRUE && event.getEventType()
> == KeyEvent.KEY_PRESSED && (event instanceof KeyEvent)) {
> 66:
> Toolkit.getToolkit().getSystemMenu().handleKeyEvent((KeyEvent)event);
> 67: }
Suggestion:
if (supported == SupportedState.TRUE && event.getEventType() ==
KeyEvent.KEY_PRESSED && event instanceof KeyEvent ke) {
Toolkit.getToolkit().getSystemMenu().handleKeyEvent(ke);
}
Or perhaps the instanceof is even superfluous, as you already verify it is a
KEY_PRESSED event.
-------------
PR Review: https://git.openjdk.org/jfx/pull/1848#pullrequestreview-3017481535
PR Comment: https://git.openjdk.org/jfx/pull/1848#issuecomment-3070707798
PR Review Comment: https://git.openjdk.org/jfx/pull/1848#discussion_r2205630127