Search code examples
javaswingkeyboard-shortcutskey-bindingskeystroke

How to define a shortcut for special keys in Java Swing, e.g. german umlaut key Ä?


How do I define a keyboard shortcut for top level special keys like german umlaut key Ä? I found a way to map unicode letters that are used for default american layout keys, see here. But the key event for the german umlaut key Ä is:

java.awt.event.KeyEvent[KEY_PRESSED,keyCode=0,keyText=Unknown keyCode: 0x0,keyChar='ä',keyLocation=KEY_LOCATION_STANDARD,rawCode=222,primaryLevelUnicode=228,scancode=40] on frame0 

The idea is to register a keyboard action:

import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;


public class KeyStrokeForGermanUmlaut {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.setPreferredSize(new Dimension(600, 400));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                JPanel panel = new JPanel();
                final JLabel label = new JLabel("Text shall change with shortcut");
                panel.add(label);
                panel.registerKeyboardAction(new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent event) {
                        label.setText("It is working!!!");
                    }
                }, KeyStroke.getKeyStroke("control typed Ä"), JComponent.WHEN_IN_FOCUSED_WINDOW);

                frame.getContentPane().add(panel);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

Solution

  • I am afraid there is something fishy in the handling of modifiers for CTRL. That is: when inspecting the received key modifier=InputEvent.CTRL_MASK, extended modifier=InputEvent.CTRL_DOWN_MASK. And the API's javadoc is a bit suspicious.

    Apart from that, Ä is not a special case, when "control" is left out.

    To make it work, I had to add a dirty hack: register a key listener, that calls the action itself. I must be overseeing something.

    For the rest I used an InputMap/ActionMap as intended. The input map does not seem to work, but to my understanding it does not work if added to a JTextField, or in the other answer (for Ä). The following works - in a horrible way.

    final JLabel label = new JLabel("Text shall change with shortcut");
    final KeyStroke key = KeyStroke.getKeyStroke((Character)'k',
            InputEvent.CTRL_DOWN_MASK, false);
    final Object actionKey = "auml";
    final Action action = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent event) {
            System.out.println("aha");
            label.setText("It is working!!!");
        }
    };
    label.addKeyListener(new KeyAdapter() {
    
        @Override
        public void keyPressed(java.awt.event.KeyEvent e) {
            if (e.isControlDown() && e.getKeyChar() == 'ä') {
                System.out.println("Ctrl-ä");
                label.getActionMap().get(actionKey).actionPerformed(null);
                // return;
            }
            super.keyPressed(e);
        }
    });
    label.getInputMap().put(key, actionKey);
    label.getActionMap().put(actionKey, action);