Mast Event Receiver

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
random
Posts: 158
Joined: Wed Aug 11, 2010 6:01 am

Post by random »

May one thing i would like to say because i also use this event receiver code and recognized some "problems".

This eventReceiver intercepts any onEvent functionality from inside other includet Classes.


two main examples:

I am also using RTSCamera script which uses an OnEvent code which was not reached from the Event, so the RTS Camera code did not worked!

Annother problem i had was that GUI events got intercepted also regarding the same problem intercepted Event´s so unreachedf inline onEvent Code because any mouseaction get cached bevor it reached the enOvent Code!

So it might happen that wished behaviour of GUI element (drag & drop, window close... for examples) or any other Classes which is naturally given by them inside within the onEvent function at their classes gets lost.

To get rid of that there i found 2 ways:

the time intensive way
1) recode any behaviour inside the event receiver ( i avoided that way but that was my conclusion)

the "speed hack" way
2) don´t do

Code: Select all

return eventprocessed;
do

Code: Select all

return false;
so any process will put through tu the onEvent functions inside included classes.

BUT (way 2 may has also a problem) it may happens that events are handeled twice or the custom inserted functionality will not get handled.

by the given examples from above (rtscammera and guielement)
when a

resizeTableColums event occours on a IGUTable
the
rtscammera will also handle this event so that the cammera rotates arround the center point while you resice the table.



There exists a third way (the one i choosed)
i deleted anything i dident need also the mousestates action and removed also the eventprocessed true in the mouseactions, that fits my needs but it doesent matter ich way you choose, you will need many time for testing all events and their desired handling.


---------

i think (and that is only my point of view) event handling with irrlicht or even c++ isnt as easy as it could be.


please correct me if I am incorrect reporting this
weloveyouclark22
Posts: 12
Joined: Thu Feb 24, 2011 10:52 pm

Post by weloveyouclark22 »

random, thank you for that post. I was confused about such until you said that. Would you recommend a different event receiver?
random
Posts: 158
Joined: Wed Aug 11, 2010 6:01 am

Post by random »

weloveyouclark22 wrote:Would you recommend a different event receiver?
well i can not recommend some other event receiver, because i am using (like mentioned) a downgradet version of this script, that fullfill´s my current needs which are surely different to your usecase.

For the MastEvenetReceiver it would be the best way (only my point of view) to allways "return false"(hardcoded).

You may want to check later in the main loop "while(device->run()) {....}" if you need any kind of event to be handeld with "if (rcv.eventprocessed == true)" twice like a "EMIE_LMOUSE_PRESSED_DOWN".
If so you may want to leave the line

Code: Select all

eventprocessed = true; 
as it is.

at the end of

Code: Select all

if (event.EventType == EET_MOUSE_INPUT_EVENT)
{
....

eventprocessed = true;//<<<<<<here
}
that would make all mouse evnets in the main loop inside the "if( rcv.eventprocessed == true)"checked in the main loop to may prevent more requests than needed.

Thatfor you need to eventprocessed available Public

Code: Select all

...
//////////////////////
// Public functions
////////////////////// 
public:
//!!!!! -- PUBLIC AVAILABLE VARIABLES --
bool eventprocessed;
//some other variables if needed
//!!!!! -- PUBLIC AVAILABLE VARIABLES --

float mouseWheel()
...
if you may want to avoid a special behaviour (like processing key events from inside the rtscammera) so that the up left right and down buttons are not used to replace and zoom the cammera position. you may want to return true; inside the event receiver or remove from the rtscammera.

afaik will gui irrlicht build in onEvent functionalitys never intercept an event. just custom added classes must than include only events that needed to be checked or even if classes from a third party needs a removing of unwished behaviour.

i should mention one thing again, may it might be misunderstood, i would not have said that the MastEventReceiver script is not good, i also would not like to say any other script might be better, i just wanted to point out that here generally a true was returned which may leads to unwished behaviour with 3rd party, custom added or Irrlicht Gui classes and that you may should check any event based behaviour by it´s own.
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

weloveyouclark22 wrote:Would you recommend a different event receiver?
not a recommendation, but here is what i use...

Code: Select all

#pragma once

#include "Irrlicht.h"

class CSEventHandler : public IEventReceiver
{
public:

	// Enumeration for UP, DOWN, PRESSED and RELEASED key states. Also used for mouse button states.
	enum keyStatesENUM {UP, DOWN, PRESSED, RELEASED};
	
	// Keyboard key states.
	keyStatesENUM keyState[KEY_KEY_CODES_COUNT];

	// Mouse data.
	struct mouseData
	{
		int X;
		int Y;
		bool LButtonDown;
		bool RButtonDown;
		bool MButtonDown;
		float Wheel; 
		float WheelDelta;
	};

