Navigation C API Pages Python bindings Applications

Input Events

Input events are somehow tied to the backends where they are stored in the event queue.

Possibly in contrast with other libraries there is not always 1:1 correspondence between input driver and backend graphics driver. That means that you can, for example, use Linux input events together with X Window without any problems. You can even write application that doesn’t draw any graphics at all and still use some of the input drivers. There are, of course, cases where input driver is created only together with graphics driver, this is the case for example for X Window backends or SDL backends.

The basic structure is roughly modeled after Linux kernel input API. The main difference is that events that belongs together are delivered together (the kernel input API sends one event for each value i.e. x or y coordinate and has sync event that finalizes the changes in the values).

Tip For example usage see input events example.

Event Structure Description

#include <gfxprim.h>
/* or */
#include <input/gp_event.h>

struct gp_event_pos_rel {
        int32_t rx;
        int32_t ry;
};

struct gp_event_pos_abs {
        uint32_t x, x_max; /* the x is between 0 and x_max */
        uint32_t y, y_max;
        uint32_t pressure, pressure_max;
};

struct gp_event_key {
        uint32_t key;
        char ascii;
};

struct gp_event_sys {
        uint32_t w, h;
};

typedef struct gp_event {
        /** enum gp_event_type */
        uint16_t type;
        /** enum gp_event_*_code */
        uint16_t code;
        union {
                /* generic integer value */
                int32_t val;
                /* key */
                struct gp_event_key key;
                /* position */
                struct gp_event_pos_rel rel;
                struct gp_event_pos_abs abs;
                /* system event */
                struct gp_event_sys sys;
                /* timer event */
                gp_timer *tmr;
        };

        /* event timestamp */
        struct timeval time;

        /*
         * Cursor position, position on screen accumulated
         * from all pointer devices
         */
        uint32_t cursor_x;
        uint32_t cursor_y;

        void *priv;
} gp_event;

The gp_event structure describes an input event (i.e. key was pressed/released, mouse was moved, window was resized by user).

enum gp_event_type {
        GP_EV_KEY, /* key/button press event */
        GP_EV_REL, /* relative event */
        GP_EV_ABS, /* absolute event */
        GP_EV_SYS, /* system events window close, resize... */
        GP_EV_TMR, /* timer expired event */
        GP_EV_MAX = GP_EV_TMR, /* maximum, greater values are free */
};

The event type determines high-level nature of the event.

  • Key events covers keyboard button presses, mouse buttons, etc.

  • Relative events covers mouse coordinates, mouse wheel, etc.

  • Absolute events covers touchscreens and tablets

  • System events are used for propagating window close and window resize events

  • Timer expired event are generated by when a timer has expired.

  • Values greater than GP_EV_MAX are free for user events

enum gp_event_key_code {
        GP_EV_KEY_UP,
        GP_EV_KEY_DOWN,
        GP_EV_KEY_REPEAT,
};

enum gp_event_rel_code {
        GP_EV_REL_POS,
        GP_EV_REL_WHEEL,
};

enum gp_event_abs_code {
        GP_EV_ABS_POS,
};

enum gp_event_sys_code {
        GP_EV_SYS_QUIT,
        GP_EV_SYS_RESIZE,
};

The event code specifies the event nature more closely, it has different meaning for each event type. The names are (hopefully) self explanatory.

The event value is a union that could hold different information. The right format of the data is known from the type and code. Some types of the events has no value at all.

Relative coordinates are used for GP_EV_REL_POS and absolute coordinates for GP_EV_ABS_POS.

The key event value is used for key-presses, additionally it holds the key value mapped to ASCII if conversion is applicable otherwise it’s set to zero. You should consult the header input/gp_event.h for the comprehensive list of key values.

Following image shows GFXprim key names without the GP_KEY_ prefix (Click for a higher resolution). So for example LEFTSHIFT on the image is GP_KEY_LEFT_SHIFT.

