Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Key Bindings using the arrow keys

camickrMay 25 2007 — edited May 26 2007
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.*;

public class KeyboardNavigationProblem implements ActionListener
{
	private JComponent component;
	private int deltaX;
	private int deltaY;
	private Timer timer;
	private int 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);
	}

	public void addAction(int keyCode, String description, int deltaX, int deltaY)
	{
		new NavigationAction(keyCode, description, deltaX, deltaY);
	}

	public void updateDeltaX(int delta)
	{
		deltaX += delta;
	}

	public void updateDeltaY(int delta)
	{
		deltaY += delta;
	}

	public void 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 NavigationAction extends AbstractAction implements ActionListener
	{
		private int deltaX;
		private int deltaY;

		private KeyStroke pressedKeyStroke;
		private boolean 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;
		}

		public void 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);
		}
	}

	public static void 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);
	}

}
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Jun 23 2007
Added on May 25 2007
3 comments
383 views