Imagine++
How to use GetEvent

Keyboard and mouse events are handled by the structure Event.

I. What is inside a structure Event?

Here is the structure defining Event:

struct Event {
EventType type;
IntPoint2 pix;
int button;
int key;
EventState state;
Window win;
int subWin;
};
EventState
Event State.
Definition: Events.h:59
WindowInternal * Window
Handle to a display window.
Definition: Types.h:48
EventType
Event type (keyboard or mouse event).
Definition: Events.h:43
Coords< 2 > IntPoint2
Plane point with integral coordinates.
Definition: Types.h:17

1. Types

The type variable indicates the nature of the event. There are 6 types of events:

enum EventType {
EVT_NONE = 0,
EVT_BUT_ON = 2,
EVT_BUT_OFF = 3,
EVT_MOTION = 5,
EVT_KEY_ON,
EVT_KEY_OFF
};
  • Button events indicate whether a mouse button was pressed or released (in which case the pix field indicates the mouse position and button the button number, 1 for left, 2 for middle and 3 for right);
  • the motion type indicates a mouse motion (the pix field indicates the new mouse position);
  • key events indicate whether a keyboard key was pressed or released.
  • The EVT_NONE type indicates a non-event, that is, nothing happened.

2. Mouse Tracking

By default, mouse motion events are only registered while a mouse button is kept pressed (mouse drag). If you want to be notified of mouse motion events even when no button is pressed, use

void enableMouseTracking(bool en)
Mouse tracking, controlling whether pointer motion triggers an event.

To deactivate, use

II. How to handle events

There is an event queue that registers all events. Each time a new event occurs, it is appended in the queue, independently of the user's code running.

New event registered in the event queue

1. GetEvent

To extract the first event of the queue (the least recent one), you call the getEvent function, which fills its second argument.

When calling getEvent, the structure Event contains the information "Key A pressed", which is extracted from the queue.
// Get event.
// Gets next event in the queue. Wait for (approx) ms milliseconds before timeout.
// param ms Number of milliseconds before timeout. If ms==-1, waits until an event.
// param ev The event. If timeout, ev.type is EVT_NONE
void getEvent(int ms, Event &ev);
void getEvent(int ms, Event &ev)
Get keyboard and mouse events.

The parameters of getEvent are:

  • ms: The time (int milliseconds) to wait to have a chance of registering a new event. A value of -1 implies that we wait indefinitely until the queue is not empty.
  • ev: the filled-out structure.

When the queue is empty, ev gets type EVT_NONE to indicate that.

2. unGetEvent

It is possible to append manually a user created event with the function unGetEvent.

// Unget event.
// Push back event at end of queue.
// param: ev The event.
void unGetEvent(const Event &ev);
void unGetEvent(const Event &ev)
Unget event.

3. flushEvents

You can decide to discard all waiting events and make the queue empty with this function.

III. Examples

1. Graphical buttons

To have a nice effect, it is good to have mouse tracking enabled to provide the user with some feedback. Use enableMouseTracking(true) for that. The code studies the mouse cursor position and determines if it is inside a "button".

Window win = openWindow(800,400,"Test Event");
Event ev;
//Displaying menu's buttons
IntPoint2 P1(250,150), P2(250,250);
int w=300, h=50;
IntPoint2 Q1(P1.x()+w/3,P1.y()+h*3/5);
IntPoint2 Q2(P2.x()+w/3,P2.y()+h*3/5);
fillRect(P1,w,h,AlphaColor(150,150,150,255));
drawString(Q1,"NEW GAME",WHITE);
fillRect(P2,w,h,Color(150,150,150));
drawString(Q2,"LOAD GAME", WHITE);
bool b = false;
// receiving mouse move events even if no button is pressed
do {
getEvent(-1,ev); // ev becomes the next event
switch (ev.type) {
case EVT_NONE:
cout << "No event" << endl;
break;
case EVT_MOTION: {
int x = ev.pix.x(); // cursor's x coord
int y = ev.pix.y(); // cursor's y coord
// Cursor is in the "NEW GAME" box.
if(P1.x()<=x && x<P1.x()+w && P1.y()<=y && y<P1.y()+h) {
// Changing the box's style
fillRect(P1,w,h,Color(128,139,203));
drawString(Q1,"NEW GAME",YELLOW);
} else if(P2.x()<=x && x<P2.x()+w && P2.y()<=y && y<P2.y()+h) {
// Cursor is in the "LOAD GAME" box.
// Changing the box's style
fillRect(P2,w,h,Color(128,139,203));
drawString(Q2,"LOAD GAME", YELLOW);
} else {
fillRect(P1,w,h,Color(150,150,150));
drawString(Q1,"NEW GAME",WHITE);
fillRect(P2,w,h,Color(150,150,150));
drawString(Q2,"LOAD GAME", WHITE);
}
break;
}
case EVT_KEY_ON:
cout << "Use your mouse!"<< endl;
break;
case EVT_BUT_ON: {
int x = ev.pix.x(); // cursor's x coord
int y = ev.pix.y(); // cursor's y coord
// Click on the NEW GAME box
if(P1.x()<=x && x<P1.x()+w && P1.y()<=y && y<P1.y()+h) {
cout << "Starting a new Tetris game !!" << endl;
b = true; // Stop the menu's loop
}
break;
}
default: break;
}
} while ((ev.type!=EVT_KEY_ON || ev.key!='q' )&& !b);
const Color YELLOW
Predefined color.
Definition: Color.h:317
const Color WHITE
Predefined color.
Definition: Color.h:287
RGBA< byte > AlphaColor
RGBA<byte> alias.
Definition: Color.h:354
RGB< byte > Color
RGB<byte> alias.
Definition: Color.h:281
void closeWindow(Window w)
Close window.
Window openWindow(int w, int h, const std::string &windowTitle="Imagine++", int x=-1, int y=-1)
New window for 2D graphics.
void drawString(int x, int y, const std::string &s, const AlphaColor &col, int fontSize=12, double alpha=0, bool italic=false, bool bold=false, bool underlined=false, bool xorMode=false)
String.
void fillRect(int x, int y, int w, int h, const AlphaColor &col, bool xorMode=false)
Filled rectangle.
A game's menu

