0

I am currently testing the KeyEventDispatcher.

Therefore I wrote a little JFrame which implements the KeyEventDispatcher and my own keyPressed and keyReleased Methods.

In those Methods, I am using a flag based System to detect only the first keypress of every arrow key.

Everything works, if you click the keys separately. But if you click Right, Up, Left (without releasing any of them) the Left key won't be recognized.

Console output:

Right clicked
4
Up clicked
6

Expected output:

Right clicked
4
Up clicked
6
Left clicked
7

My code is the following:

Main class:

public class Main {

    public static void main(String[] args) {
        UI m = new UI();
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(m);

    }
}

UI class:

public class UI extends JFrame implements KeyEventDispatcher{

    short lurd = 0;

    enum KEYSTATES{
        LEFT(1),
        UP(2),
        RIGHT(4),
        DOWN(8);

        private int m_val;
        KEYSTATES(int val){
            m_val = val;
        }

        public int getm_val(){
            return m_val;
        }

    }

    public UI(){

        setSize(800,600);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setVisible(true);

    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent e) {


        switch(e.getID())
        {
        case KeyEvent.KEY_PRESSED:
            keyPressed(e);
            return true;

        case KeyEvent.KEY_RELEASED:
            keyReleased(e);
            return true;

        }
        return false;
    }

    private void keyPressed(KeyEvent e){
        if(e.getKeyCode() == KeyEvent.VK_LEFT && ((lurd & KEYSTATES.LEFT.getm_val()) != KEYSTATES.LEFT.getm_val())){
            lurd |= KEYSTATES.LEFT.getm_val();
            System.out.println("Left clicked");
            System.out.println(lurd);
        }
        else if(e.getKeyCode() == KeyEvent.VK_UP && ((lurd & KEYSTATES.UP.getm_val()) != KEYSTATES.UP.getm_val()))
        {
            lurd |= KEYSTATES.UP.getm_val();
            System.out.println("Up clicked");
            System.out.println(lurd);
        }
        else if(e.getKeyCode() == KeyEvent.VK_RIGHT && ((lurd & KEYSTATES.RIGHT.getm_val()) != KEYSTATES.RIGHT.getm_val()))
        {
            lurd |= KEYSTATES.RIGHT.getm_val();
            System.out.println("Right clicked");
            System.out.println(lurd);
        }
        else if(e.getKeyCode() == KeyEvent.VK_DOWN && ((lurd & KEYSTATES.DOWN.getm_val()) != KEYSTATES.DOWN.getm_val()))
        {
            lurd |= KEYSTATES.DOWN.getm_val();
            System.out.println("Down clicked");
            System.out.println(lurd);
        }


    }

