I am using GLFW for a window in my C++ application and I am trying to get input events using GLFW's callbacks. For instance, this is how you get key events:
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){
// Do something with event data.
}
int main(){
// initialize window (I have no problems with this step)
glfwSetKeyCallback(window, key_callback);
// Now when a key is pressed in the window it will call this function.
}
The Problem:
In my key_callback
I want to use a variable that is declared outside of the key_callback
function and since I cannot alter the parameters of key_callback
I cannot pass a reference to the variable.
Now, in the given example above, I could simply declare my variable outside of int main()
and both key_callback
and int main()
would have access to the same instance of the variable.
My Desired Use:
I want to have a WindowWrapper
class that creates and manages the life cycle of the glfwWindow
, this would include setting the event callbacks.
WindowWrapper.h
// Includes
class WindowWrapper{
private:
Centrum* g_centrum_;
GLFWwindow* window_;
std::thread thread_;
public:
WindowWrapper();
WindowWrapper(Centrum* g_centrum);
~WindowWrapper();
private:
// Callbacks
static void key_callback(
GLFWwindow* window, int key, int scancode, int action, int mods
);
};
WindowWrapper.cpp
WindowWrapper::WindowWrapper(Centrum* g_centrum){
g_centrum_ = g_centrum;
// Initialize window
glfwSetKeyCallback(window_, key_callback); // Problems
// Window loop and OpenGL stuff
}
WindowWrapper::~WindowWrapper(){
thread_.join(); // Don't worry about this, it works but, I will make it safer.
glfwDestroyWindow(window_);
printf("WindowWrapper Completely Destructed!\n"); // For testing purposes
}
void WindowWrapper::key_callback(
GLFWwindow* window, int key, int scancode, int action, int mods
){
// This function is declared static in the class declaration.
// And as a result I cannot use g_centrum_ since it is a non-static variable
// Essentially I want to be able to access g_centrum_ from this function
g_centrum_->input_eventmanager_->key_eventmanager_->
TriggerKeyEvent(key, action, mods);
}
The first way I thought to do this was to pass a reference to g_centrum
, but GLFW will not all any deviation from the parameters for a callback.
My second attempt was to declare and define the callbacks in the constructor, but you cannot do that.
My third attempt was to make g_centrum_
static, but I would have to give it the reference outside of the constructor and I don't think that to be an elegant solution.
Use glfwSetWindowUserPointer()
to associate your wrapper pointer to the window before you register your callback. When your callback is called, you can use glfwGetWindowUserPointer()
to retrieve it. These APIs are described in the GLFW documentation.
Window user pointer
Each window has a user pointer that can be set with glfwSetWindowUserPointer and fetched with glfwGetWindowUserPointer. This can be used for any purpose you need and will not modified by GLFW throughout the life-time of the window.
As an example, you could do this in your WindowWrapper
constructor:
WindowWrapper::WindowWrapper(Centrum* g_centrum){
g_centrum_ = g_centrum;
// Initialize window first
...
// Now, associate the wrapper to the window
glfwSetWindowUserPointer(window_, this);
glfwSetKeyCallback(window_, key_callback); // Problems
// Window loop and OpenGL stuff
}
Then, in your callback:
void WindowWrapper::key_callback(
GLFWwindow* window, int key, int scancode, int action, int mods
){
void *data = glfwGetWindowUserPointer(window);
WindowWrapper *w = static_cast<WindowWrapper *>(data);
w->g_centrum_->input_eventmanager_->key_eventmanager_->
TriggerKeyEvent(key, action, mods);
}
You could have a static map that maps each GLFWindow*
to its corresponding WindowWrapper
:
private:
static std::map<GLFWindow*, WindowWrapper*> m_instanceMap;
...
Then in the constructor, you add an entry to this map:
m_instanceMap.insert(std::make_pair(window_, this));
In the destructor, remove it:
m_instanceMap.erase(window_);
Now, in the (static) callback method, you can look up the class instance, and invoke a per instance method:
void WindowWrapper::key_callback(
GLFWwindow* window, int key, int scancode, int action, int mods)
{
WindowWrapper* pThis = m_instanceMap[window];
pThis->keyHandler(key, scancode, action, mods);
}
Where keyHandler()
is a regular instance method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With