I was playing with key binding trying to create a small app where a timer is started with the press of an alt-arrow key and stopped when the key is released. The timers append Strings to a JTextArea telling which alt-arrow key is currently pressed.
This program works, and in fact if you press a combination of any two keys, both timers will work simultaneously, that is unless you press both up arrow and left arrow together. Can anyone see a bug in the program that explains why it won't work for these two particular keys when combined? Thanks in advance, Pete
My SSCCE,
KeyBindingEg.java
package javaforum2009;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class KeyBindingEg {
// parallel arrays -- sorry
private static final int[] ARROW_KEYS = {
KeyEvent.VK_UP, KeyEvent.VK_DOWN,
KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT };
private static final String[] ACTION_STRINGS = {
"Up", "Down",
"Left", "Right" };
private static final String PRESSED = "PRESSED";
private static final String RELEASED = "RELEASED";
private static final int TIMER_DELAY = 100;
private JPanel mainPanel = new JPanel();
private JTextArea textArea = new JTextArea(20, 30);
public KeyBindingEg() {
JPanel northPanel = new JPanel();
northPanel.add(new JLabel("This JTextField has the focus: "));
northPanel.add(new JTextField(10));
textArea.setEditable(false);
mainPanel.setLayout(new BorderLayout());
mainPanel.add(northPanel, BorderLayout.NORTH);
mainPanel.add(new JScrollPane(textArea), BorderLayout.CENTER);
setBindings();
}
private void setBindings() {
int context = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = mainPanel.getInputMap(context);
ActionMap actionMap = mainPanel.getActionMap();
for (int i = 0; i < ARROW_KEYS.length; i++) {
// timer is started on key press and stopped
// on key release.
Timer timer = new Timer(TIMER_DELAY, new KeyTimerListener(
ACTION_STRINGS));
timer.setInitialDelay(0);
// get input maps for all alt-arrow keys for both key press
// and key release
inputMap.put(KeyStroke.getKeyStroke(ARROW_KEYS[i],
InputEvent.ALT_DOWN_MASK, false), ACTION_STRINGS[i] + PRESSED);
inputMap.put(KeyStroke.getKeyStroke(ARROW_KEYS[i],
InputEvent.ALT_DOWN_MASK, true), ACTION_STRINGS[i] + RELEASED);
// set corresponding actions for the two different key presses above
actionMap.put(ACTION_STRINGS[i] + PRESSED, new ArrowKeyAction(false, timer));
actionMap.put(ACTION_STRINGS[i] + RELEASED, new ArrowKeyAction(true, timer));
}
}
@SuppressWarnings("serial")
private class ArrowKeyAction extends AbstractAction {
private boolean onKeyRelease;
private Timer swingTimer;
public ArrowKeyAction(boolean onKeyRelease, Timer swingTimer) {
this.onKeyRelease = onKeyRelease;
this.swingTimer = swingTimer;
}
public void actionPerformed(ActionEvent arg0) {
if (onKeyRelease) {
swingTimer.stop();
} else {
swingTimer.start();
}
}
}
private class KeyTimerListener implements ActionListener {
private String actionString;
public KeyTimerListener(String actionString) {
this.actionString = actionString;
}
public void actionPerformed(ActionEvent arg0) {
textArea.append(actionString + " pressed\n");
}
}
public JComponent getPanel() {
return mainPanel;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("KeyBindings Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new KeyBindingEg().getPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}