Figure 1. GFXprim key names without the GP_KEY_ prefix.
  • The system event is used with GP_EV_SYS_RESIZE and informs you of the new window size.

  • The value of timer event is simply pointer to the expired Timer.

The dev_id is not used at the moment and may be removed.

The timeval structure time holds time when the event was created (or received by GFXprim input driver).

The cursor_x and cursor_y holds current pointer coordinates. (All relative and absolute events are mixed together to compute current cursor position.)

The key_pressed is bitflag array of currently pressed keys which is useful for using keys as modificators. The array always holds state of the standard keyboard keys and mouse buttons.

Event API

#include <gfxprim.h>
/* or */
#include <input/gp_event.h>

void gp_event_dump(struct gp_event *ev);

The gp_event_dump dumps event in human-readable format into the stdout.

#include <gfxprim.h>
/* or */
#include <input/gp_event.h>

const char *gp_event_key_name(enum gp_event_key_value key);

Returns human-readable key name.

Timers

Input layer also implements priority queue (implemented using binary heap) to store multiple timer events. This part of the code is used in backends where you can simply add timer which gets processed automatically in the program main loop (while you call the backend Wait or Poll functions).

#include <gfxprim.h>
/* or */
#include <input/gp_timer.h>

typedef struct gp_timer {
        /* Heap pointers and number of sons */
        struct gp_timer *left;
        struct gp_timer *right;
        unsigned int sons;

        /* Expiration time */
        uint64_t expires;
        /*
         * If not zero return value from Callback is ignored and
         * timer is rescheduled each time it expires.
         */
        uint32_t period;

        /* Timer id, showed in debug messages */
        const char *id;

        /*
         * Timer Callback
         *
         * If non-zero is returned, the timer is rescheduled to expire
         * return value from now.
         */
        uint32_t (*callback)(struct gp_timer *self);
        void *priv;
} gp_timer;

#define GP_TIMER_DECLARE(name, expires, period, id, callback, priv) \
        ...

Timers are implemented as a simple structure with a callback, expiration, id string and internal heap pointers. The priority queue is described simply by the pointer to the top timer (soonest to expire).

The priv pointer is used to pass a user pointer to the callback function.

The number of timers in the queue is the number of sons of the top timer plus one.

The GP_TIMER_DECLARE() creates and initializes timer on the program stack. The name is the name of the declared timer structure and the rest of the variables corresponds to the structure members.

#include <gfxprim.h>
/* or */
#include <input/gp_timer.h>

void gp_timer_queue_dump(gp_timer *queue);

Prints the structure of binary heap into stdout, only for debugging.

#include <gfxprim.h>
/* or */
#include <input/gp_timer.h>

void gp_timer_queue_insert(gp_timer **queue, uint64_t now, gp_timer *timer);

Inserts timer into the timer priority queue. The timer is scheduled to expire at now + timer->expire.

#include <gfxprim.h>
/* or */
#include <input/gp_timer.h>

void gp_timer_queue_remove(gp_timer **queue, gp_timer *timer);

Removes timer from the queue.

If timer is not found in the queue nothing is done but warning is printed.

Runs in O(n) time (the insert and process runs in O(nlog(n))).

#include <gfxprim.h>
/* or */
#include <input/gp_timer.h>

int gp_timer_queue_process(gp_timer **queue, uint64_t now);

Processes all expired timers (all timers with timer->expires <= now are processed).

Recurrent timers and timers that returned non-zero from callback are reinserted into the queue with new expiration time.

Returns number of timers processed.

#include <gfxprim.h>
/* or */
#include <input/gp_timer.h>

unsigned int gp_timer_queue_size(gp_timer *queue);

Returns number of timers in the queue.

TimerStamp

Timestamp provides fast monotonously increasing timestamps in milliseconds.

Timestamp is used together with timers.

#include <gfxprim.h>
/* or */
#include <input/gp_time_stamp.h>

uint64_t gp_time_stamp(void);

Returns timestamp (i.e. time elapsed since some point) in milliseconds.