Tobii Interaction Library SDK

[Back to the SDK start page]

C# Sample Walkthrough

This section describes the typical workflow when using the C# Binding API of the Interaction Library SDK.

Let's assume the eye tracker is on the main screen and that the resolution is 2560x1440 pixels.

We want to tell the Interaction Library about 4 regions on screen (A, B, C and D in the picture below) for which we want to know when the user looks at them (or not). As our gaze enters and leaves them, the Interaction Library will emit "got focus" and "lost focus" events that we can react to in our client application.

Such a screen region is called an interactor in the Interaction Library API.

A screen with 4 corner interactors A, B, C and D:
2560
+-------+-------------------+-------+
| | | |
| A | 500 500 | B |
| | | |
+-------+ +-------+
| 500 500 |
| | 1440
| 500 500 |
+-------+ +-------+
| | | |
| C | 500 500 | D |
| | | |
+-------+------------------ +-------+

In the following, error checking is omitted for readability (most API functions return an Result value, where Result.Ok is the generic "success" value).

Make sure that the compiler can find the Interaction Library C# Binding assemblies, then create an instance of the Interaction Library implementation with InteractionLibFactory.CreateInteractionLib() . The returned instance implements the IDisposable pattern.

using System;
namespace CSharpSample
{
class Program
{
static void Main(string[] args)
{
// create the interaction library
Tobii.InteractionLib.FieldOfUse.Interactive);

Tell the Interaction Library our screen size with CoordinateTransformAddOrUpdateDisplayArea() and which origo our interactor coordinates are relative to with CoordinateTransformSetOriginOffset() . The latter is most useful if you want to use interactors with window local coordinates; simply update the offset as the window moves rather than all interactors.

const float width = 2560.0f;
const float height = 1440.0f;
const float offset = 0.0f;
intlib.CoordinateTransformAddOrUpdateDisplayArea(width, height);
intlib.CoordinateTransformSetOriginOffset(offset, offset);

Tell the Interaction Library where our interactors are located with AddOrUpdateInteractor() . This must be done between matching calls to BeginInteractorUpdates() and CommitInteractorUpdates() , as changes will be handled in safe and optimized batches. An interactor is identified by a unique client supplied ID. Also, interactors can overlap each other and be stacked in z-order but we leave them all at 0 in this sample.

const ulong idA = 0;
const ulong idB = 1;
const ulong idC = 2;
const ulong idD = 3;
const float size = 500.0f;
var rectA = new Tobii.InteractionLib.Rectangle( 0, 0, size, size);
var rectB = new Tobii.InteractionLib.Rectangle(width - size, 0, size, size);
var rectC = new Tobii.InteractionLib.Rectangle( 0, height - size, size, size);
var rectD = new Tobii.InteractionLib.Rectangle(width - size, height - size, size, size);
const float z = 0.0f;
intlib.BeginInteractorUpdates();
intlib.AddOrUpdateInteractor(idA, rectA, z);
intlib.AddOrUpdateInteractor(idB, rectB, z);
intlib.AddOrUpdateInteractor(idC, rectC, z);
intlib.AddOrUpdateInteractor(idD, rectD, z);
intlib.CommitInteractorUpdates();

To get a way of breaking out of the "update loop" (described further down), we track if the same interactor gets focus 3 times in a row, and if so exit the program. This is what we need for that tracking:

ulong focusId = ulong.MaxValue - 1;
uint focusCount = 0;

Tell the Interaction Library we want to get interactor focus events by subscribing to the GazeFocusEvent . When our gaze enters and leaves the interactors, the lambda callback function provided will be called by the Interaction Library and the event information is printed to standard output.

intlib.GazeFocusEvent += e =>
{
Console.WriteLine("Interactor: {0}, focused: {1}, timestamp: {2} us",
e.interactorId,
e.hasFocus,
e.timestamp_us);
if (e.hasFocus)
{
focusCount = focusId == e.interactorId ? focusCount + 1 : 1;
focusId = e.interactorId;
}
};

Tell the Interaction Library to continuously evaluate eye tracker gaze data and call any client event subscribers with WaitAndUpdate() . In the event that no device is connected, WaitAndUpdate() will attempt to find and connect to a tracker once per second. Since WaitAndUpdate() will often block the calling thread, you would normally put this loop on its own thread. WaitAndUpdate() is a convenience method that handles device connections, waiting for data and updating the Interaction Library to perform all calculation and trigger relevant callbacks all in one method. If you need granular control over updates and/or non-blocking calls use a suitable combination of the various other control methods available in the API.

Console.WriteLine("Starting interaction library update loop.");
const uint MaxFocusCount = 3;
while (focusCount < MaxFocusCount)
{
intlib.WaitAndUpdate();
}
Console.WriteLine("Interactor {0} got focused {1} times", focusId, focusCount);

Finally:

  • Compile and run the sample code. Its entirety can be found here: C# Binding Sample Complete Code
  • Observe how gaze focus "enter" and "leave" event information gets printed to standard output.
  • Focus the same interactor 3 times in a row to exit the sample program.