Key Bindings using the arrow keys

Following is some code that allows you to move a component around the screen using the arrow keys. I've noticed a problem and I'm just wondering if its Java or my keyboard.

Lets start with an example that works:

Press the down and right keys. Then press either the up or left key. The image moves proving that it supports 3 keys.

Now for the problem:

Press the up and left keys. Then press either the down or right key. Three things to notice:

a) the direction doesn't change when the third key is pressed

b) no output is displayed, so the ActionListener is not being invoked

c) after a short time, the program starts beeping

Now try rerunning the code after removing the comments that assign the key bindings to the "a, s, d, f" keys. Redo the above test and it works even if all four keys are pressed.

I don't remember this problem when I wrote the code a while ago, but I did recently get a cheap new keyboard so I'm just wondering if the problem is my keyboard or whether its a quirk with Java.

You can download Duke from here:

http://java.sun.com/docs/books/tutorial/uiswing/examples/components/LayeredPaneDemoProject/src/components/images/dukeWaveRed.gif

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

publicclass KeyboardNavigationProblemimplements ActionListener

{

private JComponent component;

privateint deltaX;

privateint deltaY;

private Timer timer;

privateint keysPressed;

private InputMap inputMap;

public KeyboardNavigationProblem(JComponent component,int delay)

{

this.component = component;

this.deltaX = deltaX;

this.deltaY = deltaY;

timer =new Timer(delay,this);

timer.setInitialDelay( 0 );

inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);

}

publicvoid addAction(int keyCode, String description,int deltaX,int deltaY)

{

new NavigationAction(keyCode, description, deltaX, deltaY);

}

publicvoid updateDeltaX(int delta)

{

deltaX += delta;

}

publicvoid updateDeltaY(int delta)

{

deltaY += delta;

}

publicvoid actionPerformed(ActionEvent e)

{

int componentWidth = component.getSize().width;

int componentHeight = component.getSize().height;

Dimension parentSize = component.getParent().getSize();

int parentWidth = parentSize.width;

int parentHeight = parentSize.height;

// Determine next X position

int nextX = Math.max(component.getLocation().x + deltaX, 0);

if ( nextX + componentWidth > parentWidth)

{

nextX = parentWidth - componentWidth;

}

// Determine next Y position

int nextY = Math.max(component.getLocation().y + deltaY, 0);

if ( nextY + componentHeight > parentHeight)

{

nextY = parentHeight - componentHeight;

}

// Move the component

component.setLocation(nextX, nextY);

}

class NavigationActionextends AbstractActionimplements ActionListener

{

privateint deltaX;

privateint deltaY;

private KeyStroke pressedKeyStroke;

privateboolean listeningForKeyPressed;

public NavigationAction(int keyCode, String description,int deltaX,int deltaY)

{

super(description);

this.deltaX = deltaX;

this.deltaY = deltaY;

pressedKeyStroke = KeyStroke.getKeyStroke(keyCode, 0,false);

KeyStroke releasedKeyStroke = KeyStroke.getKeyStroke(keyCode, 0,true);

inputMap.put(pressedKeyStroke, getValue(Action.NAME));

inputMap.put(releasedKeyStroke, getValue(Action.NAME));

component.getActionMap().put(getValue(Action.NAME),this);

listeningForKeyPressed =true;

}

publicvoid actionPerformed(ActionEvent e)

{

if (listeningForKeyPressed)

{

updateDeltaX( deltaX );

updateDeltaY( deltaY );

inputMap.remove(pressedKeyStroke);

listeningForKeyPressed =false;

if (keysPressed == 0)

{

timer.start();

}

keysPressed++;

}

else// listening for key released

{

updateDeltaX( -deltaX );

updateDeltaY( -deltaY );

inputMap.put(pressedKeyStroke, getValue(Action.NAME));

listeningForKeyPressed =true;

keysPressed--;

if (keysPressed == 0)

{

timer.stop();

}

}

System.out.println(KeyboardNavigationProblem.this.deltaX +" : "

+ KeyboardNavigationProblem.this.deltaY);

}

}

publicstaticvoid main(String[] args)

{

JPanel contentPane =new JPanel();

contentPane.setLayout(null );

JLabel duke =new JLabel(new ImageIcon("dukewavered.gif") );

duke.setSize( duke.getPreferredSize() );

duke.setLocation(100, 100);

contentPane.add( duke );

KeyboardNavigationProblem navigation =new KeyboardNavigationProblem(duke, 100);

navigation.addAction(KeyEvent.VK_LEFT,"zLeft", -5, 0);

navigation.addAction(KeyEvent.VK_RIGHT,"zRight", 5, 0);

navigation.addAction(KeyEvent.VK_UP,"zUp", 0, -5);

navigation.addAction(KeyEvent.VK_DOWN,"zDown", 0, 5);

//navigation.addAction(KeyEvent.VK_A, "zLeft", -5, 0);

//navigation.addAction(KeyEvent.VK_S, "zRight", 5, 0);

//navigation.addAction(KeyEvent.VK_D, "zUp", 0, -5);

//navigation.addAction(KeyEvent.VK_F, "zDown", 0, 5);

JFrame frame =new JFrame();

frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

frame.setContentPane( contentPane);

frame.setSize(800, 600);

frame.setLocationRelativeTo(null );

frame.setVisible(true);

}

}

[9600 byte] By [camickra] at [2007-11-27 5:33:36]
# 1
I get the same behavior with my keyboard, except no beeping. (Java 5, windows xp).
mpmarronea at 2007-7-12 15:00:53 > top of Java-index,Desktop,Core GUI APIs...
# 2

also the same behavior 1.5.0_05, winxp pro, hp notebook

if you hold down left and right (so it doesn't move), down works, but not up.

hold up/down, right works but not left.

thats for the normal arrow keys.

num lock off - use the number pad arrow keys and all works OK

Michael_Dunna at 2007-7-12 15:00:53 > top of Java-index,Desktop,Core GUI APIs...
# 3

> if you hold down left and right (so it doesn't move), down works, but not up.

> hold up/down, right works but not left.

Yes, the problem only seems to be when the up and left in combination with the right or down key is pressed.

> num lock off - use the number pad arrow keys and all works OK

Thats interesting, I didn't notice that. Although it just confuses the issue as to what the problem is.

So it appears to me that:

a) left + up + down, and

b) left + up + right

are special key combinations that are intercepted by either the OS or the JVM. Do these key combinations ring a bell to anybody?

I'm use JDK1.4.2 on XP. I wonder if other OS will have the same problem?

Again, this isn't a real, problem, just more of a curiosity. Thanks,

camickra at 2007-7-12 15:00:53 > top of Java-index,Desktop,Core GUI APIs...