2.6.3 Input handling with GLFW

Heiko Brumme edited this page Feb 20, 2016 · 6 revisions

Input handling

The way you handle input now is different from LWJGL2. Before you had a Keyboard class, now you will need to use GLFW. This is a simple tutorial to get started with input handling in LWJGL3.

The first and most important thing about input handling in GLFW is not to forget to call this method:

glfwPollEvents();

This is essential for inputs to work.

Key input handling

First off, you can find the key values in the GLFW class. Under GLFW_KEY_(Your key). For example:

GLFW_KEY_H
GLFW_KEY_I

There are two ways to know if a specific key was pressed. Either you create a key callback, or you simply check with this method:

glfwGetKey(window, GLFW_KEY_V);

This will either return zero or one. One if the key is pressed, zero if it’s not.

The other way to get key input is to use a key callback. It works the same as a KeyListener does in Swing. You need to create a new GLFWKeyCallback object to make this work. To start getting input you will need to set a key callback to GLFW using your GLFWKeyCallback object. This is done by doing this:

glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback()){
    @Override
    public void invoke (long window, int key, int scancode, int action, int mods) {

    }
});

// With Java 8 you could also use lambda expressions for setting a callback
glfwSetKeyCallback(window, keyCallback = GLFWKeyCallback.create((window, key, scancode, action, mods) -> {

}));

This method is going to get called after glfwPollEvents() has been called, but only of course if there's been any key events. To see which key has been pressed, you will need to use the key variable. This is an example how to check if either W, A, S, or D has been pressed.

if ( key == GLFW_KEY_W ) {

} else if ( key == GLFW_KEY_A ) {

} else if ( key == GLFW_KEY_S ) {

} else if ( key == GLFW_KEY_D ) {

}

The action variable is important, it tells you what kind of key event just happened. If it was pressed, released or repeated. When the user press a key, then action == GLFW_PRESS. While the user is holding the key, then action == GLFW_REPEAT. Finally when the user releases the key, then action == GLFW_RELEASE. This is an example in how it can be used:

if ( action == GLFW_PRESS ) {

} else if ( action == GLFW_RELEASE ) {

} else if ( action == GLFW_REPEAT ) {

}

After your application is done, don't forget to release the key callback with the following method:

keyCallback.release();

ScreenShot

Mouse input

The way you handle input for the mouse is similar to key input. You can either use a callback or just call a get method.

There’s four different types of mouse input that you can get. The position, if any button on the mouse has been pressed or released, if the mouse has been scrolled and when the cursor either enters or leaves the window.

You can only use the get methods to get either if any mouse button is pressed, or where the cursor is right now. There's a callback for all of them.

The first get method is this one:

glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1);

This returns if the selected mouse button has been clicked or not. This will return either one or zero, one if it was clicked and zero if it was not.

This returns the position of the cursor in two separate buffers:

DoubleBuffer b1 = BufferUtils.createDoubleBuffer(1);
DoubleBuffer b2 = BufferUtils.createDoubleBuffer(1);
glfwGetCursorPos(window, b1, b2);
System.out.println("x : " + b1.get(0) + ", y = " + b2.get(0));

I recommend not creating a DoubleBuffer or a ByteBuffer every render call, or else it will use valuable rendering time. This saves the position inside each buffer on the first index.

The callback for getting if the mouse button is pressed looks like this:

glfwSetMouseButtonCallback(window, mouseCallback = new GLFWMouseButtonCallback() {
	@Override
	public void invoke(long window, int button, int action, int mods) {

	}
});

// Java 8
glfwSetMouseButtonCallback(window, mouseCallback = GLFWMouseButtonCallback.create((window, button, action, mods) -> {

}));

The button variable is which mouse button was pressed, for example GLFW_MOUSE_BUTTON_1. Action is not the same as the key, it’s either GLFW_PRESS or GLFW_RELEASE. First when pressed, then action == GLFW_PRESS, and when the user releases the button, then action == GLFW_RELEASE. Mods is the same as for the keys, it’s a bitfield describing which modifiers keys were held down.

