This is example 16. This example demonstrates the following:
-
Processing online fixation events
This example is based on
example 10. This example adds an
onFixationEvent()
event handler function to print fixation start, end and
update events.
Source code
Source file: example16.c
Initialization
In the eyevec_create_thread()
function in the initialization part we provide
a fixation event callback function.
int main(void)
{
.
.
EyeVecResult err = eyevec_create_thread(eyevec,
onModeChange,
NULL, // onDisplayData,
NULL, // onEyeData,
NULL, // onBlinkEvent,
NULL, // onSaccadeEvent,
onFixationEvent, (1)
NULL, // onTestItemEvent,
&clientdata);
printError("eyevec_create_thread()", err);
if (err) return EXIT_FAILURE;
.
.
1 | Callback function for fixation start, end and update events. |
processInput()
The following single character commands are implemented here:
q
: quit
o
: open/close device
u
: show/hide control window
x
: toggle show gui on setup mode
X
: toggle show gui on data mode
i
: enter idle mode
s
: enter setup mode
z
: enter data mode
r
: start/stop recording
m
: toggle show mode-change events
g
: toggle gaze analysis events
When you press g
then eyevec_set_gaze_events_enabled()
will be called
to toggle (enable or disable) sending gaze analysis events. The default is
not sending them.
static int processInput(EyeVec* eyevec, ClientData* clientdata, int ch)
{
.
.
.
else if (ch == 'g') {
uint32_t enabled = eyevec_get_gaze_events_enabled(eyevec); (1)
if ((enabled & EYEVEC_ENABLE_SEND_WHILE_IN_RECORDING_MODE) != 0) {
err = eyevec_set_gaze_events_enabled(eyevec,
EYEVEC_ENABLE_SEND_WHILE_IN_RECORDING_MODE, 0); (2)
printError("eyevec_set_gaze_events_enabled(0x1, 0)", err);
}
else {
err = eyevec_set_gaze_events_enabled(eyevec,
0, EYEVEC_ENABLE_SEND_WHILE_IN_RECORDING_MODE); (3)
printError("eyevec_set_gaze_events_enabled(0, 0x1)", err);
}
}
.
.
.
}
1 | Check if gaze events are currently enabled. |
2 | Disable sending gaze events. |
3 | Enable sending gaze events. |
If for some reason you need to receive gaze events not only when in recording mode, but also when in data mode and drift-check mode (the green circles in the eye-tracker mode state diagram), then call eyevec_set_gaze_events_enabled().
To try this add the following to processInput()
:
else if (ch == 'G') {
uint32_t enabled = eyevec_get_gaze_events_enabled(eyevec);
if ((enabled & EYEVEC_ENABLE_SEND_WHILE_IN_DATA_MODE) != 0) {
err = eyevec_set_gaze_events_enabled(eyevec,
EYEVEC_ENABLE_SEND_WHILE_IN_DATA_MODE, 0);
printError("eyevec_set_gaze_events_enabled(0x2, 0)", err);
}
else {
err = eyevec_set_gaze_events_enabled(eyevec,
0, EYEVEC_ENABLE_SEND_WHILE_IN_DATA_MODE);
printError("eyevec_set_gaze_events_enabled(0, 0x2)", err);
}
}
onFixationEvent()
In the onFixationEvent()
event handler function we call onFixationStart()
,
onFixationEnd()
or onFixationUpdate()
depending on the flag
parameter
provided to the onFixationEvent()
function.
static int onFixationEvent(const EyeVec* eyevec, int64_t eventtime,
const EyeVecFixationEventData* fixationdata, int flag, void* cldata)
{
const ClientData* clientdata = (const ClientData*)cldata;
if (clientdata == NULL) return 0;
if (flag == 0)
return onFixationStart(eyevec, eventtime, fixationdata, clientdata); (1)
if (flag > 0)
return onFixationEnd(eyevec, eventtime, fixationdata, clientdata); (2)
return onFixationUpdate(eyevec, eventtime, fixationdata, clientdata); (3)
}
1 | Call onFixationStart() with provided fixation data. |
2 | Call onFixationEnd() with provided fixation data. |
3 | Call onFixationUpdate() with provided fixation data. |
onFixationStart()
This function prints the relevant EyeVecFixationEventData attributes (excluding variances) defined for the fixation start event.
static int onFixationStart(const EyeVec* eyevec, int64_t eventtime,
const EyeVecFixationEventData* fixationdata, const ClientData* clientdata)
{
(void)eyevec;
if (clientdata->showgazeevents) {
printf("onFixationStart:\n");
printf(" eventtime: %" PRId64 "\n",
eventtime);
printf(" side: %s\n",
side_string(fixationdata->side));
printf(" starttime: %" PRId64 "\n",
fixationdata->starttime);
printf(" gaze_start: %.3f, %.3f\n",
(double)fixationdata->gaze_start.x,
(double)fixationdata->gaze_start.y);
printf(" pupil_start: %.3f\n",
(double)fixationdata->pupil_start);
}
return 0;
}
onFixationEnd()
This function prints the relevant EyeVecFixationEventData attributes (excluding variances) defined for the fixation end event.
static int onFixationEnd(const EyeVec* eyevec, int64_t eventtime,
const EyeVecFixationEventData* fixationdata, const ClientData* clientdata)
{
(void)eyevec;
if (clientdata->showgazeevents) {
printf("onFixationEnd:\n");
printf(" eventtime: %" PRId64 "\n",
eventtime);
printf(" side: %s\n",
side_string(fixationdata->side));
printf(" starttime: %" PRId64 "\n",
fixationdata->starttime);
if (fixationdata->endtime >= 0) {
printf(" duration: %d\n",
(int)(fixationdata->endtime - fixationdata->starttime));
}
printf(" gaze_end: %.3f, %.3f\n",
(double)fixationdata->gaze_end.x,
(double)fixationdata->gaze_end.y);
printf(" pupil_end: %.3f\n",
(double)fixationdata->pupil_end);
printf(" gaze_avg: %.3f, %.3f\n",
(double)fixationdata->gaze_avg.x,
(double)fixationdata->gaze_avg.y);
printf(" pupil_avg: %.3f\n",
(double)fixationdata->pupil_avg);
}
return 0;
}
onFixationUpdate()
This function prints the relevant EyeVecFixationEventData attributes (excluding variances) defined for the fixation update event.
static int onFixationUpdate(const EyeVec* eyevec, int64_t eventtime,
const EyeVecFixationEventData* fixationdata, const ClientData* clientdata)
{
(void)eyevec;
if (clientdata->showgazeevents) {
printf("onFixationUpdate:\n");
printf(" eventtime: %" PRId64 "\n",
eventtime);
printf(" side: %s\n",
side_string(fixationdata->side));
printf(" starttime: %" PRId64 "\n",
fixationdata->starttime);
printf(" duration: %d\n",
(int)(fixationdata->endtime - fixationdata->starttime));
printf(" gaze_end: %.3f, %.3f\n",
(double)fixationdata->gaze_end.x,
(double)fixationdata->gaze_end.y);
printf(" pupil_end: %.3f\n",
(double)fixationdata->pupil_end);
printf(" gaze_avg: %.3f, %.3f\n",
(double)fixationdata->gaze_avg.x,
(double)fixationdata->gaze_avg.y);
printf(" pupil_avg: %.3f\n",
(double)fixationdata->pupil_avg);
}
return 0;
}
Running
After a succesful build run the program:
-
Press
o
to calleyevec_open()
. Eye-tracker should go from off mode to idle mode. -
Press
z
to calleyevec_enter_data_mode()
. Eye-tracker should go from idle mode to data mode. Note, we’re skipping setup and calibration here; still make sure the eye-tracker can see your eyes. -
Press
g
to calleyevec_set_gaze_event_enabled(0, EYEVEC_ENABLE_SEND_WHILE_IN_RECORDING_MODE)
. -
Press
r
to calleyevec_start_recording()
. Eye-tracker should go from data mode to recording mode. Fixation events should be printed. -
Press
r
to calleyevec_stop_recording()
. Eye-tracker should go from recording mode to data mode. No more fixation events will be printed. -
Press
q
to quit.
Output might look like this (empty lines added for clarity):
eyevec_create_thread(): OK
eyevec_initialize(): OK
Type q to quit, ? for help.
[o]
onModeChange:
eventtime: 1750689363293557
eyevec_open(): OK
oldmode: TRACKER_MODE_OFF
newmode: TRACKER_MODE_IDLE
[z]
eyevec_enter_data_mode(): OK
onModeChange:
eventtime: 1750689367838031
oldmode: TRACKER_MODE_IDLE
newmode: TRACKER_MODE_DATA
[g]
eyevec_set_gaze_event_enabled(0, 0x1): OK
[r]
eyevec_start_recording(): OK
onModeChange:
eventtime: 1750689402060288
oldmode: TRACKER_MODE_DATA
newmode: TRACKER_MODE_RECORDING
onFixationEnd:
eventtime: 1750689402868187
side: RIGHT
starttime: 1750689398107252
duration: 4760935
gaze_end: 0.077, 0.913
pupil_end: 4.353
gaze_avg: 0.087, 0.879
pupil_avg: 4.266
onFixationEnd:
eventtime: 1750689402868187
side: LEFT
starttime: 1750689398107252
duration: 4760935
gaze_end: 0.052, 0.927
pupil_end: 4.483
gaze_avg: 0.068, 0.884
pupil_avg: 4.381
onFixationEnd:
eventtime: 1750689402868187
side: MEAN
starttime: 1750689398107252
duration: 4760935
gaze_end: 0.064, 0.920
pupil_end: 4.418
gaze_avg: 0.077, 0.882
pupil_avg: 4.323
onFixationStart:
eventtime: 1750689402940200
side: RIGHT
starttime: 1750689402940200
gaze_start: 0.356, 0.674
pupil_start: 4.298
onFixationStart:
eventtime: 1750689402942200
side: LEFT
starttime: 1750689402942200
gaze_start: 0.361, 0.678
pupil_start: 4.559
onFixationStart:
eventtime: 1750689402942200
side: MEAN
starttime: 1750689402942200
gaze_start: 0.358, 0.676
pupil_start: 4.431
onFixationEnd:
eventtime: 1750689403002211
side: RIGHT
starttime: 1750689402940200
duration: 62011
gaze_end: 0.356, 0.677
pupil_end: 4.317
gaze_avg: 0.358, 0.672
pupil_avg: 4.311
onFixationEnd:
eventtime: 1750689403002211
side: LEFT
starttime: 1750689402942200
duration: 60011
gaze_end: 0.357, 0.679
pupil_end: 4.566
gaze_avg: 0.359, 0.676
pupil_avg: 4.571
onFixationEnd:
eventtime: 1750689403002211
side: MEAN
starttime: 1750689402942200
duration: 60011
gaze_end: 0.356, 0.678
pupil_end: 4.442
gaze_avg: 0.358, 0.674
pupil_avg: 4.441
.
.
.
[q]
eyevec_cleanup(): OK
eyevec_destroy_thread(): OK