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:

/// All the info about a keyboard or mouse event...
struct Event {
EventType type;
IntPoint2 pix;
int button;
int key;
EventState state;
Window win;
int subWin;
};
/// ...

1. Types

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

/// - EVT_NONE : No event (thus, a timeout)
/// - EVT_BUT_ON : A mouse button has been pressed
/// - EVT_BUT_OFF : A mouse button has been released
/// - EVT_MOTION : The mouse has moved
/// - EVT_KEY_ON : A key has been pressed
/// - EVT_KEY_OFF : A key has been released
enum EventType {
EVT_NONE = 0,
EVT_BUT_ON = 2,
EVT_BUT_OFF = 3,
EVT_MOTION = 5,
EVT_KEY_ON,
EVT_KEY_OFF
};

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

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.

newEvent.png
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.

getEvent.png
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);

The parameters of getEvent are:

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);

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".

/// Menu
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);
/// ...

getEvent.gif
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
};

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

/// Ball
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;
}
}
/// ...

testEvent.gif
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:

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