(C++) CIrrEventReceiver

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

(C++) CIrrEventReceiver

Post by Halifax »

Right now CIrrEventReceiver is in an early stage. It currently only supports keyboard, and mouse input. I would like to extend this into an easy to use GUI handler also.

So far it supports a wide variety of functions, and handling of the mouse. Here is just a quick example that a put together. You quit by pushing the 'UP' key. Sorry this example sucks so much, but I was pressed for time.

Download:
v 1.0 - http://weregoose.unitedti.org/halifax/C ... ceiver.rar

Code: Select all

int main()
{
	IrrlichtDevice *device = createDevice(EDT_OPENGL,
								dimension2d<s32>(640,480),
								16,
								false,
								false,
								false,
								0);
	
	IVideoDriver* driver = device->getVideoDriver();
	
	CIrrEventReceiver* recv = new CIrrEventReceiver();
	device->setEventReceiver(recv);
	
	while (device->run() && recv->isKeyUp(KEY_UP))
	{
		driver->beginScene(true, true, SColor(0,0,255,0));
		driver->endScene();
	}
	
	device->drop();
	return 0;
}
Current list of functions:
  • * isKeyDown()
    * isKeyUp()
    * isMouseButtonDown()
    * isMouseButtonUp()
    * getMouseX()
    * getMouseY()
    * getLastMouseX()
    * getLastMouseY()
    * getDeltaMouseX()
    * getDeltaMouseY()
    * getClickedMouseX()
    * getClickedMouseY()
    * getMouseWheelPosition()
    * getLastMouseWheelPosition()
    * getDeltaMouseWheelPosition()
Please report any bugs that you find, and suggest features! Also suggest things that you wish to be implemented also. :lol:
TheQuestion = 2B || !2B
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

Bugfixes:

In CIrrEventReceiver.h change:

Code: Select all

virtual bool OnEvent(SEvent event);
to

Code: Select all

virtual bool OnEvent(const SEvent& event);
In CIrrEventReceiver.cpp change:(last function)

Code: Select all

bool CIrrEventReceiver::OnEvent(SEvent event)
to

Code: Select all

bool CIrrEventReceiver::OnEvent(const SEvent& event)
and change(at the end of the OnEvent function)

Code: Select all

            break;
				}
			}
		}
		break;
	}
}
to

Code: Select all

            break;
				}
			}
		}
		break;
	}
	return false;
}
The code is now v1.4b compatible! :D Enjoy![/code]
TheQuestion = 2B || !2B
Yustme
Posts: 107
Joined: Sat Dec 01, 2007 10:50 pm

Post by Yustme »

Hi Halifax,

I am using your event receive class for mouse and keyboard events. Great code sample.

But i was having troubles with the inline functions. Didn't matter what function i called, they all gave me a linker error.

After asking for help about this on IRC channel, i found out that the inline functions should be implemented in the header file.

Credits goes to bitplane and CuteAlien for finding the error.

This is how the header file should look like:

Code: Select all


/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#ifndef __CIRREVENTRECEIVER_H__
#define __CIRREVENTRECEIVER_H__

#include <Irrlicht.h>

using namespace irr;
using namespace core;

/* I doubt the number of keys will go above 255 ;), but it is there for compatibility issues */
#define NUMBER_OF_KEYS KEY_KEY_CODES_COUNT
#define NUMBER_OF_MOUSE_BUTTONS 2

enum buttonState 
{
	BS_UP,
	BS_DOWN
};

enum mouseButton
{
	MB_LEFT,
	MB_MIDDLE,
	MB_RIGHT
};

struct mouseInformation 
{
	u32 x, y, lx, ly, cx, cy;
	f32 wheelPos, lwheelPos;
};

class CIrrEventReceiver : public IEventReceiver
{
	public:
		CIrrEventReceiver();
		~CIrrEventReceiver();
		
		bool isKeyDown(EKEY_CODE key);
		bool isKeyUp(EKEY_CODE key);
		
		bool isMouseButtonDown(mouseButton mb);
		bool isMouseButtonUp(mouseButton mb);

		inline u32 getMouseX() { return MouseData.x; }
		inline u32 getMouseY() { return MouseData.y; }
		inline u32 getLastMouseX() { return MouseData.lx; }
		inline u32 getLastMouseY() { return MouseData.ly; }

		inline u32 getDeltaMouseX()
		{
			s32 a = MouseData.x - MouseData.lx;
			return (u32)(a < 0 ? -a : a);
		}

		inline u32 getDeltaMouseY()
		{
			s32 a = MouseData.y - MouseData.ly;
			return (u32)(a < 0 ? -a : a);
		}

		inline u32 getClickedMouseX() { return MouseData.cx; }
		inline u32 getClickedMouseY() { return MouseData.cy; }

		inline f32 getMouseWheelPosition() { return MouseData.wheelPos; }
		inline f32 getLastMouseWheelPosition() { return MouseData.lwheelPos; }

		inline f32 getDeltaMouseWheelPosition()
		{
			f32 a = MouseData.wheelPos - MouseData.lwheelPos;
			return (f32)(a < 0 ? -a : a);
		}

		
		bool CIrrEventReceiver::OnEvent(const SEvent& event);
		
	protected:
		buttonState Keys[NUMBER_OF_KEYS];
		buttonState Mouse[NUMBER_OF_MOUSE_BUTTONS];
		mouseInformation MouseData;
		
};

#endif /* __CIRREVENTRECEIVER_HEADER__ */


And this is how the cpp file should look like:

Code: Select all


/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#include <stdio.h>
#include "CIrrEventReceiver.h"

CIrrEventReceiver::CIrrEventReceiver()
{
	for (u32 i=0; i<NUMBER_OF_KEYS; i++)
		Keys[i] = BS_UP;
	
	Mouse[MB_LEFT] = Mouse[MB_MIDDLE] = Mouse[MB_RIGHT] = BS_UP;
	
	MouseData.x = MouseData.y = MouseData.lx = MouseData.ly = MouseData.cx = MouseData.cy = 0;
	MouseData.wheelPos = MouseData.lwheelPos = 0;
}

CIrrEventReceiver::~CIrrEventReceiver() 
{ 
}

bool CIrrEventReceiver::isKeyDown(EKEY_CODE key)
{
	if (Keys[key] == BS_DOWN)
		return true;
	return false;
}

bool CIrrEventReceiver::isKeyUp(EKEY_CODE key)
{
	if (Keys[key] == BS_UP)
		return true;
	return false;
}

bool CIrrEventReceiver::isMouseButtonDown(mouseButton mb)
{
	if (Mouse[mb] == BS_DOWN)
		return true;
	return false;
}

bool CIrrEventReceiver::isMouseButtonUp(mouseButton mb)
{
	if (Mouse[mb] == BS_UP)
		return true;
	return false;
}

bool CIrrEventReceiver::OnEvent(const SEvent& event)
{
	switch (event.EventType) 
	{
		
		case EET_KEY_INPUT_EVENT:
		{
			if (event.KeyInput.PressedDown)
				Keys[event.KeyInput.Key] = BS_DOWN;
			else
				Keys[event.KeyInput.Key] = BS_UP;
			
			break;
		}
		
		case EET_MOUSE_INPUT_EVENT:
		{
			switch (event.MouseInput.Event)
			{
				case EMIE_MOUSE_MOVED:
				{
					MouseData.lx = MouseData.x;
					MouseData.ly = MouseData.y;
					MouseData.x = event.MouseInput.X;
					MouseData.y = event.MouseInput.Y;
					
					break;
				}
				
				case EMIE_MOUSE_WHEEL:
				{
					MouseData.lwheelPos = MouseData.wheelPos;
					MouseData.wheelPos += event.MouseInput.Wheel;
				
					break;
				}
				
				case EMIE_LMOUSE_PRESSED_DOWN:
				{
					Mouse[MB_LEFT] = BS_DOWN;
					MouseData.cx = event.MouseInput.X;
					MouseData.cy = event.MouseInput.Y;
					
					break;
				}
				
				case EMIE_LMOUSE_LEFT_UP:
				{
					Mouse[MB_LEFT] = BS_UP;
					
					break;
				}
				
				case EMIE_MMOUSE_PRESSED_DOWN:
				{
					Mouse[MB_MIDDLE] = BS_DOWN;
					MouseData.cx = event.MouseInput.X;
					MouseData.cy = event.MouseInput.Y;
					
					break;
				}
				
				case EMIE_MMOUSE_LEFT_UP:
				{
					Mouse[MB_MIDDLE] = BS_UP;
					
					break;
				}
				
				case EMIE_RMOUSE_PRESSED_DOWN:
				{
					Mouse[MB_RIGHT] = BS_DOWN;
					MouseData.cx = event.MouseInput.X;
					MouseData.cy = event.MouseInput.Y;
					
					break;
				}
				
				case EMIE_RMOUSE_LEFT_UP:
				{
					Mouse[MB_RIGHT] = BS_UP;
					
					break;
				}
			}
		}
		break;
	}
	return false;
}


