How to know when a user has really released a key in Java?

前端 未结 10 1186
孤城傲影
孤城傲影 2020-11-30 11:09

(Edited for clarity)

I want to detect when a user presses and releases a key in Java Swing, ignoring the keyboard auto repeat feature. I also would like a pure Java

相关标签:
10条回答
  • 2020-11-30 11:54

    Save the timestamp of the event (arg0.when()) in keyReleased. If the next keyPressed event is for the same key and has the same timestamp, it is an autorepeat.

    If you hold down multiple keys, X11 only autorepeats the last key pressed. So, if you hold down 'a' and 'd' you'll see something like:

    a down
    a up
    a down
    d down
    d up
    d down
    d up
    a up
    
    0 讨论(0)
  • 2020-11-30 11:54

    This approach stores key presses in a HashMap, resetting them when the key is released. Most of the code is courtesy of Elist in this post.

    import java.awt.KeyEventDispatcher;
    import java.awt.KeyboardFocusManager;
    import java.awt.event.KeyEvent;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Set;
    
    public class KeyboardInput2 {
        private static HashMap<Integer, Boolean> pressed = new HashMap<Integer, Boolean>();
        public static boolean isPressed(int key) {
            synchronized (KeyboardInput2.class) {
                return pressed.get(key);
            }
        }
    
        public static void allPressed() {
            final Set<Integer> templist = pressed.keySet();
            if (templist.size() > 0) {
                System.out.println("Key(s) logged: ");
            }
            for (int key : templist) {
                System.out.println(KeyEvent.getKeyText(key));
            }
        }
    
        public static void main(String[] args) {
            KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
    
                @Override
                public boolean dispatchKeyEvent(KeyEvent ke) {
                    synchronized (KeyboardInput2.class) {
                        switch (ke.getID()) {
                            case KeyEvent.KEY_PRESSED:
                                pressed.put(ke.getKeyCode(), true);
                                break;
                            case KeyEvent.KEY_RELEASED:
                                pressed.remove(ke.getKeyCode());
                                break;
                            }
                            return false;
                    }
                }
            });
        }
    }
    

    You can use the HashMap to check if a certain key is pressed, or call KeyboardInput2.allPressed() to print every pressed key.

    0 讨论(0)
  • 2020-11-30 11:59

    Well, you said that it is possible that the time between key events in case of key repeat be non-negative. Even so, it is likely very short. You could then threshold this time to some very small value, and everything equal or lower than it be considered a key repeat.

    0 讨论(0)
  • 2020-11-30 12:00

    I've found a solution that does without waiting in case you have something like a game loop going. The idea is storing the release events. Then you can check against them both inside the game loop and inside the key pressed handler. By "(un)register a key" I mean the extracted true press/release events that should be processed by the application. Take care of synchronization when doing the following!

    • on release events: store the event per key; otherwise do nothing!
    • on press events: if there is no stored release event, this is a new press -> register it; if there is a stored event within 5 ms, this is an auto-repeat -> remove its release event; otherwise we have a stored release event that hasn't been cleared by the game loop, yet -> (fast user) do as you like, e.g. unregister-register
    • in your loop: check the stored release events and treat those that are older than 5 ms as true releases; unregister them; handle all registered keys
    0 讨论(0)
提交回复
热议问题