event handler

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Epi
Posts: 9
Joined: Wed Mar 04, 2009 4:27 am

event handler

Post by Epi »

i had this idea of using callbacks for eventhandling and wrote this code:

CInputManager.h

Code: Select all

#ifndef CINPUTMANAGER_H
#define CINPUTMANAGER_H

#include <math.h>

#include <vector>
#include <list>
using namespace std;

#include <irrlicht.h>

class CInputManager : public irr::IEventReceiver
{
private:
	static const int KEYEVENTTYPES = 3;	//releasedcall, shift, control
	static const int GUIEVENTTYPES = 24;

	vector< vector< list< void (*)(irr::SEvent event) > > > m_KeyCallerArray;
	vector< list< void (*)(irr::SEvent event) > > m_MouseCallerArray;
	
	struct SGuiPtr
	{
		irr::gui::IGUIElement *guiElementPtr;
		vector< list< void (*)(irr::SEvent event) > > eventType;
	};
	list< SGuiPtr > m_GuiCallerArray;

	int calcKeyEventType(bool released, bool shift, bool ctrl);
	bool isCallbackInList(void (*callback)(irr::SEvent), list<void (*)(irr::SEvent)>* listToCheck);

public:
	CInputManager();

	virtual bool OnEvent(const irr::SEvent& event);

	bool registerKeyEvent(irr::EKEY_CODE key, void (*callback)(irr::SEvent), bool ctrl = false, bool shift = false, bool released = false, bool allowMultiple = false);
	void removeKeyEvent(irr::EKEY_CODE key, void (*callback)(irr::SEvent), bool ctrl = false, bool shift = false, bool released = false);

	bool registerMouseEvent(irr::EMOUSE_INPUT_EVENT mouseEvent, void (*callback)(irr::SEvent), bool allowMultiple = false);
	void removeMouseEvent(irr::EMOUSE_INPUT_EVENT mouseEvent, void (*callback)(irr::SEvent));

	bool registerGUIEvent(irr::gui::IGUIElement* elementPtr, irr::gui::EGUI_EVENT_TYPE guiEvent, void (*callback)(irr::SEvent), bool allowMultiple = false);
	void removeGUIEvent(irr::gui::IGUIElement* elementPtr, irr::gui::EGUI_EVENT_TYPE guiEvent, void (*callback)(irr::SEvent));
	void removeGUIEvent(irr::gui::IGUIElement* elementPtr);
};

#endif
and the CInputManager.cpp

Code: Select all

#include "CInputManager.h"

CInputManager::CInputManager()
{
	m_KeyCallerArray.resize(irr::KEY_KEY_CODES_COUNT);
	m_MouseCallerArray.resize(irr::EMIE_COUNT);
}

bool CInputManager::OnEvent(const irr::SEvent& event)
{
	if(event.EventType == irr::EET_KEY_INPUT_EVENT)
	{
		if(m_KeyCallerArray[event.KeyInput.Key].size() != (pow((float)2,KEYEVENTTYPES)))
			return false;

		int keyEventType = calcKeyEventType(!event.KeyInput.PressedDown, event.KeyInput.Shift, event.KeyInput.Control);

		list<void (*)(irr::SEvent event)>::iterator it = m_KeyCallerArray[event.KeyInput.Key][keyEventType].begin();

		for(; it != m_KeyCallerArray[event.KeyInput.Key][keyEventType].end(); it++)
			(**it)(event);
	}
	else if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)
	{
		list<void (*)(irr::SEvent event)>::iterator it = m_MouseCallerArray[event.MouseInput.Event].begin();

		for(; it != m_MouseCallerArray[event.MouseInput.Event].end(); it++)
			(**it)(event);
	}
	else if(event.EventType == irr::EET_GUI_EVENT)
	{
		list< SGuiPtr >::iterator itElement = m_GuiCallerArray.begin();
		for(; itElement != m_GuiCallerArray.end(); itElement++)
		{
			if((*itElement).guiElementPtr = event.GUIEvent.Caller)
			{
				list< void (*)(irr::SEvent event) >::iterator itCalls = (*itElement).eventType[event.GUIEvent.EventType].begin();
				for(; itCalls != (*itElement).eventType[event.GUIEvent.EventType].end(); itCalls++)
				{
					(**itCalls)(event);
				}
				break;
			}
		}
	}
	return false;
}

bool CInputManager::isCallbackInList(void (*callback)(irr::SEvent), list<void (*)(irr::SEvent)>* listToCheck)
{
	list<void (*)(irr::SEvent event)>::iterator it = listToCheck->begin();

	for(; it != listToCheck->end(); it++)
		if(*it == callback)
			return true;

	return false;
}