The honor is yours to change the version number :D
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

thanks for adding this feature.

awesome.
Image
Yustme
Posts: 107
Joined: Sat Dec 01, 2007 10:50 pm

Post by Yustme »

Hi,

I think I found a bug in the mouse button states.

In my game there are 2 spheres. It's a turn based game.

After shooting my sphere the other player is on turn.

And when he got his shot, my sphere is suddenly shot right after the second player did.

This is because the left mouse button which was down when i took my first shot, never got reseted.

So i added a method which does this for me. I call this method from my main.cpp.

In the header file i added this line:

Code: Select all

void resetMouseButtonState();
In the cpp file i added these 4 lines:

Code: Select all

void CIrrEventReceiver::resetMouseButtonState()
{
	Mouse[MB_LEFT] = BS_UP;
}
In my case, the left mouse button was enough.

But if you want them all to be reseted again, you can change it to this:

Code: Select all

void CIrrEventReceiver::resetMouseButtonState()
{
	Mouse[MB_LEFT] = Mouse[MB_MIDDLE] = Mouse[MB_RIGHT] = BS_UP;
}

Merry Christmas everyone :D
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

Wow, I am very surprised people are still using this, haha. Thanks for keeping it updated, and trying to make it stable Yustme.
TheQuestion = 2B || !2B
GameDude
Posts: 500
Joined: Thu May 24, 2007 12:24 am

Post by GameDude »

This is a pretty good small program. Sure it could use improvements, but its pretty easy to add anything you want, yourself.
Yustme
Posts: 107
Joined: Sat Dec 01, 2007 10:50 pm

Post by Yustme »

Hi,

I have updated the class again.

I added support for:

- Key pressed/released events for mouse and keyboard;
- Gui events (atm only buttons);

I'll updated the Gui events again soon. So that it's returning the ID of the component that caused the event.

Right now it's done manually by just checking in the event class which ID of the button caused the event to fire.

Header file:

Code: Select all

/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#ifndef __CIRREVENTRECEIVER_H__
#define __CIRREVENTRECEIVER_H__

#include <Irrlicht.h>
#include <iostream>
#include <sstream>

using namespace irr;
using namespace core;
using namespace gui;
using namespace io;
using namespace std;

/* I doubt the number of keys will go above 255 ;), but it is there for compatibility issues */
#define NUMBER_OF_KEYS KEY_KEY_CODES_COUNT
#define NUMBER_OF_MOUSE_BUTTONS 3

enum buttonState 
{
	BS_UP,
	BS_DOWN,
	BS_PRESSED,
	BS_RELEASED
};

enum mouseButtonState 
{
	MBS_UP,
	MBS_DOWN,
	MBS_PRESSED,
	MBS_RELEASED
};

enum mouseButton
{
	MB_LEFT,
	MB_MIDDLE,
	MB_RIGHT
};

struct mouseInformation 
{
	s32 x, y, lx, ly, cx, cy;
	f32 wheelPos, lwheelPos;
};

// Enumeration for Event Handling State.
enum ProcessEventState
{
	STARTED, 
	ENDED
};

class CIrrEventReceiver : public IEventReceiver
{
	public:
		CIrrEventReceiver();
		~CIrrEventReceiver();
		
		// for buttons GUI:
		bool isButtonOnePressed();
		bool isButtonTwoPressed();
		bool isButtonThreePressed();
		
		void resetButtonOnePressed();
		void resetButtonTwoPressed();
		void resetButtonThreePressed();
		
		// Keyboard events:
		bool isKeyUp(EKEY_CODE key);
		bool isKeyDown(EKEY_CODE key);
		bool isKeyPressed(EKEY_CODE key);
		bool isKeyReleased(EKEY_CODE key);
		
		// Mouse events:
		bool isMouseButtonPressed(mouseButton mb);
		bool isMouseButtonReleased(mouseButton mb);

		bool isMouseButtonDown(mouseButton mb);
		bool isMouseButtonUp(mouseButton mb);

		bool mouseMoved();
		
		// Processing functions:
		void startEventProcess();
		void endEventProcess();

		int getDeltaMousePosX();
		int getDeltaMousePosY();

		inline int getMouseX() { return MouseData.x; }
		inline int getMouseY() { return MouseData.y; }
		inline int getLastMouseX() { return MouseData.lx; }
		inline int getLastMouseY() { return MouseData.ly; }

		inline s32 getDeltaMouseX()
		{
			s32 a = MouseData.x - MouseData.lx;
			return (s32)(a < 0 ? -a : a);
		}

		inline s32 getDeltaMouseY()
		{
			s32 a = MouseData.y - MouseData.ly;
			return (s32)(a < 0 ? -a : a); 
		}

		inline u32 getClickedMouseX() { return MouseData.cx; }
		inline u32 getClickedMouseY() { return MouseData.cy; }

		inline f32 getMouseWheelPosition() { return MouseData.wheelPos; }
		inline f32 getLastMouseWheelPosition() { return MouseData.lwheelPos; }

		inline f32 getDeltaMouseWheelPosition()
		{
			f32 a = MouseData.wheelPos - MouseData.lwheelPos;
			return (f32)(a < 0 ? -a : a);
		}

		bool OnEvent(const SEvent& event);

	protected:
		buttonState Keys[NUMBER_OF_KEYS];
		mouseButtonState Mouse[NUMBER_OF_MOUSE_BUTTONS];
		mouseInformation MouseData;
		ProcessEventState procesState;
		
		bool mouseHasMoved;
		
		// for buttons GUI:
		bool btnOnePressed;
		bool btnTwoPressed;
		bool btnThreePressed;
		 
		int deltaMouseX;
		int deltaMouseY;
		
		// for converting anything to string (good for debug to console).
		template <class T>
		inline std::string ToString(const T& t)
		{
			std::stringstream ss;
			ss << t;
			return ss.str();
		}
};

#endif /* __CIRREVENTRECEIVER_HEADER__ */

The Source file:

Code: Select all

/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#include <stdio.h>
#include "CIrrEventReceiver.h"

CIrrEventReceiver::CIrrEventReceiver()
{
	for(u32 i = 0; i < NUMBER_OF_KEYS; i++)
		Keys[i] = BS_UP;
	
	Mouse[MB_LEFT] = Mouse[MB_MIDDLE] = Mouse[MB_RIGHT] = MBS_UP;

	MouseData.x = MouseData.y = MouseData.lx = MouseData.ly = MouseData.cx = MouseData.cy = 0;
	MouseData.wheelPos = MouseData.lwheelPos = 0;

	deltaMouseX = deltaMouseY = 0;

	mouseHasMoved = false;
	
	btnOnePressed = btnTwoPressed = btnThreePressed = false;
}

CIrrEventReceiver::~CIrrEventReceiver() 
{ 
}

bool CIrrEventReceiver::isKeyUp(EKEY_CODE key)
{
	if (Keys[key] == BS_UP)
		return true;
	return false;
}

bool CIrrEventReceiver::isKeyDown(EKEY_CODE key)
{
	if (Keys[key] == BS_DOWN)
		return true;
	return false;
}

bool CIrrEventReceiver::isKeyPressed(EKEY_CODE key)
{
  if(Keys[key] == BS_PRESSED)
    return true;
  else 
    return false;
}

bool CIrrEventReceiver::isKeyReleased(EKEY_CODE key)
{
  if(Keys[key] == BS_RELEASED)
    return true;
  else
    return false;
}

bool CIrrEventReceiver::isMouseButtonUp(mouseButton mb)
{
	if (Mouse[mb] == MBS_UP)
		return true;
	return false;
}

bool CIrrEventReceiver::isMouseButtonDown(mouseButton mb)
{
	if (Mouse[mb] == MBS_DOWN)
		return true;
	return false;
}


bool CIrrEventReceiver::isMouseButtonPressed(mouseButton mb)
{
	if (Mouse[mb] == MBS_PRESSED)
		return true;
	return false;
}

bool CIrrEventReceiver::isMouseButtonReleased(mouseButton mb)
{
	if (Mouse[mb] == MBS_RELEASED)
		return true;
	return false;
}

int CIrrEventReceiver::getDeltaMousePosX()
{
	return deltaMouseX;
}

int CIrrEventReceiver::getDeltaMousePosY()
{
	return deltaMouseY;
}

bool CIrrEventReceiver::mouseMoved()
{
	if(mouseHasMoved)
	{
		// set its state back to false.
		mouseHasMoved = false;
		return true;
	}

	else
		return false;
}

// for graphical user interface (just the buttons for now):
bool CIrrEventReceiver::isButtonOnePressed()
{
	return btnOnePressed;
}

bool CIrrEventReceiver::isButtonTwoPressed()
{
	return btnTwoPressed;
}

bool CIrrEventReceiver::isButtonThreePressed()
{
	return btnThreePressed;
}

void CIrrEventReceiver::resetButtonOnePressed()
{
	// set its state back to false.
	btnOnePressed = false;
}