	struct mouseData m_Mouse;
	int MouseX()			{ return m_Mouse.X;				};
	int MouseY()			{ return m_Mouse.Y;				};
	float MouseWheel()		{ return m_Mouse.Wheel;			};
	float MouseWheelDelta()	{ return m_Mouse.WheelDelta;	};

	CSEventHandler(void)			
	{
		for (int i = 0; i < KEY_KEY_CODES_COUNT; i++) keyState[i] = RELEASED;
		m_Mouse.X = 0;
		m_Mouse.Y = 0;
		m_Mouse.Wheel = 0;
		m_Mouse.WheelDelta = 0;
		m_Mouse.LButtonDown = false;
		m_Mouse.RButtonDown = false;
		m_Mouse.MButtonDown = false;
	};

	virtual ~CSEventHandler(void)	{};

	// keyboard events
	virtual bool OnKeyInputEvent(const SEvent& e)	{	return false;														};
	virtual bool IsKeyPressed(char keycode)			{	return (keyState[keycode] == PRESSED);								};
	virtual bool IsKeyDown(char keycode)			{	return (keyState[keycode] == DOWN || keyState[keycode] == PRESSED); };
	virtual bool IsKeyUp(char keycode)				{	return (keyState[keycode] == UP || keyState[keycode] == RELEASED);	};
	virtual bool IsKeyReleased(char keycode)		{	return (keyState[keycode] == RELEASED);								};

	// guievents
	virtual bool OnButtonClicked(const SEvent& e)			{	return false;	};
	virtual bool OnScrollBarChanged(const SEvent& e)		{	return false;	};
	virtual bool OnCheckBoxChanged(const SEvent& e)			{	return false;	};
	virtual bool OnListBoxChanged(const SEvent& e)			{	return false;	};
	virtual bool OnListBoxSelectedAgain(const SEvent& e)	{	return false;	};
	virtual bool OnFileSelected(const SEvent& e)			{	return false;	};
	virtual bool OnMessageBoxYes(const SEvent& e)			{	return false;	};
	virtual bool OnMessageBoxNo(const SEvent& e)			{	return false;	};
	virtual bool OnMessageBoxOk(const SEvent& e)			{	return false;	};
	virtual bool OnMessageBoxCancel(const SEvent& e)		{	return false;	};
	virtual bool OnEditBoxEnter(const SEvent& e)			{	return false;	};
	virtual bool OnTabChanged(const SEvent& e)				{	return false;	};
	virtual bool OnComboBoxChanged(const SEvent& e)			{	return false;	};
	virtual bool OnSpinBoxChanged(const SEvent& e)			{	return false;	};

	// mouse events
	virtual bool OnLMousePressedDown(const SEvent& e)		{	return false;	};
	virtual bool OnRMousePressedDown(const SEvent& e)		{	return false;	};
	virtual bool OnMMousePressedDown(const SEvent& e)		{	return false;	};
	virtual bool OnLMouseLeftUp(const SEvent& e)			{	return false;	};
	virtual bool OnRMouseLeftUp(const SEvent& e)			{	return false;	};
	virtual bool OnMMouseLeftUp(const SEvent& e)			{	return false;	};
	virtual bool OnMouseMoved(const SEvent& e)				{	return false;	};
	virtual bool OnMouseWheel(const SEvent& e)				{	return false;	};

	// user events
	virtual bool OnUserEvent(const SEvent& e)				{	return false;	};

