Search code examples
javastaticwhile-looplwjgl

LWJGL Keyboard loop


I've created a static Input class, that basicly have a method that I can call, which is this:

public static boolean GetKeyDown(int keyCode) {
    while(Keyboard.next()) {
        Keyboard.enableRepeatEvents(false);
        if (Keyboard.getEventKeyState()) {
            if (Keyboard.getEventKey() == keyCode) {
                return true;
            } else {
                return false;
            }
        }
    }
    return false;
}

And in my game update loop, I've wanted to use this, instead of having to make a single while-loop:

if(Input.GetKeyDown(KeyCode.S)) {
    //Something happens
}
if(Input.GetKeyDown(KeyCode.R)) {
    //Something happens
}
//etc..

But it seems that only the first one loaded, will work. In this case 'S'. Is there a way for me to do be able to use the others too?


Solution

  • That is because in your GetKeyDown() method, you call Keyboard.next(), when you call that method it removes the Event of the current key from Keyboard, the only gets refilled with Events, when you call Display.update();

    NOTE: This method does not query the operating system for new events. To do that, Display.processMessages() (or Display.update()) must be called first.

    Source: LWJGL Docs

    You Could

    Instead you can use the Keyboard.isKeyDown(int key) method, to achieve what you're trying to do.

    Though it returns true/false depending on the following.

    Returns: true if the key is down according to the last poll()

    But that still doesn't quite fix the problem because it relies on the poll() method.

    Fixing The Problem

    You can fix the problem by creating some custom methods to use with the Keyboard class, as you already did, though as said the Keyboard Events only gets updated when you call the Display.update(); method.

    You already got the right idea about which function to create, though you need to split them into, two different methods. You need a secondary method which you call once each time you want to update your keyboard.

    public class MyKeyboard {
        /*
         * Remember that the index where we store the value,
         * is the index of the key. Thereby one key might have
         * an index of 400, then your array need to have at least
         * the same size, to be able to store it.
         */
        public static boolean[] keys = new boolean[100]; // 100 is the amount of keys to remember!
    
        public static void update() {
            while(Keyboard.next()) {
                if (Keyboard.getEventKey() < keys.length) {
                    keys[Keyboard.getEventKey()] = Keyboard.getEventKeyState();
                }
            }
        }
    
        public static boolean isKeyDown(int key) {
            if ((key > 0) && (key < keys.length)) {
                return keys[key];
            }
    
            return false;
        }
    }
    

    Remember to only call the MyKeyboard.update() method once per Display.update() I also renamed your GetKeyDown() method to isKeyDown(), because I think that sounds and describes it better, but you can rename it again in your project if you want to.

    The above code was made within this answer, without the use of an IDE, etc. So if there's anything wrong with it I apologize, but just comment and I will fix it.

    One problem that arises with this method is the lack of rechecking. Since Keyboard.next() only checks the inputs that have occurred in the current frame. A button which was once pressed will remain "pressed" until it is pressed again. I ran into this problem while trying to implement this solution. The answer to this new problem is here:

    public static void update() {
    
        for(int i = 0; i < keys.length; i++) {
            keys[i] = false;
        }
        while(Keyboard.next()) {
            keys[Keyboard.getEventKey()] = Keyboard.getEventKeyState();
        }
    }
    

    You must clear the keypresses of the previous frame by setting everything to false.