void CIrrEventReceiver::resetButtonTwoPressed()
{
	// set its state back to false.
	btnTwoPressed = false;
}

void CIrrEventReceiver::resetButtonThreePressed()
{
	// set its state back to false.
	btnThreePressed = false;
}
// end gui button functions


// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this function at the END of your Main Loop.
void CIrrEventReceiver::startEventProcess()
{
	procesState = STARTED;

	// Keyboard Key States
	for(int i = 0; i < KEY_KEY_CODES_COUNT; i++)
	{
		if(Keys[i] == BS_RELEASED)
			Keys[i] = BS_UP;
		
		if(Keys[i] == BS_PRESSED)
			Keys[i] = BS_DOWN;
	}
	
	// Mouse Key States
	for(int i = 0; i < NUMBER_OF_MOUSE_BUTTONS; i++)
	{
		if(Mouse[i] == MBS_RELEASED)
			Mouse[i] = MBS_UP;

		if(Mouse[i] == MBS_PRESSED)
			Mouse[i] = MBS_DOWN;
	}
}

// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this at the very START of your Main Loop
void CIrrEventReceiver::endEventProcess()
{
	procesState = ENDED;
}

bool CIrrEventReceiver::OnEvent(const SEvent& event)
{
	switch (event.EventType) 
	{
		case EET_KEY_INPUT_EVENT:
		{
			if(procesState == STARTED)
			{
				if(event.KeyInput.PressedDown)
				{
					// If key was not down before
					if(Keys[event.KeyInput.Key] != BS_DOWN)
						Keys[event.KeyInput.Key] = BS_PRESSED; // Set key to Pressed
					else
						Keys[event.KeyInput.Key] = BS_DOWN;
				}
				
				else
				{
					// if the key is down
					if(Keys[event.KeyInput.Key] != BS_UP)    
						Keys[event.KeyInput.Key] = BS_RELEASED; // Set key to Released
					else
						Keys[event.KeyInput.Key] = BS_UP;
				}
			}
			
			break;
		}
		
		case EET_MOUSE_INPUT_EVENT:
		{
			switch(event.MouseInput.Event)
			{
				case EMIE_MOUSE_MOVED:
				{
					deltaMouseX = event.MouseInput.X - MouseData.lx;
					deltaMouseY = event.MouseInput.Y - MouseData.ly;

					MouseData.x = event.MouseInput.X;
					MouseData.y = event.MouseInput.Y;

					MouseData.lx = MouseData.x;
					MouseData.ly = MouseData.y;
					
					mouseHasMoved = true;

					break;
				}
				
				case EMIE_MOUSE_WHEEL:
				{
					MouseData.lwheelPos = MouseData.wheelPos;
					MouseData.wheelPos += event.MouseInput.Wheel;
				
					break;
				}
				
				case EMIE_LMOUSE_PRESSED_DOWN:
				{
					Mouse[MB_LEFT] = MBS_DOWN;
					MouseData.cx = event.MouseInput.X;
					MouseData.cy = event.MouseInput.Y;
					
					break;
				}
				
				case EMIE_LMOUSE_LEFT_UP:
				{
					Mouse[MB_LEFT] = MBS_UP;
					
					break;
				}
				
				case EMIE_MMOUSE_PRESSED_DOWN:
				{
					Mouse[MB_MIDDLE] = MBS_DOWN;
					MouseData.cx = event.MouseInput.X;
					MouseData.cy = event.MouseInput.Y;
					
					break;
				}
				
				case EMIE_MMOUSE_LEFT_UP:
				{
					Mouse[MB_MIDDLE] = MBS_UP;
					
					break;
				}
				
				case EMIE_RMOUSE_PRESSED_DOWN:
				{
					Mouse[MB_RIGHT] = MBS_DOWN;
					MouseData.cx = event.MouseInput.X;
					MouseData.cy = event.MouseInput.Y;
					
					break;
				}
				
				case EMIE_RMOUSE_LEFT_UP:
				{
					Mouse[MB_RIGHT] = MBS_UP;
					
					break;
				}
			}
		}

		case EET_GUI_EVENT:
		{
			switch(event.GUIEvent.EventType)
			{
				case EGET_BUTTON_CLICKED:
				{
					if(event.GUIEvent.Caller->getID() == 103) // you might wanna chance 103 to your own button ID.
						btnOnePressed = true;
					
					if(event.GUIEvent.Caller->getID() == 104) // you might wanna chance 104 to your own button ID.
						btnTwoPressed = true;

					if(event.GUIEvent.Caller->getID() == 105) // you might wanna chance 105 to your own button ID.
						btnThreePressed = true;
				}
			}
		}

		break;
	}
	
	return false;
}

I copied these functions:

Code: Select all

void startEventProcess();
void endEventProcess();

