-
Notifications
You must be signed in to change notification settings - Fork 36
2.6.3 Input handling with GLFW
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.
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();
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
.
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]
- Left and right on left sticker.
- Up and down on left sticker.
- Left and right back triggers.
- Up and down on right sticker.
- 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]
- A
- B
- X
- Y
- Left shoulder button
- Right shoulder button
- Back button <
- Start button >
- Left sticker button
- Right sticker button
- D-Pad Up
- D-Pad Right
- D-Pad Down
- 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)