    private void keyReleased(KeyEvent e){
        if(e.getKeyCode() == KeyEvent.VK_LEFT && ((lurd & KEYSTATES.LEFT.getm_val()) == KEYSTATES.LEFT.getm_val())){
            lurd &= ~KEYSTATES.LEFT.getm_val();
            System.out.println("Left released");
            System.out.println(lurd);
        }
        else if(e.getKeyCode() == KeyEvent.VK_UP && ((lurd & KEYSTATES.UP.getm_val()) == KEYSTATES.UP.getm_val()))
        {
            lurd &= ~KEYSTATES.UP.getm_val();
            System.out.println("Up released");
            System.out.println(lurd);
        }
        else if(e.getKeyCode() == KeyEvent.VK_RIGHT && ((lurd & KEYSTATES.RIGHT.getm_val()) == KEYSTATES.RIGHT.getm_val()))
        {
            int x = ~KEYSTATES.RIGHT.getm_val();
            lurd &= x;
            System.out.println("Right released");
            System.out.println(lurd);
        }
        else if(e.getKeyCode() == KeyEvent.VK_DOWN && ((lurd & KEYSTATES.DOWN.getm_val()) == KEYSTATES.DOWN.getm_val()))
        {
            lurd &= ~KEYSTATES.DOWN.getm_val();
            System.out.println("Down released");
            System.out.println(lurd);
        }


    }


}
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Loki
  • 4,065
  • 4
  • 29
  • 51
  • When you say click keys, do you mean press the keys on your physical keyboard? You may have a lower quality keyboard that doesn't recognize multiple key presses that happen close together. – NESPowerGlove Mar 12 '14 at 15:22
  • Yes. I mean pressing the keys on my physical keyboard. Maybe my keyboard is lower quality :) If you copy my code and test it and it works with you, I know it's not a code issue. – Loki Mar 12 '14 at 15:23
  • I do own a nice mechanical keyboard but I don't have the time to test it. In the meantime you can test your keyboard by opening a text editor and attempt to press a group of keys together at once, for example see if you can hold qwerf together and have each individual letter printed without releasing the keys. My mechanical does that just fine, but my laptop does not. – NESPowerGlove Mar 12 '14 at 15:29
  • Well my keyboard seems not to be the problem, as some orders of the keys work and others do not (left, down, right works (any order) but left, up, right not, right, down, up works not but right, up, left (or vice versa? :D) I think I have a problem within the if-statements – Loki Mar 12 '14 at 15:34
  • Your code is working fine. If you just print out the KeyCode at the beginning of the method keyPressed you'll realize that LEFT is never recognized when you already pressed UP and RIGHT. Pretty sure it is like NESPowerGlove says and has something to do with the keyboard. I don't have a mechanical keyboard to test either though. – user432 Mar 12 '14 at 15:41

1 Answers1

0

To solve this issue, hold references of boolean variables for particular keys when they are pressed, and make them true, and make those variable false when their respective key is released.

Here's an example:

Here's keyPressed() method:

public void keyPressed(KeyEvent e)
{
  switch(e.getKeyCode())
  {
    case VK_LEFT: setLeftKeyPressed(true);
                  break;
    case VK_RIGHT: setRightKeyPressed(true);
                   break;
    case VK_UP: setUpKeyPressed(true);
                break;
    case VK_DOWN: setDownKeyPressed(true);
                  break;
    //...
  }
  printKeyStates();
}

And here's keyReleased() method:

public void keyReleased(KeyEvent e)
{
  switch(e.getKeyCode())
  {
    case VK_LEFT: setLeftKeyPressed(false);
                  break;
    case VK_RIGHT: setRightKeyPressed(false);
                   break;
    case VK_UP: setUpKeyPressed(false);
                break;
    case VK_DOWN: setDownKeyPressed(false);
                  break;
    //...
  }
  printKeyStates();
}

And here's how printKeyStates() method would look like:

public void printKeyStates()
{
  print("Left", isLeftKeyPressed());
  print("Right", isRightKeyPressed());
  print("Up", isUpKeyPressed());
  print("Down", isDownKeyPressed());
}

private void print(String key, boolean isPressed)
{
  System.out.println(key + " key is " + (isPressed ? "" : "NOT ") + "pressed.");
}

The boolean variables would look like:

private boolean isLeftKeyPressed;
private boolean isRightKeyPressed;
private boolean isUpKeyPressed;
private boolean isDownKeyPressed;

And their setters like:

public void setLeftKeyPressed(boolean value)
{
  isLeftKeyPressed = value;
}

And similarly the rest of the setters...

And the getters like:

public boolean isLeftKeyPressed()
{
  return isLeftKeyPressed;
}

And similarly the rest of the getters...

Usually, in games, and in networked remote control where such behavior is expected, it is resolved through this technique.

The difference in the flips of the boolean variables will let you know the count of "clicks" that happened for any key. To record that "click" count, you can have count variables which will hold the state of the amount of clicks that have happened for any key.

Here's how you can do that:

int leftKeyClickCount = 0; // Initially ZERO

Then in setter of isLeftKeyPressed variable, you can do something like following:

public void setLeftKeyPressed(boolean value)
{
  if(isLeftKeyPressed != value)
  {
    isLeftKeyPressed = value;
    ++leftKeyClickCount;
  }
}

And similarly can other setters be written...

Then you can print the click counts of each key by printing the appropriate xyzKeyClickCount variable value like:

System.out.println("Left key clicked: " + leftKeyClickCount + " time(s).");
Aman Agnihotri
  • 2,973
  • 1
  • 18
  • 22