From the Masteventreceive class (hope he doesn't mind).

Put the endEventProcess() function at the beginning of your mainloop.

And put the startEventProcess() function at the end of your mainloop.

This is needed for getting the Pressed/Released events from keyboard and mouse buttons.
Last edited by Yustme on Sun Jan 27, 2008 9:02 pm, edited 1 time in total.
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

Great job, Yustme, I really like your improvements to this event receiver.
TheQuestion = 2B || !2B
Yustme
Posts: 107
Joined: Sat Dec 01, 2007 10:50 pm

Post by Yustme »

Hi Halifax,

It's my pleasure!

I've added support for all GUI events.

I haven't tested it with all the gui elements. The ones i have tested worked great:
  • Button;
    Editbox;
    Scrollbar;
    Checkbox;
Here is the header file:

Code: Select all

/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#ifndef __CIRREVENTRECEIVER_H__
#define __CIRREVENTRECEIVER_H__

#include <Irrlicht.h>
#include <iostream>
#include <sstream>

using namespace irr;
using namespace core;
using namespace gui;
using namespace io;
using namespace std;

/* I doubt the number of keys will go above 255 ;), but it is there for compatibility issues */
#define NUMBER_OF_KEYS KEY_KEY_CODES_COUNT
#define NUMBER_OF_MOUSE_BUTTONS 3
#define NUMBER_OF_GUI_ELEMENTS 21

enum buttonState 
{
	BS_UP,
	BS_DOWN,
	BS_PRESSED,
	BS_RELEASED
};

enum mouseButtonState 
{
	MBS_UP,
	MBS_DOWN,
	MBS_PRESSED,
	MBS_RELEASED
};

enum mouseButton
{
	MB_LEFT,
	MB_MIDDLE,
	MB_RIGHT
};

struct mouseInformation 
{
	s32 x, y, lx, ly, cx, cy;
	f32 wheelPos, lwheelPos;
};

// Enumeration for Event Handling State.
enum ProcessEventState
{
	STARTED, 
	ENDED
};

enum ElementStatus
{
	TRUE,
	FALSE
};

class CIrrEventReceiver : public IEventReceiver
{
	public:
		CIrrEventReceiver();
		~CIrrEventReceiver();
		
		// for buttons GUI:
		bool getEventCallerByElement(EGUI_EVENT_TYPE);
		int getEventCallerByID();

		// Keyboard events:
		bool isKeyUp(EKEY_CODE key);
		bool isKeyDown(EKEY_CODE key);
		bool isKeyPressed(EKEY_CODE key);
		bool isKeyReleased(EKEY_CODE key);
		
		// Mouse events:
		bool isMouseButtonPressed(mouseButton mb);
		bool isMouseButtonReleased(mouseButton mb);

		bool isMouseButtonDown(mouseButton mb);
		bool isMouseButtonUp(mouseButton mb);

		bool mouseMoved();
		
		// Processing functions:
		void startEventProcess();
		void endEventProcess();

		int getDeltaMousePosX();
		int getDeltaMousePosY();
		
		inline int getMouseX() { return MouseData.x; }
		inline int getMouseY() { return MouseData.y; }
		inline int getLastMouseX() { return MouseData.lx; }
		inline int getLastMouseY() { return MouseData.ly; }

		inline s32 getDeltaMouseX()
		{
			s32 a = MouseData.x - MouseData.lx;
			return (s32)(a < 0 ? -a : a);
		}

		inline s32 getDeltaMouseY()
		{
			s32 a = MouseData.y - MouseData.ly;
			return (s32)(a < 0 ? -a : a); 
		}

		inline u32 getClickedMouseX() { return MouseData.cx; }
		inline u32 getClickedMouseY() { return MouseData.cy; }

		inline f32 getMouseWheelPosition() { return MouseData.wheelPos; }
		inline f32 getLastMouseWheelPosition() { return MouseData.lwheelPos; }

		inline f32 getDeltaMouseWheelPosition()
		{
			f32 a = MouseData.wheelPos - MouseData.lwheelPos;
			return (f32)(a < 0 ? -a : a);
		}

		bool OnEvent(const SEvent& event);

	protected:
		buttonState Keys[NUMBER_OF_KEYS];
		mouseButtonState Mouse[NUMBER_OF_MOUSE_BUTTONS];
		ElementStatus elementStatus[NUMBER_OF_GUI_ELEMENTS];
		mouseInformation MouseData;
		ProcessEventState procesState;
		
		int deltaMouseX;
		int deltaMouseY;
		
		bool mouseHasMoved;
		 
		int callerID;
		
		// for converting anything to string (good for debug to console).
		template <class T>
		inline std::string ToString(const T& t)
		{
			std::stringstream ss;
			ss << t;
			return ss.str();
		}
};

#endif /* __CIRREVENTRECEIVER_HEADER__ */

And here is the source file:

Code: Select all

/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#include <stdio.h>
#include "CIrrEventReceiver.h"

CIrrEventReceiver::CIrrEventReceiver()
{
	for(u32 i = 0; i < NUMBER_OF_KEYS; i++)
     Keys[i] = BS_UP;
   
	Mouse[MB_LEFT] = Mouse[MB_MIDDLE] = Mouse[MB_RIGHT] = MBS_UP;

	MouseData.x = MouseData.y = MouseData.lx = MouseData.ly = MouseData.cx = MouseData.cy = 0;
	MouseData.wheelPos = MouseData.lwheelPos = 0;

	deltaMouseX = deltaMouseY = 0;

	mouseHasMoved = false; 

	callerID = 0;

	elementStatus[EGET_ELEMENT_FOCUS_LOST] = elementStatus[EGET_ELEMENT_FOCUSED] = 
	elementStatus[EGET_ELEMENT_HOVERED] = elementStatus[EGET_ELEMENT_LEFT] =
	elementStatus[EGET_ELEMENT_CLOSED] = elementStatus[EGET_BUTTON_CLICKED] = 
	elementStatus[EGET_SCROLL_BAR_CHANGED] = elementStatus[EGET_CHECKBOX_CHANGED] =
	elementStatus[EGET_LISTBOX_CHANGED] = elementStatus[EGET_LISTBOX_SELECTED_AGAIN] = 
	elementStatus[EGET_FILE_SELECTED] = elementStatus[EGET_FILE_CHOOSE_DIALOG_CANCELLED] =
	elementStatus[EGET_MESSAGEBOX_YES] = elementStatus[EGET_MESSAGEBOX_NO] = 
	elementStatus[EGET_MESSAGEBOX_OK] = elementStatus[EGET_MESSAGEBOX_CANCEL] = 
	elementStatus[EGET_EDITBOX_ENTER] = elementStatus[EGET_TAB_CHANGED] = 
	elementStatus[EGET_MENU_ITEM_SELECTED] = elementStatus[EGET_COMBO_BOX_CHANGED] = 
	elementStatus[EGET_SPINBOX_CHANGED] = FALSE; // << set all gui elements to false
}

CIrrEventReceiver::~CIrrEventReceiver() 
{ 
}

bool CIrrEventReceiver::isKeyUp(EKEY_CODE key)
{
   if (Keys[key] == BS_UP)
      return true;
   return false;
}

bool CIrrEventReceiver::isKeyDown(EKEY_CODE key)
{
   if (Keys[key] == BS_DOWN)
      return true;
   return false;
}

bool CIrrEventReceiver::isKeyPressed(EKEY_CODE key)
{
  if(Keys[key] == BS_PRESSED)
    return true;
  return false;
}

bool CIrrEventReceiver::isKeyReleased(EKEY_CODE key)
{
  if(Keys[key] == BS_RELEASED)
    return true;
  return false;
}

bool CIrrEventReceiver::isMouseButtonUp(mouseButton mb)
{
   if (Mouse[mb] == MBS_UP)
      return true;
   return false;
}

bool CIrrEventReceiver::isMouseButtonDown(mouseButton mb)
{
   if (Mouse[mb] == MBS_DOWN)
      return true;
   return false;
}


bool CIrrEventReceiver::isMouseButtonPressed(mouseButton mb)
{
   if (Mouse[mb] == MBS_PRESSED)
      return true;
   return false;
}

bool CIrrEventReceiver::isMouseButtonReleased(mouseButton mb)
{
   if (Mouse[mb] == MBS_RELEASED)
      return true;
   return false;
}

int CIrrEventReceiver::getDeltaMousePosX()
{
   return deltaMouseX;
}

int CIrrEventReceiver::getDeltaMousePosY()
{
   return deltaMouseY;
}

bool CIrrEventReceiver::mouseMoved()
{
   if(mouseHasMoved)
   {
      // set its state back to false.
      mouseHasMoved = false;
      return true;
   }

	 return false;
}

bool CIrrEventReceiver::getEventCallerByElement(EGUI_EVENT_TYPE guiEventType)
{
	if(elementStatus[guiEventType] == TRUE)
		return true;
	return false;
}

int CIrrEventReceiver::getEventCallerByID()
{
	return callerID;
}

// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this function at the END of your Main Loop.
void CIrrEventReceiver::startEventProcess()
{
	procesState = STARTED;
	
	// Keyboard Key States
	for(int i = 0; i < KEY_KEY_CODES_COUNT; i++)
	{
		if(Keys[i] == BS_RELEASED)
			 Keys[i] = BS_UP;

		if(Keys[i] == BS_PRESSED)
		 Keys[i] = BS_DOWN;
	}

	// Mouse Key States
	for(int i = 0; i < NUMBER_OF_MOUSE_BUTTONS; i++)
	{
		if(Mouse[i] == MBS_RELEASED)
			 Mouse[i] = MBS_UP;

		if(Mouse[i] == MBS_PRESSED)
		 Mouse[i] = MBS_DOWN;
	}

	elementStatus[EGET_ELEMENT_FOCUS_LOST] = elementStatus[EGET_ELEMENT_FOCUSED] = 
	elementStatus[EGET_ELEMENT_HOVERED] = elementStatus[EGET_ELEMENT_LEFT] =
	elementStatus[EGET_ELEMENT_CLOSED] = elementStatus[EGET_BUTTON_CLICKED] = 
	elementStatus[EGET_SCROLL_BAR_CHANGED] = elementStatus[EGET_CHECKBOX_CHANGED] =
	elementStatus[EGET_LISTBOX_CHANGED] = elementStatus[EGET_LISTBOX_SELECTED_AGAIN] = 
	elementStatus[EGET_FILE_SELECTED] = elementStatus[EGET_FILE_CHOOSE_DIALOG_CANCELLED] =
	elementStatus[EGET_MESSAGEBOX_YES] = elementStatus[EGET_MESSAGEBOX_NO] = 
	elementStatus[EGET_MESSAGEBOX_OK] = elementStatus[EGET_MESSAGEBOX_CANCEL] = 
	elementStatus[EGET_EDITBOX_ENTER] = elementStatus[EGET_TAB_CHANGED] = 
	elementStatus[EGET_MENU_ITEM_SELECTED] = elementStatus[EGET_COMBO_BOX_CHANGED] = 
	elementStatus[EGET_SPINBOX_CHANGED] = FALSE; // << set all gui elements to false
}

// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this at the very START of your Main Loop
void CIrrEventReceiver::endEventProcess()
{
	procesState = ENDED;
}

bool CIrrEventReceiver::OnEvent(const SEvent& event)
{
	switch (event.EventType) 
	{
		case EET_KEY_INPUT_EVENT:
    {
			 if(procesState == STARTED)
			 {
					if(event.KeyInput.PressedDown)
					{
						 // If key was not down before
						 if(Keys[event.KeyInput.Key] != BS_DOWN)
								Keys[event.KeyInput.Key] = BS_PRESSED; // Set key to Pressed
						 else
								Keys[event.KeyInput.Key] = BS_DOWN;
					}
	        
					else
					{
						 // if the key is down
						 if(Keys[event.KeyInput.Key] != BS_UP)   
								Keys[event.KeyInput.Key] = BS_RELEASED; // Set key to Released
						 else
								Keys[event.KeyInput.Key] = BS_UP;
					}
			 }
    }

		break;

    case EET_MOUSE_INPUT_EVENT:
    {
       switch(event.MouseInput.Event)
       {
					case EMIE_MOUSE_MOVED:
					{
						 deltaMouseX = event.MouseInput.X - MouseData.lx;
						 deltaMouseY = event.MouseInput.Y - MouseData.ly;

						 MouseData.x = event.MouseInput.X;
						 MouseData.y = event.MouseInput.Y;

						 MouseData.lx = MouseData.x;
						 MouseData.ly = MouseData.y;
	           
						 mouseHasMoved = true;

						 break;
					}
          
          case EMIE_MOUSE_WHEEL:
          {
             MouseData.lwheelPos = MouseData.wheelPos;
             MouseData.wheelPos += event.MouseInput.Wheel;
          
             break;
          }
          
          case EMIE_LMOUSE_PRESSED_DOWN:
          {
             Mouse[MB_LEFT] = MBS_DOWN;
             MouseData.cx = event.MouseInput.X;
             MouseData.cy = event.MouseInput.Y;
             
             break;
          }
          
          case EMIE_LMOUSE_LEFT_UP:
          {
             Mouse[MB_LEFT] = MBS_UP;
             
             break;
          }
          
          case EMIE_MMOUSE_PRESSED_DOWN:
          {
             Mouse[MB_MIDDLE] = MBS_DOWN;
             MouseData.cx = event.MouseInput.X;
             MouseData.cy = event.MouseInput.Y;
             
             break;
          }
          
          case EMIE_MMOUSE_LEFT_UP:
          {
             Mouse[MB_MIDDLE] = MBS_UP;
             
             break;
          }
          
          case EMIE_RMOUSE_PRESSED_DOWN:
          {
             Mouse[MB_RIGHT] = MBS_DOWN;
             MouseData.cx = event.MouseInput.X;
             MouseData.cy = event.MouseInput.Y;
             
             break;
          }
          
          case EMIE_RMOUSE_LEFT_UP:
          {
             Mouse[MB_RIGHT] = MBS_UP;
             
             break;
          }

          default:
             break;
       }
    }

		break;

		case EET_GUI_EVENT:
		{
			callerID = event.GUIEvent.Caller->getID();
			elementStatus[event.GUIEvent.EventType] = TRUE;
					
			break;
		}

		default:
			break;
	}
	
	return false;
}

Here is the link to the tutorial for handling gui events with this class:

http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=25972

I hope you'll find it useful!


EDIT 29-01-2008:

The bug has been fixed. The CIrrEventReceiver is a fully functional class for all events keyboard, mouse and gui events.

Bug report:

http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=25970
Last edited by Yustme on Tue Jan 29, 2008 4:06 pm, edited 2 times in total.
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

Instead of that long switch

Code: Select all

case EET_GUI_EVENT:
      {
         switch(event.GUIEvent.EventType)
         {
            case EGET_ELEMENT_FOCUSED:
            {
               //callerID = event.GUIEvent.Caller->getID();
               //elementStatus[EGET_ELEMENT_FOCUSED] = TRUE;
               
               break;
            } 
...
Why not do something like this:

Code: Select all

case EET_GUI_EVENT:
      {
         callerID = event.GUIEvent.Caller->getID();
         elementStatus[event.GUIEvent.EventType] = true;
      }
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
Yustme
Posts: 107
Joined: Sat Dec 01, 2007 10:50 pm

Post by Yustme »

Hi MasterGod,

At the moment, the gui event handler contains a few bugs which i just reported them in the bug report forum.

That's exactly how i had it the first time, but my app crashes immediately when you start it.

But once the bugs have been fixed, i'll update the post and reduce the amount of lines in the gui switch.


EDIT 29-07-2008:

Bug has been fixed, see my last post for reference.
Yustme
Posts: 107
Joined: Sat Dec 01, 2007 10:50 pm

Post by Yustme »

Hi,

I forgot to add the "pressed" and "released" states for the mouse buttons in the switch statement.

Also I have changed the names of the mouse buttons because "MB_RIGHT" was conflicting with:

Code: Select all

#define MB_RIGHT                    0x00080000L

Which is defined in the winuser.h header file.

This is the error i got before changing it:
error C2664: 'CIrrEventReceiver::isMouseButtonPressed' : cannot convert parameter 1 from 'long' to 'mouseButton'

The CIrrEventReceiver header file:

Code: Select all

/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#ifndef __CIRREVENTRECEIVER_H__
#define __CIRREVENTRECEIVER_H__

#include <Irrlicht.h>
#include <iostream>
#include <sstream>

using namespace irr;
using namespace core;
using namespace gui;
using namespace io;
using namespace std;

/* I doubt the number of keys will go above 255 ;), but it is there for compatibility issues */
#define NUMBER_OF_KEYS KEY_KEY_CODES_COUNT
#define NUMBER_OF_MOUSE_BUTTONS 2
#define NUMBER_OF_GUI_ELEMENTS 21

enum buttonState
{
	BS_UP,
	BS_DOWN,
	BS_PRESSED,
	BS_RELEASED
};

enum mouseButton
{
	MBLEFT,
	MBMIDDLE,
	MBRIGHT
};

enum mouseButtonState
{
	MBS_UP,
	MBS_DOWN,
	MBS_PRESSED,
	MBS_RELEASED
};

struct mouseInformation
{
	s32 x, y, lx, ly, cx, cy;
	f32 wheelPos, lwheelPos;
};

// Enumeration for Event Handling State.
enum ProcessEventState
{
	STARTED, 
	ENDED
};

enum ElementStatus
{
	TRUE,
	FALSE
};

class CIrrEventReceiver : public IEventReceiver
{
	public:
		CIrrEventReceiver();
		~CIrrEventReceiver();
		
		// for buttons GUI:
		bool getEventCallerByElement(EGUI_EVENT_TYPE);
		int getEventCallerByID();
		
		// Keyboard events:
    bool isKeyUp(EKEY_CODE key);
    bool isKeyDown(EKEY_CODE key);
    bool isKeyPressed(EKEY_CODE key);
    bool isKeyReleased(EKEY_CODE key);
    
    // Mouse events:
		bool isMouseButtonUp(mouseButton mb);
		bool isMouseButtonDown(mouseButton mb);
    bool isMouseButtonPressed(mouseButton mb);
    bool isMouseButtonReleased(mouseButton mb);

    bool mouseMoved();
    
    // Processing functions:
    void startEventProcess();
    void endEventProcess();

    int getDeltaMousePosX();
    int getDeltaMousePosY();
    
    inline int getMouseX() { return MouseData.x; }
    inline int getMouseY() { return MouseData.y; }
    inline int getLastMouseX() { return MouseData.lx; }
    inline int getLastMouseY() { return MouseData.ly; }

    inline s32 getDeltaMouseX()
    {
       s32 a = MouseData.x - MouseData.lx;
       return (s32)(a < 0 ? -a : a);
    }

    inline s32 getDeltaMouseY()
    {
       s32 a = MouseData.y - MouseData.ly;
       return (s32)(a < 0 ? -a : a);
    }

    inline u32 getClickedMouseX() { return MouseData.cx; }
    inline u32 getClickedMouseY() { return MouseData.cy; }

    inline f32 getMouseWheelPosition() { return MouseData.wheelPos; }
    inline f32 getLastMouseWheelPosition() { return MouseData.lwheelPos; }

    inline f32 getDeltaMouseWheelPosition()
    {
       f32 a = MouseData.wheelPos - MouseData.lwheelPos;
       return (f32)(a < 0 ? -a : a);
    }

		bool OnEvent(const SEvent& event);

	protected:
		buttonState Keys[NUMBER_OF_KEYS];
    mouseButtonState Mouse[NUMBER_OF_MOUSE_BUTTONS];
    ElementStatus elementStatus[NUMBER_OF_GUI_ELEMENTS];
    mouseInformation MouseData;
    ProcessEventState procesState;
    
    int deltaMouseX;
    int deltaMouseY;
    
    bool mouseHasMoved;
    
    int callerID;
    
    // for converting anything to string (good for debug to console).
    template <class T>
    inline std::string ToString(const T& t)
    {
       std::stringstream ss;
       ss << t;
       return ss.str();
    } 
};

#endif /* __CIRREVENTRECEIVER_HEADER__ */

The source file:

Code: Select all

/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#include <stdio.h>
#include "CIrrEventReceiver.h"

CIrrEventReceiver::CIrrEventReceiver()
{
	for(u32 i = 0; i < NUMBER_OF_KEYS; i++)
     Keys[i] = BS_UP;

	// Mouse Key States
	for(u32 i = 0; i < NUMBER_OF_MOUSE_BUTTONS; i++)
		 Mouse[i] = MBS_UP;
   
	//Mouse[MB_LEFT] = Mouse[MB_MIDDLE] = Mouse[MB_RIGHT] = MBS_UP;

	MouseData.x = MouseData.y = MouseData.lx = MouseData.ly = MouseData.cx = MouseData.cy = 0;
	MouseData.wheelPos = MouseData.lwheelPos = 0;

	deltaMouseX = deltaMouseY = 0;

	mouseHasMoved = false; 

	callerID = 0;

	elementStatus[EGET_ELEMENT_FOCUS_LOST] = elementStatus[EGET_ELEMENT_FOCUSED] = 
	elementStatus[EGET_ELEMENT_HOVERED] = elementStatus[EGET_ELEMENT_LEFT] =
	elementStatus[EGET_ELEMENT_CLOSED] = elementStatus[EGET_BUTTON_CLICKED] = 
	elementStatus[EGET_SCROLL_BAR_CHANGED] = elementStatus[EGET_CHECKBOX_CHANGED] =
	elementStatus[EGET_LISTBOX_CHANGED] = elementStatus[EGET_LISTBOX_SELECTED_AGAIN] = 
	elementStatus[EGET_FILE_SELECTED] = elementStatus[EGET_FILE_CHOOSE_DIALOG_CANCELLED] =
	elementStatus[EGET_MESSAGEBOX_YES] = elementStatus[EGET_MESSAGEBOX_NO] = 
	elementStatus[EGET_MESSAGEBOX_OK] = elementStatus[EGET_MESSAGEBOX_CANCEL] = 
	elementStatus[EGET_EDITBOX_ENTER] = elementStatus[EGET_TAB_CHANGED] = 
	elementStatus[EGET_MENU_ITEM_SELECTED] = elementStatus[EGET_COMBO_BOX_CHANGED] = 
	elementStatus[EGET_SPINBOX_CHANGED] = FALSE; // << set all gui elements to false
}

CIrrEventReceiver::~CIrrEventReceiver() 
{ 
}

bool CIrrEventReceiver::isKeyUp(EKEY_CODE key)
{
   if (Keys[key] == BS_UP)
      return true;
   return false;
}

bool CIrrEventReceiver::isKeyDown(EKEY_CODE key)
{
   if (Keys[key] == BS_DOWN)
      return true;
   return false;
}

bool CIrrEventReceiver::isKeyPressed(EKEY_CODE key)
{
  if(Keys[key] == BS_PRESSED)
    return true;
  return false;
}

bool CIrrEventReceiver::isKeyReleased(EKEY_CODE key)
{
  if(Keys[key] == BS_RELEASED)
    return true;
  return false;
}

bool CIrrEventReceiver::isMouseButtonUp(mouseButton mb)
{
   if (Mouse[mb] == MBS_UP)
      return true;
   return false;
}

bool CIrrEventReceiver::isMouseButtonDown(mouseButton mb)
{
   if (Mouse[mb] == MBS_DOWN)
      return true;
   return false;
}

bool CIrrEventReceiver::isMouseButtonPressed(mouseButton mb)
{
   if (Mouse[mb] == MBS_PRESSED)
      return true;
   return false;
}

bool CIrrEventReceiver::isMouseButtonReleased(mouseButton mb)
{
   if (Mouse[mb] == MBS_RELEASED)
      return true;
   return false;
}

int CIrrEventReceiver::getDeltaMousePosX()
{
   return deltaMouseX;
}

int CIrrEventReceiver::getDeltaMousePosY()
{
   return deltaMouseY;
}

bool CIrrEventReceiver::mouseMoved()
{
   if(mouseHasMoved)
   {
      // set its state back to false.
      mouseHasMoved = false;
      return true;
   }

	 return false;
}

bool CIrrEventReceiver::getEventCallerByElement(EGUI_EVENT_TYPE guiEventType)
{
	if(elementStatus[guiEventType] == TRUE)
		return true;
	return false;
}

int CIrrEventReceiver::getEventCallerByID()
{
	return callerID;
}

// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this function at the END of your Main Loop.
void CIrrEventReceiver::startEventProcess()
{
	procesState = STARTED;
	
	// Keyboard Key States
	for(int i = 0; i < KEY_KEY_CODES_COUNT; i++)
	{
		if(Keys[i] == BS_RELEASED)
			 Keys[i] = BS_UP;

		if(Keys[i] == BS_PRESSED)
		 Keys[i] = BS_DOWN;
	}

	// Mouse Key States
	for(int i = 0; i < NUMBER_OF_MOUSE_BUTTONS; i++)
	{
		if(Mouse[i] == MBS_RELEASED)
			 Mouse[i] = MBS_UP;

		if(Mouse[i] == MBS_PRESSED)
		 Mouse[i] = MBS_DOWN;
	}

	elementStatus[EGET_ELEMENT_FOCUS_LOST] = elementStatus[EGET_ELEMENT_FOCUSED] = 
	elementStatus[EGET_ELEMENT_HOVERED] = elementStatus[EGET_ELEMENT_LEFT] =
	elementStatus[EGET_ELEMENT_CLOSED] = elementStatus[EGET_BUTTON_CLICKED] = 
	elementStatus[EGET_SCROLL_BAR_CHANGED] = elementStatus[EGET_CHECKBOX_CHANGED] =
	elementStatus[EGET_LISTBOX_CHANGED] = elementStatus[EGET_LISTBOX_SELECTED_AGAIN] = 
	elementStatus[EGET_FILE_SELECTED] = elementStatus[EGET_FILE_CHOOSE_DIALOG_CANCELLED] =
	elementStatus[EGET_MESSAGEBOX_YES] = elementStatus[EGET_MESSAGEBOX_NO] = 
	elementStatus[EGET_MESSAGEBOX_OK] = elementStatus[EGET_MESSAGEBOX_CANCEL] = 
	elementStatus[EGET_EDITBOX_ENTER] = elementStatus[EGET_TAB_CHANGED] = 
	elementStatus[EGET_MENU_ITEM_SELECTED] = elementStatus[EGET_COMBO_BOX_CHANGED] = 
	elementStatus[EGET_SPINBOX_CHANGED] = FALSE; // << set all gui elements to false
}

// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this at the very START of your Main Loop
void CIrrEventReceiver::endEventProcess()
{
	procesState = ENDED;
}

bool CIrrEventReceiver::OnEvent(const SEvent& event)
{
	switch (event.EventType) 
	{
		case EET_KEY_INPUT_EVENT:
    {
			 if(procesState == STARTED)
			 {
					if(event.KeyInput.PressedDown)
					{
						 // If key was not down before
						 if(Keys[event.KeyInput.Key] != BS_DOWN)
								Keys[event.KeyInput.Key] = BS_PRESSED; // Set key to Pressed
						 else
								Keys[event.KeyInput.Key] = BS_DOWN;

						 break;
					}
	        
					else
					{
						 // if the key is down
						 if(Keys[event.KeyInput.Key] != BS_UP)   
								Keys[event.KeyInput.Key] = BS_RELEASED; // Set key to Released
						 else
								Keys[event.KeyInput.Key] = BS_UP;

						 break;
					}
			 }
    }

		break;

    case EET_MOUSE_INPUT_EVENT:
    {
       switch(event.MouseInput.Event)
       {
					case EMIE_MOUSE_MOVED:
					{
						 deltaMouseX = event.MouseInput.X - MouseData.lx;
						 deltaMouseY = event.MouseInput.Y - MouseData.ly;

						 MouseData.x = event.MouseInput.X;
						 MouseData.y = event.MouseInput.Y;

						 MouseData.lx = MouseData.x;
						 MouseData.ly = MouseData.y;
	           
						 mouseHasMoved = true;

						 break;
					}
          
          case EMIE_MOUSE_WHEEL:
          {
             MouseData.lwheelPos = MouseData.wheelPos;
             MouseData.wheelPos += event.MouseInput.Wheel;
          
             break;
          }
          
          // Left Mouse Button Pressed
					case EMIE_LMOUSE_PRESSED_DOWN:
          {
             if(Mouse[MBLEFT] == MBS_UP || Mouse[MBLEFT] == MBS_RELEASED)
                Mouse[MBLEFT] = MBS_PRESSED;
             
             else
                Mouse[MBLEFT] = MBS_DOWN;

						 break;
          }

          // Left Mouse Button Rleased
					case EMIE_LMOUSE_LEFT_UP:
          {
             if(Mouse[MBLEFT] != MBS_UP)
                Mouse[MBLEFT] = MBS_RELEASED;

						 break;
          }

          // Middle Mouse Button Pressed
					case EMIE_MMOUSE_PRESSED_DOWN:
          {
             if(Mouse[MBMIDDLE] == MBS_UP || Mouse[MBMIDDLE] == MBS_RELEASED)
                Mouse[MBMIDDLE] = MBS_PRESSED;
             
             else
                Mouse[MBMIDDLE] = MBS_DOWN;

						 break;
          }

          // Middle Mouse Button Rleased
					case EMIE_MMOUSE_LEFT_UP:
          {
						if (Mouse[MBMIDDLE] != MBS_UP)
                Mouse[MBMIDDLE] = MBS_RELEASED;

						 break;
          }

          // Right Mouse Button Pressed
					case EMIE_RMOUSE_PRESSED_DOWN:
          {
             if (Mouse[MBRIGHT] == MBS_UP || Mouse[MBRIGHT] == MBS_RELEASED)
                Mouse[MBRIGHT] = MBS_PRESSED;

             else
                Mouse[MBRIGHT] = MBS_DOWN;

						 break;
          }

          // Right Mouse Button Rleased
					case EMIE_RMOUSE_LEFT_UP:
          {
             if(Mouse[MBRIGHT] != MBS_UP)
                Mouse[MBRIGHT] = MBS_RELEASED;

						 break;
          }

          default:
             break;
       }
    }

		break;

		case EET_GUI_EVENT:
		{
			callerID = event.GUIEvent.Caller->getID();
			elementStatus[event.GUIEvent.EventType] = TRUE;
					
			break;
		}

		default:
			break;
	}
	
	return false;
}
Yustme
Posts: 107
Joined: Sat Dec 01, 2007 10:50 pm

Post by Yustme »

Hi,

I have extended the gui event with a new function to support the events from the context menu.

The CIrrEventReceiver header file:

Code: Select all

/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#ifndef __CIRREVENTRECEIVER_H__
#define __CIRREVENTRECEIVER_H__

#include <Irrlicht.h>
#include <iostream>
#include <sstream>

using namespace irr;
using namespace core;
using namespace gui;
using namespace io;
using namespace std;

/* I doubt the number of keys will go above 255 ;), but it is there for compatibility issues */
#define NUMBER_OF_KEYS KEY_KEY_CODES_COUNT
#define NUMBER_OF_MOUSE_BUTTONS 3
#define NUMBER_OF_GUI_ELEMENTS 21

enum buttonState
{
	BS_UP,
	BS_DOWN,
	BS_PRESSED,
	BS_RELEASED
};

enum mouseButton
{
	MBLEFT,
	MBMIDDLE,
	MBRIGHT
};

enum mouseButtonState
{
	MBS_UP,
	MBS_DOWN,
	MBS_PRESSED,
	MBS_RELEASED
};

struct mouseInformation
{
	s32 x, y, lx, ly, cx, cy;
	f32 wheelPos, lwheelPos;
};

// Enumeration for Event Handling State.
enum ProcessEventState
{
	STARTED, 
	ENDED
};

// this enum is for setting the gui events to true or false.
enum ElementStatus
{
	TRUE,
	FALSE
};

class CIrrEventReceiver : public IEventReceiver
{
	public:
		CIrrEventReceiver();
		~CIrrEventReceiver();
		
		// GUI events:
		bool getEventCallerByElement(EGUI_EVENT_TYPE);
		
		int getEventCallerOfMenuByID();
		int getEventCallerByID();

		// Keyboard events:
    bool isKeyUp(EKEY_CODE key);
    bool isKeyDown(EKEY_CODE key);
    bool isKeyPressed(EKEY_CODE key);
    bool isKeyReleased(EKEY_CODE key);
    
    // Mouse events:
		bool isMouseButtonUp(mouseButton mb);
		bool isMouseButtonDown(mouseButton mb);
    bool isMouseButtonPressed(mouseButton mb);
    bool isMouseButtonReleased(mouseButton mb);

    bool mouseMoved();
    
    // Processing functions:
    void startEventProcess();
    void endEventProcess();

    int getDeltaMousePosX();
    int getDeltaMousePosY();
    
    inline int getMouseX() { return MouseData.x; }
    inline int getMouseY() { return MouseData.y; }
    inline int getLastMouseX() { return MouseData.lx; }
    inline int getLastMouseY() { return MouseData.ly; }

    inline s32 getDeltaMouseX()
    {
       s32 a = MouseData.x - MouseData.lx;
       return (s32)(a < 0 ? -a : a);
    }

    inline s32 getDeltaMouseY()
    {
       s32 a = MouseData.y - MouseData.ly;
       return (s32)(a < 0 ? -a : a);
    }

    inline u32 getClickedMouseX() { return MouseData.cx; }
    inline u32 getClickedMouseY() { return MouseData.cy; }

    inline f32 getMouseWheelPosition() { return MouseData.wheelPos; }
    inline f32 getLastMouseWheelPosition() { return MouseData.lwheelPos; }

    inline f32 getDeltaMouseWheelPosition()
    {
       f32 a = MouseData.wheelPos - MouseData.lwheelPos;
       return (f32)(a < 0 ? -a : a);
    }
		
		
		bool OnEvent(const SEvent& event);

	protected:
		buttonState Keys[NUMBER_OF_KEYS];
    mouseButtonState Mouse[NUMBER_OF_MOUSE_BUTTONS];
    ElementStatus elementStatus[NUMBER_OF_GUI_ELEMENTS];
    mouseInformation MouseData;
    ProcessEventState procesState;
    
		IGUIContextMenu* menu;
		s32 menuItemSelectedID;
		s32 generalCallerID;

    int deltaMouseX;
    int deltaMouseY;
    
    bool mouseHasMoved;
    
    // for converting anything to string (good for debug to console).
    template <class T>
    inline std::string ToString(const T& t)
    {
       std::stringstream ss;
       ss << t;
       return ss.str();
    } 
};

#endif /* __CIRREVENTRECEIVER_HEADER__ */

The source file:

Code: Select all

/******************************************************************************
 * CIrrEventReceiver
 * =================
 *
 * CIrrEventReceiver has no restrictions. Credit would be appreciated, but not
 * required.
 ******************************************************************************/
 
#include <stdio.h>
#include "CIrrEventReceiver.h"

CIrrEventReceiver::CIrrEventReceiver()
{
	for(u32 i = 0; i < NUMBER_OF_KEYS; i++)
     Keys[i] = BS_UP;

	// Mouse Key States
	for(u32 i = 0; i < NUMBER_OF_MOUSE_BUTTONS; i++)
		 Mouse[i] = MBS_UP;
   
	MouseData.x = MouseData.y = MouseData.lx = MouseData.ly = MouseData.cx = MouseData.cy = 0;
	MouseData.wheelPos = MouseData.lwheelPos = 0;

	deltaMouseX = deltaMouseY = 0;

	mouseHasMoved = false; 

	generalCallerID = menuItemSelectedID = 0;

	menu = NULL;

	elementStatus[EGET_ELEMENT_FOCUS_LOST] = elementStatus[EGET_ELEMENT_FOCUSED] = 
	elementStatus[EGET_ELEMENT_HOVERED] = elementStatus[EGET_ELEMENT_LEFT] =
	elementStatus[EGET_ELEMENT_CLOSED] = elementStatus[EGET_BUTTON_CLICKED] = 
	elementStatus[EGET_SCROLL_BAR_CHANGED] = elementStatus[EGET_CHECKBOX_CHANGED] =
	elementStatus[EGET_LISTBOX_CHANGED] = elementStatus[EGET_LISTBOX_SELECTED_AGAIN] = 
	elementStatus[EGET_FILE_SELECTED] = elementStatus[EGET_FILE_CHOOSE_DIALOG_CANCELLED] =
	elementStatus[EGET_MESSAGEBOX_YES] = elementStatus[EGET_MESSAGEBOX_NO] = 
	elementStatus[EGET_MESSAGEBOX_OK] = elementStatus[EGET_MESSAGEBOX_CANCEL] = 
	elementStatus[EGET_EDITBOX_ENTER] = elementStatus[EGET_TAB_CHANGED] = 
	elementStatus[EGET_MENU_ITEM_SELECTED] = elementStatus[EGET_COMBO_BOX_CHANGED] = 
	elementStatus[EGET_SPINBOX_CHANGED] = FALSE; // << set all gui elements to false
}

CIrrEventReceiver::~CIrrEventReceiver() 
{ 
}

bool CIrrEventReceiver::isKeyUp(EKEY_CODE key)
{
   if (Keys[key] == BS_UP)
      return true;
   return false;
}

bool CIrrEventReceiver::isKeyDown(EKEY_CODE key)
{
   if (Keys[key] == BS_DOWN)
      return true;
   return false;
}

bool CIrrEventReceiver::isKeyPressed(EKEY_CODE key)
{
  if(Keys[key] == BS_PRESSED)
    return true;
  return false;
}

bool CIrrEventReceiver::isKeyReleased(EKEY_CODE key)
{
  if(Keys[key] == BS_RELEASED)
    return true;
  return false;
}

bool CIrrEventReceiver::isMouseButtonUp(mouseButton mb)
{
   if (Mouse[mb] == MBS_UP)
      return true;
   return false;
}

bool CIrrEventReceiver::isMouseButtonDown(mouseButton mb)
{
   if (Mouse[mb] == MBS_DOWN)
      return true;
   return false;
}

bool CIrrEventReceiver::isMouseButtonPressed(mouseButton mb)
{
   if (Mouse[mb] == MBS_PRESSED)
      return true;
   return false;
}

bool CIrrEventReceiver::isMouseButtonReleased(mouseButton mb)
{
   if (Mouse[mb] == MBS_RELEASED)
      return true;
   return false;
}

int CIrrEventReceiver::getDeltaMousePosX()
{
   return deltaMouseX;
}

int CIrrEventReceiver::getDeltaMousePosY()
{
   return deltaMouseY;
}

bool CIrrEventReceiver::mouseMoved()
{
   if(mouseHasMoved)
   {
      // set its state back to false.
      mouseHasMoved = false;
      return true;
   }

	 return false;
}

bool CIrrEventReceiver::getEventCallerByElement(EGUI_EVENT_TYPE guiEventType)
{
	if(elementStatus[guiEventType] == TRUE)
		return true;
	return false;
}

// This function will be used to get the ID of a gui element.
// This is a general function for getting the ID.
// It works for a lot of gui events but not all.
// Like getting the ID of the context menu wont work with this function
// Instead, use this function: getEventCallerOfMenuByID()
int CIrrEventReceiver::getEventCallerByID()
{
	return generalCallerID;
}

// meant for event: EGET_MENU_ITEM_SELECTED
// because IGUIContextMenu does not have the function: getID()
// in this line: event.GUIEvent.Caller->getID()
// So I had to make a custome one for the EGET_MENU_ITEM_SELECTED events.
int CIrrEventReceiver::getEventCallerOfMenuByID()
{
	return menuItemSelectedID;
}

// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this function at the END of your Main Loop.
void CIrrEventReceiver::startEventProcess()
{
	procesState = STARTED;
	
	// Keyboard Key States
	for(int i = 0; i < KEY_KEY_CODES_COUNT; i++)
	{
		if(Keys[i] == BS_RELEASED)
			 Keys[i] = BS_UP;

		if(Keys[i] == BS_PRESSED)
		 Keys[i] = BS_DOWN;
	}

	// Mouse Key States
	for(int i = 0; i < NUMBER_OF_MOUSE_BUTTONS; i++)
	{
		if(Mouse[i] == MBS_RELEASED)
			 Mouse[i] = MBS_UP;

		if(Mouse[i] == MBS_PRESSED)
		 Mouse[i] = MBS_DOWN;
	}

	elementStatus[EGET_ELEMENT_FOCUS_LOST] = elementStatus[EGET_ELEMENT_FOCUSED] = 
	elementStatus[EGET_ELEMENT_HOVERED] = elementStatus[EGET_ELEMENT_LEFT] =
	elementStatus[EGET_ELEMENT_CLOSED] = elementStatus[EGET_BUTTON_CLICKED] = 
	elementStatus[EGET_SCROLL_BAR_CHANGED] = elementStatus[EGET_CHECKBOX_CHANGED] =
	elementStatus[EGET_LISTBOX_CHANGED] = elementStatus[EGET_LISTBOX_SELECTED_AGAIN] = 
	elementStatus[EGET_FILE_SELECTED] = elementStatus[EGET_FILE_CHOOSE_DIALOG_CANCELLED] =
	elementStatus[EGET_MESSAGEBOX_YES] = elementStatus[EGET_MESSAGEBOX_NO] = 
	elementStatus[EGET_MESSAGEBOX_OK] = elementStatus[EGET_MESSAGEBOX_CANCEL] = 
	elementStatus[EGET_EDITBOX_ENTER] = elementStatus[EGET_TAB_CHANGED] = 
	elementStatus[EGET_MENU_ITEM_SELECTED] = elementStatus[EGET_COMBO_BOX_CHANGED] = 
	elementStatus[EGET_SPINBOX_CHANGED] = FALSE; // << set all gui elements to false
}

// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this at the very START of your Main Loop
void CIrrEventReceiver::endEventProcess()
{
	procesState = ENDED;
}

bool CIrrEventReceiver::OnEvent(const SEvent& event)
{
	switch (event.EventType) 
	{
		case EET_KEY_INPUT_EVENT:
    {
			 if(procesState == STARTED)
			 {
					if(event.KeyInput.PressedDown)
					{
						 // If key was not down before
						 if(Keys[event.KeyInput.Key] != BS_DOWN)
								Keys[event.KeyInput.Key] = BS_PRESSED; // Set key to Pressed
						 else
								Keys[event.KeyInput.Key] = BS_DOWN;

						 break;
					}
	        
					else
					{
						 // if the key is down
						 if(Keys[event.KeyInput.Key] != BS_UP)   
								Keys[event.KeyInput.Key] = BS_RELEASED; // Set key to Released
						 else
								Keys[event.KeyInput.Key] = BS_UP;

						 break;
					}
			 }
    }

		break;

    case EET_MOUSE_INPUT_EVENT:
    {
       switch(event.MouseInput.Event)
       {
					case EMIE_MOUSE_MOVED:
					{
						 deltaMouseX = event.MouseInput.X - MouseData.lx;
						 deltaMouseY = event.MouseInput.Y - MouseData.ly;

						 MouseData.x = event.MouseInput.X;
						 MouseData.y = event.MouseInput.Y;

						 MouseData.lx = MouseData.x;
						 MouseData.ly = MouseData.y;
	           
						 mouseHasMoved = true;

						 break;
					}
          
          case EMIE_MOUSE_WHEEL:
          {
             MouseData.lwheelPos = MouseData.wheelPos;
             MouseData.wheelPos += event.MouseInput.Wheel;
          
             break;
          }
          
          // Left Mouse Button Pressed
					case EMIE_LMOUSE_PRESSED_DOWN:
          {
             if(Mouse[MBLEFT] == MBS_UP || Mouse[MBLEFT] == MBS_RELEASED)
                Mouse[MBLEFT] = MBS_PRESSED;
             
             else
                Mouse[MBLEFT] = MBS_DOWN;

						 break;
          }

          // Left Mouse Button Rleased
					case EMIE_LMOUSE_LEFT_UP:
          {
             if(Mouse[MBLEFT] != MBS_UP)
                Mouse[MBLEFT] = MBS_RELEASED;

						 break;
          }

          // Middle Mouse Button Pressed
					case EMIE_MMOUSE_PRESSED_DOWN:
          {
             if(Mouse[MBMIDDLE] == MBS_UP || Mouse[MBMIDDLE] == MBS_RELEASED)
                Mouse[MBMIDDLE] = MBS_PRESSED;
             
             else
                Mouse[MBMIDDLE] = MBS_DOWN;

						 break;
          }

          // Middle Mouse Button Rleased
					case EMIE_MMOUSE_LEFT_UP:
          {
						if (Mouse[MBMIDDLE] != MBS_UP)
                Mouse[MBMIDDLE] = MBS_RELEASED;

						 break;
          }

          // Right Mouse Button Pressed
					case EMIE_RMOUSE_PRESSED_DOWN:
          {
             if (Mouse[MBRIGHT] == MBS_UP || Mouse[MBRIGHT] == MBS_RELEASED)
                Mouse[MBRIGHT] = MBS_PRESSED;

             else
                Mouse[MBRIGHT] = MBS_DOWN;

						 break;
          }

          // Right Mouse Button Rleased
					case EMIE_RMOUSE_LEFT_UP:
          {
             if(Mouse[MBRIGHT] != MBS_UP)
                Mouse[MBRIGHT] = MBS_RELEASED;

						 break;
          }

          default:
             break;
       }
    }

		break;

		case EET_GUI_EVENT:
		{
			generalCallerID = event.GUIEvent.Caller->getID();
			
			switch(event.GUIEvent.EventType)
			{
				case EGET_ELEMENT_FOCUS_LOST:
				case EGET_ELEMENT_FOCUSED:
				case EGET_ELEMENT_HOVERED:
				case EGET_ELEMENT_LEFT:
				case EGET_ELEMENT_CLOSED:
				case EGET_BUTTON_CLICKED:
				case EGET_SCROLL_BAR_CHANGED:
				case EGET_CHECKBOX_CHANGED:
				case EGET_LISTBOX_CHANGED:
				case EGET_LISTBOX_SELECTED_AGAIN:
				case EGET_FILE_SELECTED:
				case EGET_FILE_CHOOSE_DIALOG_CANCELLED:
				case EGET_MESSAGEBOX_YES:
				case EGET_MESSAGEBOX_NO:
				case EGET_MESSAGEBOX_OK:
				case EGET_MESSAGEBOX_CANCEL:
				case EGET_EDITBOX_ENTER:
				case EGET_TAB_CHANGED:
				case EGET_COMBO_BOX_CHANGED:
				case EGET_SPINBOX_CHANGED:
					elementStatus[event.GUIEvent.EventType] = TRUE;
				
				break;

				case EGET_MENU_ITEM_SELECTED:
					elementStatus[EGET_MENU_ITEM_SELECTED] = TRUE;
					menu = (IGUIContextMenu*)event.GUIEvent.Caller; 
					menuItemSelectedID = menu->getItemCommandId(menu->getSelectedItem());
				break;
			}
		}

		default:
			break;
	}
	
	return false;
}

[EDIT 06-02-2008]

Hi,

I changed:

Code: Select all

#define NUMBER_OF_MOUSE_BUTTONS 2
From 3 to 2 for testing something last time. But it has to be changed back to 3 because the last mouse button in the enum won't be fired by the event. Because it will only see the first 2 mouse buttons.

In this case it's the MBRIGHT mouse button, in this enum that wont be fired by not changing the 2 back to 3:

Code: Select all

enum mouseButton
{
	MBLEFT,
	MBMIDDLE,
	MBRIGHT
};

I've changed it back to 3 in the code above.

[/EDIT]
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

lol these copyrights just keep getting better.

there is almost not a single thing you can claim on this because it's all irrlicht code.

not to mention I beat you by a few months with my MasterReceiver I've been keeping a secret.

your thing has more functionality appearently but it's a different layer.

EDIT: in fact at a second glance this thing is no where near as good as my master receiver.. awsome lol
Post Reply