-
Notifications
You must be signed in to change notification settings - Fork 1
Event Handling
Handling events is essential to having a game window that's not.. well.. frozen and unresponsive. Zenderer has a simple API in-place for taking care of system events such as keyboard presses, window events, and mouse state. The system is an object-oriented wrapper over GLFW's event handling API. The style itself takes slightly after Pygame's style of events, with separate structures based on the type of event generated.
Note: All of the code below assumes using namespace zen; using namespace evt;
for brevity's sake.
You can see the identifiers for the various events supported by Zenderer in the code here; they are also outlined below.
The structure used to trigger event sequences throughout Zenderer contains several components, each pertaining to different EventType
values. You can access keyboard event data through event_t::key
, mouse data through event_t::mouse
, and the type data through event_t::type
. For any given event, the relevant structure is guaranteed to contain valid data. For example, a KEY_DOWN
event ensures that the event_t::key
structure has valid information about the keyboard state.
The keyboard event structure (key_t
) contains information about events generated by pressing keys, letting them go, and holding them down. They are recognized by the various KEY_*
enumeration values.
-
KEY_DOWN
: This event is triggered when key on the keyboard is initially pressed. -
KEY_UP
: This event is triggered when a previously pressed key is released. -
KEY_HOLD
: This event is triggered after aKEY_DOWN
event if the key is held for a certain period of time. It is consistently triggered until the key is released. -
KEY_PRINTABLE
: This event is triggered simultaneously withKEY_DOWN
if the pressed key has an ASCII printable representation.
The keyboard event structure holds several data fields: information about various keyboard modifier keys (such as Shift, Alt, etc.), an identifier for the key that was pressed, a ASCII printable representation of the key, if possible, and the system-dependant scan code for the key.
If the character is not printable, event_t::key::symbol
is the NULL
terminator (\0
). A unique identifier for the key pressed can be access through event_t::key::key
, and a full list of the possible keys is in the Key
enumeration
Assuming a previously polled event structure, you could check for user attempts to quit the program though the keyboard like so:
// -snip-
// Event polling
// -snip-
// Assume "Evt" is of type "evt::event_t" and has been polled.
if (Evt.type == EventType::KEY_DOWN &&
Evt.key.key == Key::ESCAPE)
{
Quit();
}
The mouse event structure (mouse_t
) contains information about events generated by pressing buttons on the mouse, letting them go, and moving the mouse. There is support for up to 8 different mouse buttons. The first three are identified by LEFT
, MIDDLE
, and RIGHT
, respectively, but the remainder are identified by BUTTONi
where i
is in the range [4, 8]. They are recognized by the various MOUSE_*
enumeration values.
-
MOUSE_DOWN
: This event is triggered when a mouse button is initially pressed. -
MOUSE_UP
: This event is triggered when a previously pressed button is released. -
MOUSE_MOTION
: This event is triggered when the mouse is moved from its previous position.
The mouse event structure holds several data fields: information about various keyboard modifier keys (such as Shift, Alt, etc.), an identifier for the button that was pressed, the current position of the mouse, and whether or not the relevant button (if any) is pressed down or not.
Note: The mouse_t::down
and mouse_t::button
specifiers are not set to some "valid" value with MOUSE_MOTION
events. Rather, they are set to their defaults; namely, the button specifier is MouseButton::UNKNOWN
, and the mouse-down state is false
.
Assuming a previously polled event structure, you could output current mouse position like so:
// -snip-
// Event boilerplate as above.
// -snip-
if (Evt.type == EventType::MOUSE_MOTION)
{
std::cout << Evt.mouse.position << std::endl;
}
Sometimes it's not feasible to wait for events to trigger for the mouse, so it's possible to directly retrieve the state of the mouse. GetMousePosition()
returns the mouse position for the current window. Additionally, GetMouseState(MouseButton)
gives the state of a button at that moment in time, returning true
if the button is down, and false
if not.
Currently, the only window event that causes a trigger is the WINDOW_CLOSE
event, fired when the user clicks the 'X' on the window, or whatever other mechanism your supported OS uses for closing applications.
Note: If a WINDOW_CLOSE
event was triggered, this does NOT mean that the window will be closed. This is a note that says that the user wants the close the window, it's up to the client application to handle the event appropriately.
In example, a "quit-handling" loop such as this will not work as expected:
while (Window.IsOpen())
{
// -snip-
// Event boilerplate as above.
// -snip-
if (Evt.type == EventType::WINDOW_CLOSE) break;
}
You must actively do something with the event, such as call gfx::zWindow::Destroy()
.
There is a global singleton event state manager, known as zEventHandler
, which is accessible through zEventHandler::GetInstance()
. Every frame, you should call PollEvents()
on this instance to pump all of the latest events into the queue. After this, call PopEvent(event_t&)
repeatedly until there are no more events in the queue, handling them as would be appropriate for your application. The event queue actually performs as a stack, giving the latest events first (LIFO).
In code, the process would look something like this:
// Event structure.
event_t e;
// Shortcut to global instance.
zEventHandler& Evts = zEventHandler::GetInstance();
Evts.PollEvents();
while (Evts.PopEvent(e))
{
// Handle events somehow.
}
The various event callbacks are registered by gfx::zWindow
when one is created. Theoretically, multiple windows should registered and trigger separate callbacks, but this has most assuredly not been tested. Future implementations may add a window identifier to event_t
instances.