🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Is my user event handling ok ? (glfw/c++)

Started by
2 comments, last by Green_Baron 5 years, 1 month ago

So this is how i do it:

On creation, my window object (GlfwWindow * is passed in) creates an EventHandler, which holds a data structure for objects to register themselves and offers virtual methods for the c-style callback functions (code for the cursor callback, not every callback is implemented yet). In EventHandler.h/.cpp:


typedef enum eventType : unsigned int  {
		MOUSE_MOVE = 0b1,
		MOUSE_BUTTON = 0b10,
		MOUSE_SCROLL = 0b100,
		KEY = 0b1000,
		CHAR = 0b10000,
		FRAMEBUFFER_RESIZE = 0b100000
	} eventType;

std::vector<EventHandler::RegisteredObject> EventHandler::s_registeredObjects {};

EventHandler::EventHandler( GlfwWindow *win ) : m_window { win } {
	glfwSetCursorPosCallback( m_window->getWindow(), cursorPosCallback );
  ...
  ...

The callback redirects to the virtual method:


// static
void EventHandler::cursorPosCallback( GLFWwindow *w, double x, double y ) {
	EventHandler *e = reinterpret_cast<EventHandler *>( glfwGetWindowUserPointer( w ) );
	e->onMouseMove( (float)x, (float)y );
}

The virtual method iterates over registered objects and calls their respective overriden methods, that can return a bool if they don't want anybody else to handle the event:


// virtual
bool EventHandler::onMouseMove( float x, float y ) {
	bool handled = false;
	for( RegisteredObject &obj : s_registeredObjects ) {
		if( obj.types & MOUSE_MOVE ) {
			//handled = reinterpret_cast<EventHandler *>(obj.object)->onMouseMove( x, y );
			handled = obj.object->onMouseMove( x, y );
			if( handled )
				break;
		}
	}
	return handled;
}

A class that wants to receive user events must inherit from EventHandler and register the events it wants to receive via a method from the eventhandler, via a simple bit field (in the first code snippet):


void EventHandler::registerObject( RegisteredObject &obj ) {
	bool found = false;
	for( RegisteredObject &r : s_registeredObjects ) {
		if( r.object == obj.object ) {
			Logbook::getInstance().logMsg( Logbook::WINDOW, Logbook::WARNING,
				 "Ignoring try to register an already registered object with the event handler." );
			found = true;
		}
	}
	if( !found )
		s_registeredObjects.push_back( obj );
}

And overrides the inherited virtual method:


// virtual
bool Camera::onMouseMove( float x, float y ) {
	bool handled{ false };
	... do mouse move stuff ...
	return handled;
}	// onMouseMove()

It works, for Camera, UI interface and my drawing apps.

What do you think ? It is probably a standard, though i have seen more complicated solutions. Have i missed something ? Could it be done better with the window user pointer, whose function i haven't really understood ?

Advertisement

You are reinventing the wheels. And your solution is not easy to use by requiring inheritance.

There are quite some C++ event dispatcher libraries out of there. I develop my eventpp library which can be used for general purpose.

https://www.kbasm.com -- My personal website

https://github.com/wqking/eventpp  eventpp -- C++ library for event dispatcher and callback list

https://github.com/cpgf/cpgf  cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.

Well, i am aware, i checked a lot of those, and finally thought that i wanted to "cook my own soup", but am still at the beginning with all this. I needed a solution for the problem that the callbacks are c-functions, but i want to access them from different objects in c++.

But I didn't think about thread safety (yet, it is on the table), so that's a thing to keep in mind for the near future.

Question ... what's wrong with inheritance ? I find it pretty straight forward and use it for other things as well, like my renderable objects that inherit their life cycle (setup, pre-frame, render, post-frame, cleanup) as well as camera/window/ui-access via inheritance.

Edit: It is no meant as a generalized solution, others can do this much better than i will ever be able to. Just for my own brew ?

This topic is closed to new replies.

Advertisement