Dispara um JButton com a barra de espaço ou a tecla Enter ou o clique do mouse

Estou tentando obter um JFrame simples com um único botão para disparar um evento quando algum desses eventos acontecer:

A tecla Enter é pressionada E o JButton tem focoA barra de espaço é pressionada E o JButton tem focoO JButton é clicado.

Parece que o Enter ea barra de espaço vêm "de graça" junto com o clique do mouse padrão usando addActionListener no JButton; O problema é que eu li que as ligações de teclas são dependentes da aparência e uso.

Eu tentei obter um comportamento universal em LaF adicionando Enter e barra de espaço ao mapa de ação do JButton, e até adicionei uma chave aleatória ("m") para garantir que o ActionMap estava fazendo o trabalho (era), mas agora o mouse clique está perdido. A única maneira de conseguir obter todas as teclas e o clique do mouse é usar o mapa de ação e o addActionListener.

Existe uma maneira de fazer com que essas ligações de teclas e mouse funcionem consistentemente em todos os LaF sem tentar detectar todos os LaFs possíveis que possam surgir? Posso registrar um único ouvinte de ação que será disparado em eventos de chave e mouse?

Minha solução favorita seria adicionar um clique do mouse ao mapa de ação do JButton e detectar qual tecla ou clique do mouse aconteceu dentro da ação.

Eu ainda estou aprendendo as coisas aqui, então isso provavelmente não é a melhor maneira ou a mais eficiente de fazer as coisas; Tenho certeza que é super engenharia. Este é um tipo de exercício de treinamento onde estou experimentando tudo o que posso conseguir. Qualquer e todos os comentários de estilo de codificação são bem-vindos!

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

public class Example extends JFrame {

// ============================
private class BtnListener extends AbstractAction {
    private static final long serialVersionUID = 1L;

    public void actionPerformed(ActionEvent ae) {
        System.out.println("\nclick button listener triggered");
        System.out.println(ae.getSource().getClass().toString());
    }
} // class BtnListener

private static final int NO_MODIFIER = 0;
private static final boolean ON_KEY_PRESS = false;
private static final KeyStroke ENTER_PRESSED = KeyStroke.getKeyStroke(
        KeyEvent.VK_ENTER, NO_MODIFIER, ON_KEY_PRESS);
private static final KeyStroke M_PRESSED = KeyStroke.getKeyStroke(
        KeyEvent.VK_M, NO_MODIFIER, ON_KEY_PRESS);
private static final KeyStroke SPACEBAR_PRESSED = KeyStroke.getKeyStroke(
        KeyEvent.VK_SPACE, NO_MODIFIER, ON_KEY_PRESS);
private JButton btnButton;
private final AbstractAction btnListener = new BtnListener();
private JPanel buttonPanel;
private JFrame frmMain;

public static void main(String[] args) {
    Example ex = new Example();
    ex.displayFrame();
}

Action btnActionListener = new AbstractAction() {
    private static final long serialVersionUID = 1L;

    public void actionPerformed(ActionEvent e) {
        System.out.println("\nkey button action triggerred");
        System.out.println(e.getSource().getClass().toString());
        if (e.getSource() instanceof JButton) {
            System.out.println("button");
        } else {
            System.out.println("Something else");
        }
    }
};

public Example() {
    initialize();
}

public void displayFrame() {
    try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (Throwable e) {
        e.printStackTrace();
    }
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                frmMain.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

private void initialize() {

    frmMain = new JFrame();
    btnButton = new JButton("Abutton");

    // Comment this out, you lose the mouse click
    btnButton.addActionListener(btnListener);

    // Comment out ActionMaps, but keep addActionListner (above), and
            // only lose M_PRESSED
    InputMap buttonFocusedMap = btnButton
            .getInputMap(JComponent.WHEN_FOCUSED);

    buttonFocusedMap.put(ENTER_PRESSED, "blah");
    btnButton.getActionMap().put("blah", btnActionListener);

    buttonFocusedMap.put(SPACEBAR_PRESSED, "blort");
    btnButton.getActionMap().put("blort", btnActionListener);

    buttonFocusedMap.put(M_PRESSED, "gaaak");
    btnButton.getActionMap().put("gaaak", btnActionListener);

    // Is there a way to add a mouse click to the ActionMap?

    buttonPanel = new JPanel();
    buttonPanel.add(btnButton);

    frmMain.getContentPane().add(buttonPanel);
    frmMain.setBounds(100, 100, 500, 432);
    frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

}

questionAnswers(2)

yourAnswerToTheQuestion