Search code examples
javaswingkeypress

How can I stop keyPressed from repeatedly being called?


When I press an arrow key, keyPressed is called once, and then after a delay it is called very rapidly, like when holding down a key to type a long string of letters like so: eeeeeeeeeeeeeeeeeeeeeee

public void keyPressed(KeyEvent e) {
    System.out.println(e); //this prints repeatedly while any key is held down
}

Is there a way to stop it from being called more than once?

I'm planning on adding a boolean to store true when an arrow key is pressed and false when it is released, and then have an if loop set up inside the keyPressed so it doesn't activate multiple times, but having to do all this makes me think there is a simpler solution.


Solution

  • The answer to your question is that it can’t be done. Java doesn’t control this; the operating system does. The operating system sends native key press events repeatedly; Java just translates them into java.awt.event.KeyEvent objects.

    The way to deal with it is to keep your own Set which tracks which keys are pressed and which are not, and update that Set in a KeyListener’s keyPressed and keyReleased methods. Then your program can react to the keys in that Set, rather than acting directly on events. Here’s a short example:

    import java.util.Collection;
    import java.util.HashSet;
    
    import java.awt.EventQueue;
    import java.awt.BorderLayout;
    
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyAdapter;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JList;
    import javax.swing.JScrollPane;
    import javax.swing.BorderFactory;
    
    public class KeyPressMonitor {
        private final Collection<Integer> keysPressed = new HashSet<>();
    
        private final JList<String> pressedKeyList;
    
        private final JFrame window;
    
        public KeyPressMonitor() {
            pressedKeyList = new JList<>();
    
            JLabel input = new JLabel("Awaiting key presses");
            input.setFocusable(true);
            input.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
    
            input.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent event) {
                    if (keysPressed.add(event.getKeyCode())) {
                        processNewKeyPresses();
                    }
                }
    
                @Override
                public void keyReleased(KeyEvent event) {
                    if (keysPressed.remove(event.getKeyCode())) {
                        processNewKeyPresses();
                    }
                }
            });
    
            window = new JFrame("Key press monitor");
            window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            window.getContentPane().add(input, BorderLayout.PAGE_START);
            window.getContentPane().add(new JScrollPane(pressedKeyList),
                BorderLayout.CENTER);
    
            window.pack();
            window.setLocationByPlatform(true);
    
            input.requestFocusInWindow();
        }
    
        private void processNewKeyPresses() {
            pressedKeyList.setListData(
                keysPressed.stream().map(KeyEvent::getKeyText).sorted().toArray(
                    String[]::new));
        }
    
        void show() {
            window.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(() -> new KeyPressMonitor().show());
        }
    }