The callback for getting the position of the cursor looks like this:

glfwSetCursorPosCallback(window, posCallback = new GLFWCursorPosCallback() {
	@Override
	public void invoke(long window, double xpos, double ypos) {

	}
});

// Java 8
glfwSetCursorPosCallback(window, posCallback = GLFWCursorPosCallback.create((window, xpos, ypos) -> {

}));

xpos is the current x position of the mouse, ypos is the current y position of the mouse. This only gets called when the cursors position changes.

The callback for getting the scroll amount from the mouse looks like this:

glfwSetScrollCallback(window, scrollCallback = new GLFWScrollCallback() {
	@Override
	public void invoke(long window, double xoffset, double yoffset) {

	}
});

// Java 8
glfwSetScrollCallback(window, scrollCallback = GLFWScrollCallback.create((window, xoffset, yoffset) -> {

}));

You're mostly going to focus on the yoffset, since this is the scroll amount when scrolling up and down.

The callback for when the mouse is either entering and leaving the window is this:

glfwSetCursorEnterCallback(window, enterCallback = new GLFWCursorEnterCallback() {
	@Override
	public void invoke(long window, int entered) {

	}
});

// Java 8
glfwSetCursorEnterCallback(window, enterCallback = GLFWCursorEnterCallback.create((window, entered) -> {

}));

This gets called whenever the mouse either leaves or enters the window, not in-between. When the mouse enters, then entered == 1. When the mouse leaves the window, then entered == 0.

Joystick input

First off, there’s no callbacks here, only get methods.

In the GLFW class, there’s sixteen GLFW_JOYSTICK_X variables. If you have one controller plugged in, then you'll use GLFW_JOYSTICK_1, if you're using two controllers, you need to use GLFW_JOYSTICK_1 and GLFW_JOYSTICK_2.

The first method that we are going to take a look at is this:

glfwGetJoystickName(GLFW_JOYSTICK_1);

This returns the name of the first joystick, in my case, it returned “Microsoft PC-joystick driver”, because I had an Xbox controller.

For example, if you want to get the joystick name of the fifth controller, you simply call:

glfwGetJoystickName(GLFW_JOYSTICK_5);

If there isn't a fifth joystick, then it will simply return null (Not as a string "null").

The second method is this:

glfwGetJoystickAxes(GLFW_JOYSTICK_1)

It returns a FloatBuffer. In my case, the FloatBuffer had a capacity of 5. This method tells you what the value is on the different axes, the axes which can have different values, not just one or zero. On a Xbox controller, it's left and right sticker, and also the two back trigger. This is what the FloatBuffer stored on different indexes.

[Index] [Where the data came from]

  1. Left and right on left sticker.
  2. Up and down on left sticker.
  3. Left and right back triggers.
  4. Up and down on right sticker.
  5. Left and right on right sticker.

On index two, it returned a number when nothing was pressed, and it returned that same number when both triggers was down. Quite weird.

All values was from a range of -1 to 1, except when both left and right trigger was/wasn’t down. Experiment with your controller with what values you get! It might differ from mine!!!

The second method is this:

glfwGetJoystickButtons(GLFW_JOYSTICK_1)

As you might expect, this returns a buffer with all values of the different buttons. The value is either zero or one, one if pressed down, zero if it’s not. This is what the ByteBuffer stored on different indexes.

[Index] [Where the data came from]

  1. A
  2. B
  3. X
  4. Y
  5. Left shoulder button
  6. Right shoulder button
  7. Back button <
  8. Start button >
  9. Left sticker button
  10. Right sticker button
  11. D-Pad Up
  12. D-Pad Right
  13. D-Pad Down
  14. D-Pad Left

On index 8 and 9. It does only return 1 when you press down the stick, not moving it around. Once again, this might only be these values for the Xbox controller, so test all values on your controller and map them out.

Written by Theodor Angergård aka Portals (@Portals)