3

Background

Due to a known bug, JavaFX applications that use a MenuBar will keep the mnemonic selected ("latched") when the user presses Alt+Tab to switch to another program. When the user returns to the JavaFX application, the framework retains the latch.

Problem

If the user then presses a letter that corresponds to the mnemonic, then the letter is consumed and that menu is opened.

This behaviour is not what users have come to expect from an application: it interrupts workflow. Rather, Alt+Tab should not put the application in a state whereby the menu can open. This is conflating Alt by itself to trigger the menu with Alt+Tab, a conceptually different operation.

Other questions seek to disable the mnemonic, but we want to clear the latch so that when the user returns to the application, pressing a letter will not trigger opening the menu.

Question

How do you instruct a JavaFX application to clear the latched mnemonics when Alt+Tab is pressed (i.e., the application focus is lost)?

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315

1 Answers1

2

There are a couple of parts to this solution: releasing the mnemonics and consuming the Alt key press. Be sure to implement both.

Release mnemonics

One way to work around the bug is to add a focus listener to the application's Stage that fires a key released event for all known mnemonics. Given a Stage instance, we can iterate over all the main menu mnemonics as follows:

stage.focusedProperty().addListener( ( c, lost, show ) -> {
  if( lost ) {
    for( final var mnemonics : stage.getScene().getMnemonics().values() ) {
      for( final var mnemonic : mnemonics ) {
        mnemonic.getNode().fireEvent( keyUp( ALT, false ) );
      }
    }
  }
  else if( show ) {
    // Make sure the menu does not capture focus.
    stage.getScene().focusOwnerProperty().get().requestFocus();
  }
} );

We'll need a few helper methods to create the key release event:

public static Event keyDown( final KeyCode code, final boolean shift ) {
  return keyEvent( KEY_PRESSED, code, shift );
}

public static Event keyUp( final KeyCode code, final boolean shift ) {
  return keyEvent( KEY_RELEASED, code, shift );
}

private static Event keyEvent(
  final EventType<KeyEvent> type, final KeyCode code, final boolean shift ) {
  return new KeyEvent(
    type, "", "", code, shift, false, false, false
  );
}

With those methods in place, cycling windows by pressing Alt+Tab no longer opens the menu upon returning to the JavaFX application followed by pressing a mnemonic key (such as "f" for the "File" menu).

Consume event

Additionally, make the scene consume the event:

scene.addEventHandler( KEY_PRESSED, event -> {
  final var code = event.getCode();

  if( event.isAltDown() && (code == ALT_GRAPH || code == ALT) ) {
    event.consume();
  }
} );
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315