	virtual bool OnEvent(const SEvent& e)
	{

		switch (e.EventType)
		{
			case EET_KEY_INPUT_EVENT : 
				{
					if (e.KeyInput.PressedDown == true)
					{
						if (keyState[e.KeyInput.Key] != DOWN) 
							keyState[e.KeyInput.Key] = PRESSED; 
						else keyState[e.KeyInput.Key] = DOWN; 
					}
					else
					if (keyState[e.KeyInput.Key] != UP)	
						keyState[e.KeyInput.Key] = RELEASED; 

					if (e.KeyInput.PressedDown == true) return OnKeyInputEvent(e); 
				} 	break;

			case EET_GUI_EVENT :
				{
					switch (e.GUIEvent.EventType)
					{
						case EGET_BUTTON_CLICKED			: return OnButtonClicked(e);
						case EGET_SCROLL_BAR_CHANGED		: return OnScrollBarChanged(e);
						case EGET_CHECKBOX_CHANGED			: return OnCheckBoxChanged(e);
						case EGET_LISTBOX_CHANGED			: return OnListBoxChanged(e);
						case EGET_LISTBOX_SELECTED_AGAIN	: return OnListBoxSelectedAgain(e);
						case EGET_FILE_SELECTED				: return OnFileSelected(e);
						case EGET_MESSAGEBOX_YES			: return OnMessageBoxYes(e);
						case EGET_MESSAGEBOX_NO				: return OnMessageBoxNo(e);
						case EGET_MESSAGEBOX_OK				: return OnMessageBoxOk(e);
						case EGET_MESSAGEBOX_CANCEL			: return OnMessageBoxCancel(e);
						case EGET_EDITBOX_ENTER				: return OnEditBoxEnter(e);
						case EGET_TAB_CHANGED				: return OnTabChanged(e);
						case EGET_COMBO_BOX_CHANGED			: return OnComboBoxChanged(e);
						case EGET_SPINBOX_CHANGED			: return OnSpinBoxChanged(e);
						default : return false;
					}
				} break; 

			case EET_MOUSE_INPUT_EVENT :
				{
					m_Mouse.X = e.MouseInput.X;
					m_Mouse.Y = e.MouseInput.Y;

					switch (e.MouseInput.Event)
					{
						case EMIE_LMOUSE_PRESSED_DOWN	:	m_Mouse.LButtonDown = true; return OnLMousePressedDown(e);
						case EMIE_RMOUSE_PRESSED_DOWN	:	m_Mouse.RButtonDown = true; return OnRMousePressedDown(e);
						case EMIE_MMOUSE_PRESSED_DOWN	:	m_Mouse.MButtonDown = true; return OnMMousePressedDown(e);
						case EMIE_LMOUSE_LEFT_UP		:	m_Mouse.LButtonDown = false; return OnLMouseLeftUp(e);
						case EMIE_RMOUSE_LEFT_UP		:	m_Mouse.RButtonDown = false; return OnRMouseLeftUp(e);
						case EMIE_MMOUSE_LEFT_UP		:	m_Mouse.MButtonDown = false; return OnMMouseLeftUp(e);
						case EMIE_MOUSE_MOVED			:	return OnMouseMoved(e);
						case EMIE_MOUSE_WHEEL			:	
							{
								m_Mouse.WheelDelta = m_Mouse.Wheel - e.MouseInput.Wheel; 
								m_Mouse.Wheel += e.MouseInput.Wheel;
								return OnMouseWheel(e);
							}
						default : return false;
					}
				} break;

			case EET_USER_EVENT : 
				{
					return OnUserEvent(e);
					default : return false;
				} break;
		}
		return false;
	}
};

i then derive my level app and level classes from this and set the app / level as the eventreceiver. Easily captures all of the gui events and keeps the code clean and organized.

Code: Select all

class app : public CSEventHandler
{
    blah blah blah.......
    
    virtual bool OnButtonClicked(const SEvent& e)	
            {	
                   switch (e.whatever)
                   {
                         case ID_SOMETHING : doit(); return true;
                         case ID_SOMETHING2 : doit2(); return true;
                         case ID_SOMETHING3 : doit3(); return true;
                    }                      
                   return false;	
             }
}


note : this isnt my code, I got it off of the forums here somewhere..............
random
Posts: 158
Joined: Wed Aug 11, 2010 6:01 am

Post by random »

@ seven very nice clean script i will try that also when i am finsished wit other parts of refacturing.

BUT (yes again a BUT) i am wondering one thing...

both scripts have (beneath allmost the same comments) the same Bug (well for me on Windows XP with Irrlicht 1.71 using code::blocks with builtin MinGW) which i just recovered yet.

on these functions

on MastEventReceiver:

Code: Select all

bool keyDown(char keycode)...
bool keyPressed(char keycode)...
bool keyUp(char keycode)...
bool keyReleased(char keycode)...
and on the CSEventHandler:

Code: Select all

   virtual bool IsKeyPressed(char keycode)
   virtual bool IsKeyDown(char keycode) 
   virtual bool IsKeyUp(char keycode)
   virtual bool IsKeyReleased(char keycode)

the argument has the wrong type.
char would work for the most cases BUT not for the control key´s!
it must be EKEY_CODE instead.

so for MastEventReceiver:

Code: Select all

bool keyDown(EKEY_CODE keycode)...
bool keyPressed(EKEY_CODE keycode)...
bool keyUp(EKEY_CODE keycode)...
bool keyReleased(EKEY_CODE keycode)...
and for CSEventHandler:

Code: Select all

   virtual bool IsKeyPressed(EKEY_CODE keycode)
   virtual bool IsKeyDown(EKEY_CODE keycode) 
   virtual bool IsKeyUp(EKEY_CODE keycode)
   virtual bool IsKeyReleased(EKEY_CODE keycode)
I do call these functions from main loop with

Code: Select all

 if (receiver.keyPressed(KEY_LCONTROL) || receiver.keyPressed(KEY_RCONTROL) || receiver.keyPressed(KEY_CONTROL))
	    {
	        std::cout << " \n PRESSED CONTROL ";
	    }
for example and the if condition will not be true with a cahr as type, or is ther something wrong with the function call?

i don´t know if that is a Bug that only occures on windows systems or even if my function call is wrong but i am wondering that both scripts used to have the same Bug and the same Comments, is there a book or an old thread in forum or a blog where the code originaly were comming from?
Post Reply