Keyboard input
At the start of our game loop we should process our keyboard inputs. For now we are not really using them but later we might want to implement movement or interaction keys and such
To implement a basic keyboard input processing we just need to call the glfwGetKey(...) function every frame. For this we can make a function that handles all inputs. Such function may look like the code below
void processKeyboardInputs(GLFWwindow *window){
// close our window when space is pressed
if(glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
// change window title when W is pressed
if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
glfwSetWindowTitle(window, "Window where 'W' was pressed");
}Then we just call processKeyboardInputs(...) at the start of each frame
while(!glfwWindowShouldClose(window)){
glfwPollEvents();
processKeyboardInputs(window);
// ------
// rendering, game logic etc.
// ------
glfwSwapBuffers(window);
}Keyboard callback
Instead of checking pressed keys every frame we can let GLFW run a callback for any newly pressed/released or held buttons. This is not preferred for movement or any other action that heavily works with held keys as the callback for a held key is not send every frame. This is however preferred for actions that act more like a text input or an event like interaction with key press
For a keyboard callback we need to make a function defined as
void keyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods){
if (key == GLFW_KEY_E && action == GLFW_PRESS)
interact();
}This function has many arguments. Below is the definition for them
key is for the key pressed. It starts with GLFW_KEY_ and then the key we are checking for. The last part can be for example ENTER, E, F3 or 4
scancode is a platform specific scancode for the key pressed
action is either GLFW_PRESS, GLFW_REPEAT or GLFW_RELEASE
mods is short for modifier bits which are flags triggered during mouse button press like holding shift, ctrl and such. The flags are:
- GLFW_MOD_SHIFT
- GLFW_MOD_CONTROL
- GLFW_MOD_ALT
- GLFW_MOD_SUPER - super is the name for the commonly named “windows button” or any other OS equivalent name
- GLFW_MOD_CAPS_LOCK
- GLFW_MOD_NUM_LOCK
Mouse input
Instead of a function that returns the mouse position/event and such we use event callbacks. GLFW offers multiple callbacks for mouse click, move, scroll,…
Mouse movement
To set the mouse movement callback we need to make a function to link to the callback. Make sure that your function always matches the argument and return value types
void cursorPositionCallback(GLFWwindow* window, double xpos, double ypos){
// store or in any was use the new cursor position
}And to set the callback we just need to set it with
glfwSetCursorPosCallback(window, cursorPositionCallback);Polling mouse position
It is possible to poll the position from GLFW at any time we want however we should prefer storing the mouse position from the callback instead
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);Hiding/showing the cursor
When playing for example a 3D game we often can’t see our cursor. Hiding the cursor is essential for 3D games to not feel bad but when opening a menu or an interaction requires a cursor we want to show it again for a limited time. Hiding and showing the cursor requires just a single function call
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);The GLFW_CURSOR_DISABLED is one of many modes a cursor can gain. Here is a short list of usable cursor modes
- GLFW_CURSOR_NORMAL - Normal cursor behavior
- GLFW_CURSOR_DISABLED - Cursor is not visible and automatically centered so it cannot move offscreen
- GLFW_CURSOR_HIDDEN - Cursor is hidden but can move anywhere even outside of the window
Delta mouse
For things like camera control and such we do not care about the mouse position but more about how much did our mouse move from last time which is called delta movement
To implement this we just need to modify our callback a little
glm::vec2 deltaMouse = glm::vec2(0.0f, 0.0f);
glm::vec2 mousePos = glm::vec2(0.0f, 0.0f);
void cursorPositionCallback(GLFWwindow* window, double xpos, double ypos){
glm::vec2 newMousePos = glm::vec2(xpos, ypos);
deltaMouse = newMousePos - mousePos;
mousePos = newMousePos;
}Mouse click
For mouse button inputs we have to again create a function for the callback
void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods){
if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
std::cout << "Pressed right click!" << std::endl;
} The callback gives us three values. button, action and mods
button can have the following values
- GLFW_MOUSE_BUTTON_LEFT - left click
- GLFW_MOUSE_BUTTON_MIDDLE - middle click
- GLFW_MOUSE_BUTTON_RIGHT - right click
- GLFW_MOUSE_BUTTON_X - the X can be a number between 1 and 8 (inclusive). The values 1, 2 and 3 are for the left, middle and right click and the bigger values are for things like mouse side buttons
action can only be GLFW_PRESS or GLFW_RELEASE
mods represent the same values as during keyboard callback
Polling mouse click
Like with the mouse position we can also poll for mouse buttons and see which ones are pressed and which ones are not. It is again better to use the callback if possible
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);The state will be equal to either GLFW_PRESS or GLFW_RELEASE
When polling the mouse inputs there is a chance of missing the mouse input. To prevent that we should also set our mouse keys as “sticky keys” where they retain GLFW_PRESS even if they are not pressed anymore until we call glfwGetMouseButton(...) on them
glfwSetInputMode(window, GLFW_STICKY_MOUSE_BUTTONS, GLFW_TRUE);Mousewheel scroll
The function for mouse scroll should be defined as
void scrollCallback(GLFWwindow* window, double xoffset, double yoffset){
// ...
}And to register the function to the glfw callback we just need to call
glfwSetScrollCallback(window, scrollCallback);