Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change mnemonic modifier key in Java/Swing

Setting focus hot keys in Swing is very easy:

  tfldPlantsNeeded = new JTextField( FIELD_LEN_MED );
  lblPlantsNeeded = new JLabel( "Plants Needed" );
  lblPlantsNeeded.setDisplayedMnemonic( 'p' );
  lblPlantsNeeded.setLabelFor( tfldPlantsNeeded );

This will give focus to the tfldPlantsNeeded JTextField when the user presses ALT+p. It also highlights/displays the character that will trigger the focus change. (In this case, when ALT is pressed, the 'P' in "Plants" is underlined.)

This is great ... well, kinda. On a Mac, when the user presses ALT (which is also Option on the Mac keyboard) the mnemonic is highlited, but the focus change isn't triggered when p is pressed too. If, however, the user presses Control + Option + p, then it works as "expected" and focus is changed. (As an aside, if the user DOES press Option + p, the currently focused text field will get funny characters inserted.)

I know that I can do this myself by specifying custom keybindings via getInputMap and getActionMap, but is there a way to change the application global mnemonic modifier so that we can use the automatic keybindings and trigger character highlighting? (In my case, I would like to use Command or Meta as the mnemonic modifer key.)

like image 474
Clayton Avatar asked Mar 11 '14 12:03

Clayton


1 Answers

Apparently this isn't as straightforward as you might think, but there is a way.

First of all, for menus (JMenu) there is a property which is controlled by the look and feel called Menu.shortcutKeyswhich you can set manually. This sets the mnemonic modifier for menus in the specific look and feel. If you want more information about this feel free to ask.

In order to set the mnemonic modifier for everything, you need to override the default toolkit (Toolkit). First of all, run a main method to find what it is with the following lines

System.out.println(System.getProperty("java.awt.headless"));
System.out.println(System.getProperty("awt.toolkit"));

If the first line is null of false (see java.awt.Toolkit getDefaultToolkit()) then the second line will give you the class name which is used as the default Toolkit for your system. I use Windows and the second line gives the output sun.awt.windows.WToolkit. Now create a class that overrides getFocusAcceleratorKeyMask in your default toolkit. For me it looks like this

public class MyToolkit extends WToolkit {

    @Override
    public int getFocusAcceleratorKeyMask() {
        return InputEvent.CTRL_DOWN_MASK;
    }
}

Finally, we have to tell the system to use it. In your application, put the line

System.setProperty("awt.toolkit", "packagename.MyToolkit");

where you need to set the correct package path to your class. Make sure this line is placed before starting any GUI related code, preferably in the first lines of main. This should now set CONTROL as the global mnemonic modifier (or use META_DOWN_MASK if that's what you want. Look at java.awt.event.InputEvent for MASK list.).

like image 104
user1803551 Avatar answered Sep 19 '22 07:09

user1803551