Java KeyListener Not Registering Arrow Keys

Landric picture Landric · Jan 22, 2012 · Viewed 17.8k times · Source

I'm writing a simple program in Java which includes a KeyListener with the following overriding they KeyTyped method:

@Override
        public void keyTyped(KeyEvent e)
        {
            int key = e.getKeyCode();
            System.out.println("TEST");

            if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_LEFT)
            {
                System.out.println("LEFT");
                //Call some function
            }
            else if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT)
            {
                System.out.println("RIGHT");
                //Call some function
            }
        }

When I type anything other than the arrow keys (e.g. "a"), it prints TEST as it should. However, when I type a numpad arrowkey, it only prints TEST and when I type a standard arrow key it doesn't print anything at all. Is this possibly because I'm on a laptop, or have I just made a silly mistake somewhere?

Answer

Hovercraft Full Of Eels picture Hovercraft Full Of Eels · Jan 22, 2012

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;
   }
}