Java KeyListener Not Registering Arrow Keys
Yep, you'll see the arrow keys respond to keyPressed and keyReleased, not keyTyped. My SSCCE:
import java.awt.Dimension;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class ArrowTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
public ArrowTest() {
setFocusable(true);
requestFocusInWindow();
addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
myKeyEvt(e, "keyTyped");
}
@Override
public void keyReleased(KeyEvent e) {
myKeyEvt(e, "keyReleased");
}
@Override
public void keyPressed(KeyEvent e) {
myKeyEvt(e, "keyPressed");
}
private void myKeyEvt(KeyEvent e, String text) {
int key = e.getKeyCode();
System.out.println("TEST");
if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_LEFT)
{
System.out.println(text + " LEFT");
//Call some function
}
else if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT)
{
System.out.println(text + " RIGHT");
//Call some function
}
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ArrowTest mainPanel = new ArrowTest();
JFrame frame = new JFrame("ArrowTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
So to solve this, override keyPressed rather than keyTyped if you want to listen to arrow events.
Or for an even better solution: use Key Bindings
Edit
My Key Bindings version:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class ArrowTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
public ArrowTest() {
ActionMap actionMap = getActionMap();
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
for (Direction direction : Direction.values()) {
inputMap.put(direction.getKeyStroke(), direction.getText());
actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
}
}
private class MyArrowBinding extends AbstractAction {
public MyArrowBinding(String text) {
super(text);
putValue(ACTION_COMMAND_KEY, text);
}
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
System.out.println("Key Binding: " + actionCommand);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ArrowTest mainPanel = new ArrowTest();
JFrame frame = new JFrame("ArrowTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum Direction {
UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
Direction(String text, KeyStroke keyStroke) {
this.text = text;
this.keyStroke = keyStroke;
}
private String text;
private KeyStroke keyStroke;
public String getText() {
return text;
}
public KeyStroke getKeyStroke() {
return keyStroke;
}
@Override
public String toString() {
return text;
}
}
KeyListener not working the way I want it to for arrow keys?
I have solved my problem, thank you @azurefrog, @Hovercraft Full Of Eels, and @AJNeufeld. Here is my solution in case other people have the same problem as mine. Disclaimer: I am not done with this game so the "snake" is just a block, I still have to figure out how to make it an actual snake. I am just posting this to show how I handled the movement of the snake.
First, I made two global variables in my Snake
class (the class of the game):
private String currentDir = "";
private Timer moveTimer = new Timer(100, new MoveListener());
Then, I made a MoveListener
class that extends the ActionListener
class. This MoveListener
class serves as the parameter for the moveTimer
:
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
out.println("timer action called");
int snakeX = 0;
int snakeY = 0;
for (int row = 0; row < positions.length; row++) {
for (int col = 0; col < positions[row].length; col++) {
if (positions[row][col] == 's') {
snakeX = row;
snakeY = col;
}
}
}
if (currentDir.equals("left")) {
positions[snakeX - 1][snakeY] = 's';
positions[snakeX][snakeY] = '\u0000';
repaint();
} else if (currentDir.equals("right")) {
positions[snakeX + 1][snakeY] = 's';
positions[snakeX][snakeY] = '\u0000';
repaint();
} else if (currentDir.equals("up")) {
positions[snakeX][snakeY - 1] = 's';
positions[snakeX][snakeY] = '\u0000';
repaint();
} else if (currentDir.equals("down")) {
positions[snakeX][snakeY + 1] = 's';
positions[snakeX][snakeY] = '\u0000';
repaint();
}
}
}
Finally, I made my KeyListener
so that it simply set the variable currentDir
based on the corresponding movement keys, and started the MoveTimer
thread.
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_A) {
out.println("Left key pressed");
currentDir = "left";
moveTimer.start();
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_D) {
out.println("Right key pressed");
currentDir = "right";
moveTimer.start();
} else if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
out.println("Up key pressed");
currentDir = "up";
moveTimer.start();
} else if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_S) {
out.println("Down key pressed");
currentDir = "down";
moveTimer.start();
}
}
Java KeyListener's keyReleased not called for left and right arrow keys
Snippet from java api - Keyevent:
Not all keyboards or systems are capable of generating all virtual key codes. No attempt is made in Java to generate these keys artificially.
So from Java- side it is still defined behaviour. However from my logic feeling I also cannot give you any difference between up/down and left/right arrow keys.
Just if we follow the API definition. It seems to be system dependent.
how can I detect arrow keys in java?
I would recommend using:
if (event.getKeyCode() == KeyEvent.VK_UP) {
...
}
repeating with VK_DOWN, VK_LEFT, VK_RIGHT
.
There are seperate codes for the numeric keypad: VK_KP_UP, VK_KP_DOWN, VK_KP_LEFT, VK_KP_RIGHT
if you need them.
See KeyEvent for all of the codes.
Add Arrow Keylistener to a Jframe that implements ActionListener
This can be solved by giving your JFrame the focus after making it focusable, but once it loses focus, the KeyListener will fail to work. My main suggestion is that you don't use a KeyListener but rather use Key Bindings as these function are higher level constructs and work well with Swing applications, especially with respect to gaining and losing focus. There are many similar posts on this subject, and if you hang on, I'll get you some links.
- Key Bindings Tutorial
- A Key Bindings example that uses arrow keys can be found here: java keylistener not registering arrow keys
- Another example: java keylistener not called
Related Topics
Behaviour of Final Static Method
Convert Boolean to Int in Java
Are Java Static Initializers Thread Safe
Jax-Rs/Jersey How to Customize Error Handling
Specifying Java Version in Maven - Differences Between Properties and Compiler Plugin
Using Mockito with Multiple Calls to the Same Method with the Same Arguments
Socket Programming Multiple Client to One Server
Simple Way to Find If Two Different Lists Contain Exactly the Same Elements
Break When Exception Is Thrown
What's the Advantage of a Java Enum Versus a Class with Public Static Final Fields
Can Constructors Throw Exceptions in Java
Add Context Path to Spring Boot Application
Do I Need to Close() Both Filereader and Bufferedreader
Does a Finally Block Always Run
Easy, Simple to Use Lru Cache in Java
When Should I Use the "Strictfp" Keyword in Java
How to Define a List Bean in Spring
Ignore Fields from Java Object Dynamically While Sending as JSON from Spring MVC