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.
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.
How do you instruct a JavaFX application to clear the latched mnemonics when Alt+Tab is pressed (i.e., the application focus is lost)?
There are a couple of parts to this solution: releasing the mnemonics and consuming the Alt key press. Be sure to implement both.
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).
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();
}
} );