The method glfwSetKeyCallback
takes a Function Pointer as its argument. Function Pointers are a relatively essential part of C and C++ functionality, and are the common idiom for implementing callbacks, as seen in this case.
What GLFW will do with the function passed to it is it has an internal polling functionality for system events (which you invoke using glfwPollEvents();
) that, upon encountering a system event, will translate it into a system-agnostic form that can be interpreted using the callback you provided.
However, GLFW is written in C, and cannot handle the more complex, advanced kinds of Function Pointers or Functors that are native to C++, so when we pass a Function Pointer to GLFW, we need to reduce it down to a simpler form. A Member function of an object won't cut it. This is because a method like this:
class Input
{
public:
void HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods);
private:
};
Secretly, according to the compiler, actually looks like this:
void Input__HandleInput(Input * ptr, GLFWwindow* window, int key, int scancode, int action, int mods);
And since this signature does not match what GLFW is expecting for the callback, it will not accept it.
If you intend to use a class function as a callback for this function, you'll need to make it static.
struct Input {//'class' is fine, but 'struct' reduces boilerplate
static void HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods);
};
int main() {
glfwInit();
GLFWWindow* window = glfwCreateWindow(/*...*/);
glfwSetKeyCallback(window, Input::HandleInput);
}
This may, however, represent a problem for you. After all, you probably wrote a class for this callback functionality specifically to offer some encapsulation of the behavior you need. Being forced to revert to using a static function or a global function defeats this purpose.
Instead, you need to use the User Pointer functionality that GLFW integrates.
struct InputHandler {
static void HandleKey(GLFWwindow* window, int key, int scancode, int action, int mods) {
//Perfectly legal: we fully intend to only permit the User Pointer to be of type 'InputHandler*'
InputHandler & handler = *reinterpret_cast<InputHandler*>(glfwGetWindowUserPointer(window));
handler.handleKeyImpl(window, key, scancode, action, mods);
}
void handleKeyImpl(GLFWwindow* window, int key, int scancode, int action, int mods) {
/*...*/
}
};
int main() {
glfwInit();
InputHandler input;
GLFWWindow* window = glfwCreateWindow(/*...*/);
glfwSetWindowUserPointer(window, &input);
glfwSetKeyCallback(window, Input::HandleInput);
}