bool CInputManager::registerKeyEvent(irr::EKEY_CODE key, void (*callback)(irr::SEvent), bool ctrl, bool shift, bool released, bool allowMultiple)
{
	if(m_KeyCallerArray[key].size() != (pow((float)2,KEYEVENTTYPES)))
		m_KeyCallerArray[key].resize((int)(pow((float)2,KEYEVENTTYPES)));

	int keyEventType = calcKeyEventType(released, shift, ctrl);

	if(allowMultiple == false && isCallbackInList(callback, &m_KeyCallerArray[key][keyEventType]))
		return false;

	m_KeyCallerArray[key][keyEventType].push_back(callback);

	return true;
}

void CInputManager::removeKeyEvent(irr::EKEY_CODE key, void (*callback)(irr::SEvent), bool ctrl, bool shift, bool released)
{
	if(m_KeyCallerArray[key].size() != (pow((float)2,KEYEVENTTYPES)))
		return;

	int keyEventType = calcKeyEventType(released, shift, ctrl);

	m_KeyCallerArray[key][keyEventType].remove(callback);
}

int CInputManager::calcKeyEventType(bool released, bool shift, bool ctrl)
{
	int keyEventType = 0;

	keyEventType |= (int)ctrl << 2;
	keyEventType |= (int)shift << 1;
	keyEventType |= (int)released;

	return keyEventType;
}

bool CInputManager::registerMouseEvent(irr::EMOUSE_INPUT_EVENT mouseEvent, void (*callback)(irr::SEvent), bool allowMultiple)
{
	if(allowMultiple == false && isCallbackInList(callback, &m_MouseCallerArray[mouseEvent]))
		return false;

	m_MouseCallerArray[mouseEvent].push_back(callback);

	return true;
}

void CInputManager::removeMouseEvent(irr::EMOUSE_INPUT_EVENT mouseEvent, void (*callback)(irr::SEvent))
{
	m_MouseCallerArray[mouseEvent].remove(callback);
}

bool CInputManager::registerGUIEvent(irr::gui::IGUIElement* elementPtr, irr::gui::EGUI_EVENT_TYPE guiEvent, void (*callback)(irr::SEvent), bool allowMultiple)
{
	list< SGuiPtr >::iterator it = m_GuiCallerArray.begin();
	for(; it != m_GuiCallerArray.end(); it++)
	{
		if((*it).guiElementPtr = elementPtr)
		{
			if(allowMultiple == false && isCallbackInList(callback, &((*it).eventType[guiEvent])))
				return false;

			(*it).eventType[guiEvent].push_back(callback);
			return true;
		}
	}
	vector< list< void (*)(irr::SEvent event) > > eventType(GUIEVENTTYPES);
	SGuiPtr guiPtr = {elementPtr, eventType};
	guiPtr.eventType[guiEvent].push_back(callback);
	m_GuiCallerArray.push_back(guiPtr);

	return true;
}

void CInputManager::removeGUIEvent(irr::gui::IGUIElement* elementPtr, irr::gui::EGUI_EVENT_TYPE guiEvent, void (*callback)(irr::SEvent))
{
	list< SGuiPtr >::iterator it = m_GuiCallerArray.begin();
	for(; it != m_GuiCallerArray.end(); it++)
	{
		if((*it).guiElementPtr = elementPtr)
		{
			(*it).eventType[guiEvent].remove(callback);
			break;
		}
	}
}

void CInputManager::removeGUIEvent(irr::gui::IGUIElement* elementPtr)
{
	list< SGuiPtr >::iterator it = m_GuiCallerArray.begin();
	for(; it != m_GuiCallerArray.end(); it++)
	{
		if((*it).guiElementPtr = elementPtr)
		{
			m_GuiCallerArray.erase(it);
			break;
		}
	}
}
and how to use it:

Code: Select all

//telling irrlicht about it
CInputManager inputManager;
deviceParameter.EventReceiver = &inputManager;

IrrlichtDevice *device = createDeviceEx(deviceParameter);

//the callback itself
void run(SEvent event)
{
     //...
}

//ctrl + Q for calling void run(SEvent event)
inputManager.registerKeyEvent(KEY_KEY_Q, run, true);

//left mousebutton released calls run(...)
inputManager.registerMouseEvent(EMIE_MMOUSE_LEFT_UP, run);

//a button used to call run(...)
gui::IGUIButton* tmp = env->addButton(core::rect<s32>(100,100,200,300), 0, -1, L"Quit", L"quits...");
inputManager.registerGUIEvent(tmp, gui::EGET_BUTTON_CLICKED, run);

//and to delete them...
inputManager.removeKeyEvent(KEY_KEY_Q, run, true);
inputManager.removeMouseEvent(EMIE_MMOUSE_LEFT_UP, run);
inputManager.removeGUIEvent(tmp, gui::EGET_BUTTON_CLICKED, run);
so its pretty easy to use and you dont have to write all these if's to check if something is pressed or not.

what you guys think about it?
Post Reply