2. Moving a ball with the keyboard

We examine the value of ev.key to know the pressed key. Printable characters are identified by their ASCII code (for example 'A', '0', '?'). Non-printable keys are identified by a specific code in this list:

// Keyboard codes.
// Codes assigned to most non alpha-numeric keys.
// (alpha-numeric keys are represented by their ASCII code: 'A', '0'...)
enum KeyCode {
KEY_BACK=16777219,KEY_TAB=16777217,KEY_RETURN=16777220,
KEY_ESCAPE=16777216,KEY_SPACE=32,KEY_DELETE=16777223,KEY_START=16777250,
KEY_SHIFT=16777248,KEY_ALT=16777251,KEY_CONTROL=16777249,
KEY_MENU=16777301,KEY_PAUSE=16777224,KEY_CAPITAL=16777252,
KEY_END=16777233,KEY_HOME=16777232,
KEY_LEFT=16777234,KEY_UP=16777235,KEY_RIGHT=16777236,KEY_DOWN=16777237,
KEY_INSERT=16777222,
KEY_NUMPAD0=48, KEY_NUMPAD1, KEY_NUMPAD2, KEY_NUMPAD3, KEY_NUMPAD4,
KEY_NUMPAD5, KEY_NUMPAD6, KEY_NUMPAD7, KEY_NUMPAD8, KEY_NUMPAD9,
KEY_MULTIPLY=42,KEY_ADD,KEY_SEPARATOR,KEY_SUBTRACT,KEY_DECIMAL,
KEY_DIVIDE,
KEY_F1=16777264, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8,
KEY_F9, KEY_F10, KEY_F11, KEY_F12,
KEY_NUMLOCK=16777253, KEY_SCROLL=16777254, KEY_PAGEUP=16777238,
KEY_PAGEDOWN, KEY_NUMPAD_ENTER=16777221
};
KeyCode
Keyboard codes for characterless keys.
Definition: Events.h:17

To have a readable source code, you must never use the actual numeric values in this list, but only their code.

win = openWindow(500,500,"Ball");
// receiving mouse move events only with button pressed
cout << "Use your arrow keys. Press 'q' to quit." << endl;
int x=50, y=200, r=5;
int xt=x, yt=y;
fillCircle(x,y,r,GREEN);
while(true) {
int k = getKey();
if(k == 'q')
break;
bool update = true;
switch(k){
case KEY_UP: y-=5; break;
case KEY_DOWN: y+=5; break;
case KEY_LEFT: x-=5; break;
case KEY_RIGHT:x+=5; break;
default: update=false; break;
}
if(update) {
fillCircle(xt,yt,r,WHITE);
fillCircle(x,y,r,GREEN);
xt = x; yt = y;
}
}
const Color GREEN
Predefined color.
Definition: Color.h:311
int getKey(bool ignoreModifier=true)
Wait for key press in active window.
void fillCircle(int xc, int yc, int r, const AlphaColor &col, bool xorMode=false)
Filled Circle.
A keyboard controlled ball

3. Keyboard auto-repeat

When a key, other than Shift, Ctrl, or Alt, is maintained pressed longer than some minimal time (tunable by the system), auto-repeatition occurs. In that case, the sequence of events is the following:

  • EVT_KEY_ON
  • EVT_KEY_ON
  • ...
  • EVT_KEY_OFF

That is, it behaves as if the key was pressed multiple times, but only the final key release event is registered.