Leap Motion C API  4.1.0
The API to the LeapC library.
Callback Example

This example demonstrates the basic usage of the LeapC API to get tracking data.

Sample.c

Sample.c is an example client application that consumes the tracking data – in this case, by simply printing basic data to stdout.

Sample.C defines three callback functions, one each for OnConnect, OnDevice, and OnFrame. Each of these callback functions are called by ExampleConnection when the LeapC library returns the associated event. The OnConnect callback doesn't have any associated data, but you can use the event to initialize parts of your application that depend on a connection. OnDevice provides the LEAP_DEVICE_INFO struct describing the connected device. OnFrame provides the LEAP_TRACKING_EVENT struct that contains all the tracking data (except images) for the latest frame.

Callback functions are invoked directly from the ExampleConnection thread created to service the LeapC message pump. This can be problematic for applications that use UI or graphics libraries that must be called on a particular thread. For such applications, you must implement a means for one thread to hand of data to the other. The best approach is platform dependent. For example, the Windows API provides a SynchronizationContext construct that can be used in some cases. The Polling Example demonstrates an approach in which the latest data objects are cached by the servicing thread and the application can access these objects when ready. The Interpolated Frames Example demonstrates another way around the problem for tracking data, which works because interpolated frames are returned directly to the calling function rather than passing throught the LeapC message pump.

1 #undef __cplusplus
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include "LeapC.h"
6 #include "ExampleConnection.h"
7 
8 static LEAP_CONNECTION* connectionHandle;
9 
10 /** Callback for when the connection opens. */
11 static void OnConnect(){
12  printf("Connected.\n");
13 }
14 
15 /** Callback for when a device is found. */
16 static void OnDevice(const LEAP_DEVICE_INFO *props){
17  printf("Found device %s.\n", props->serial);
18 }
19 
20 /** Callback for when a frame of tracking data is available. */
21 static void OnFrame(const LEAP_TRACKING_EVENT *frame){
22  printf("Frame %lli with %i hands.\n", (long long int)frame->info.frame_id, frame->nHands);
23 
24  for(uint32_t h = 0; h < frame->nHands; h++){
25  LEAP_HAND* hand = &frame->pHands[h];
26  printf(" Hand id %i is a %s hand with position (%f, %f, %f).\n",
27  hand->id,
28  (hand->type == eLeapHandType_Left ? "left" : "right"),
29  hand->palm.position.x,
30  hand->palm.position.y,
31  hand->palm.position.z);
32  }
33 }
34 
35 static void OnImage(const LEAP_IMAGE_EVENT *image){
36  printf("Image %lli => Left: %d x %d (bpp=%d), Right: %d x %d (bpp=%d)\n",
37  (long long int)image->info.frame_id,
38  image->image[0].properties.width,image->image[0].properties.height,image->image[0].properties.bpp*8,
39  image->image[1].properties.width,image->image[1].properties.height,image->image[1].properties.bpp*8);
40 }
41 
42 static void OnLogMessage(const eLeapLogSeverity severity, const int64_t timestamp,
43  const char* message) {
44  const char* severity_str;
45  switch(severity) {
46  case eLeapLogSeverity_Critical:
47  severity_str = "Critical";
48  break;
49  case eLeapLogSeverity_Warning:
50  severity_str = "Warning";
51  break;
52  case eLeapLogSeverity_Information:
53  severity_str = "Info";
54  break;
55  default:
56  severity_str = "";
57  break;
58  }
59  printf("[%s][%lli] %s\n", severity_str, (long long int)timestamp, message);
60 }
61 
62 static void* allocate(uint32_t size, eLeapAllocatorType typeHint, void* state) {
63  void* ptr = malloc(size);
64  return ptr;
65 }
66 
67 static void deallocate(void* ptr, void* state) {
68  if (!ptr)
69  return;
70  free(ptr);
71 }
72 
73 void OnPointMappingChange(const LEAP_POINT_MAPPING_CHANGE_EVENT *change){
74  if (!connectionHandle)
75  return;
76 
77  uint64_t size = 0;
78  if (LeapGetPointMappingSize(*connectionHandle, &size) != eLeapRS_Success || !size)
79  return;
80 
81  LEAP_POINT_MAPPING* pointMapping = (LEAP_POINT_MAPPING*)malloc(size);
82  if (!pointMapping)
83  return;
84 
85  if (LeapGetPointMapping(*connectionHandle, pointMapping, &size) == eLeapRS_Success &&
86  pointMapping->nPoints > 0) {
87  printf("Managing %u points as of frame %lld at %lld\n", pointMapping->nPoints, (long long int)pointMapping->frame_id, (long long int)pointMapping->timestamp);
88  }
89  free(pointMapping);
90 }
91 
92 void OnHeadPose(const LEAP_HEAD_POSE_EVENT *event) {
93  printf("Head pose:\n");
94  printf(" Head position (%f, %f, %f).\n",
95  event->head_position.x,
96  event->head_position.y,
97  event->head_position.z);
98  printf(" Head orientation (%f, %f, %f, %f).\n",
99  event->head_orientation.w,
100  event->head_orientation.x,
101  event->head_orientation.y,
102  event->head_orientation.z);
103  }
104 
105 int main(int argc, char** argv) {
106  //Set callback function pointers
107  ConnectionCallbacks.on_connection = &OnConnect;
108  ConnectionCallbacks.on_device_found = &OnDevice;
109  ConnectionCallbacks.on_frame = &OnFrame;
110  ConnectionCallbacks.on_image = &OnImage;
111  ConnectionCallbacks.on_point_mapping_change = &OnPointMappingChange;
112  ConnectionCallbacks.on_log_message = &OnLogMessage;
113  ConnectionCallbacks.on_head_pose = &OnHeadPose;
114 
115  connectionHandle = OpenConnection();
116  {
117  LEAP_ALLOCATOR allocator = { allocate, deallocate, NULL };
118  LeapSetAllocator(*connectionHandle, &allocator);
119  }
120  LeapSetPolicyFlags(*connectionHandle, eLeapPolicyFlag_Images | eLeapPolicyFlag_MapPoints, 0);
121 
122  printf("Press Enter to exit program.\n");
123  getchar();
124 
125  DestroyConnection();
126 
127  return 0;
128 }
129 //End-of-Sample.c

ExampleConnection.h

ExampleConnection.h defines the public functions that should be called by applications. Any other functions should be considered private.

Typedefs and function pointers for the supported callback functions are also defined here. Sample.c only uses three of the callbacks, but the complete set are defined in this example.

1 #ifndef ExampleConnection_h
2 #define ExampleConnection_h
3 
4 #include "LeapC.h"
5 
6 /* Client functions */
7 LEAP_CONNECTION* OpenConnection();
8 void CloseConnection();
9 void DestroyConnection();
10 LEAP_TRACKING_EVENT* GetFrame(); //Used in polling example
11 LEAP_DEVICE_INFO* GetDeviceProperties(); //Used in polling example
12 const char* ResultString(eLeapRS r);
13 
14 /* State */
15 extern bool IsConnected;
16 
17 /* Callback function pointers */
18 typedef void (*connection_callback) ();
19 typedef void (*device_callback) (const LEAP_DEVICE_INFO *device);
20 typedef void (*device_lost_callback) ();
21 typedef void (*device_failure_callback) (const eLeapDeviceStatus failure_code,
22  const LEAP_DEVICE failed_device);
23 typedef void (*policy_callback) (const uint32_t current_policies);
24 typedef void (*tracking_callback) (const LEAP_TRACKING_EVENT *tracking_event);
25 typedef void (*log_callback) (const eLeapLogSeverity severity,
26  const int64_t timestamp,
27  const char* message);
28 typedef void (*config_change_callback) (const uint32_t requestID, const bool success);
29 typedef void (*config_response_callback)(const uint32_t requestID, LEAP_VARIANT value);
30 typedef void (*image_callback) (const LEAP_IMAGE_EVENT *image_event);
31 typedef void (*point_mapping_change_callback)(const LEAP_POINT_MAPPING_CHANGE_EVENT *point_mapping_change_event);
32 typedef void (*head_pose_callback)(const LEAP_HEAD_POSE_EVENT *head_pose_event);
33 
34 struct Callbacks{
35  connection_callback on_connection;
36  connection_callback on_connection_lost;
37  device_callback on_device_found;
38  device_lost_callback on_device_lost;
39  device_failure_callback on_device_failure;
40  policy_callback on_policy;
41  tracking_callback on_frame;
42  log_callback on_log_message;
43  config_change_callback on_config_change;
44  config_response_callback on_config_response;
45  image_callback on_image;
46  point_mapping_change_callback on_point_mapping_change;
47  head_pose_callback on_head_pose;
48 };
49 extern struct Callbacks ConnectionCallbacks;
50 extern void millisleep(int milliseconds);
51 #endif /* ExampleConnection_h */

ExampleConnection.c

ExampleConnection.c demonstrates how to service the LeapC message pump. LeapC gathers events from the Leap Motion service and places them in a queues. Client applications must service this queue by calling LeapPollConnection(). A good way to do this is in a dedicated thread – otherwise servicing the message pump may block the application thread, or conversely, fall behind and lose event messages.

The client application calls the OpenConnection() function in ExampleConnection, which calls LeapC functions to establish the connection with the Leap Motion service. If the connection is successful, a new thread is started to run serviceMessageLoop().

ServiceMessageLoop() calls the LeapC LeapPollConnection() in a tight loop. When tracking frames are being produced, the average time elapsed per loop iteration will equal the service frame rate (about 9ms). A separate handler function is defined for each possible LeapC event, which, in turn, invoke the relevant callback funtions, if the main application has provided one.

Note that ExampleConnection is intended as a simple demonstration only – not as production-ready code.

1 #include "ExampleConnection.h"
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #if defined(_MSC_VER)
6  #include <Windows.h>
7  #include <process.h>
8  #define LockMutex EnterCriticalSection
9  #define UnlockMutex LeaveCriticalSection
10 #else
11  #include <unistd.h>
12  #include <pthread.h>
13  #define LockMutex pthread_mutex_lock
14  #define UnlockMutex pthread_mutex_unlock
15 #endif
16 
17 
18 //Forward declarations
19 #if defined(_MSC_VER)
20 static void serviceMessageLoop(void * unused);
21 #else
22 static void* serviceMessageLoop(void * unused);
23 #endif
24 static void setFrame(const LEAP_TRACKING_EVENT *frame);
25 static void setDevice(const LEAP_DEVICE_INFO *deviceProps);
26 
27 //External state
28 bool IsConnected = false;
29 
30 //Internal state
31 static volatile bool _isRunning = false;
32 static LEAP_CONNECTION connectionHandle = NULL;
33 static LEAP_TRACKING_EVENT *lastFrame = NULL;
34 static LEAP_DEVICE_INFO *lastDevice = NULL;
35 
36 //Callback function pointers
37 struct Callbacks ConnectionCallbacks;
38 
39 //Threading variables
40 #if defined(_MSC_VER)
41 static HANDLE pollingThread;
42 static CRITICAL_SECTION dataLock;
43 #else
44 static pthread_t pollingThread;
45 static pthread_mutex_t dataLock;
46 #endif
47 
48 /**
49  * Creates the connection handle and opens a connection to the Leap Motion
50  * service. On success, creates a thread to service the LeapC message pump.
51  */
52 LEAP_CONNECTION* OpenConnection(){
53  if(_isRunning){
54  return &connectionHandle;
55  }
56  if(connectionHandle || LeapCreateConnection(NULL, &connectionHandle) == eLeapRS_Success){
57  eLeapRS result = LeapOpenConnection(connectionHandle);
58  if(result == eLeapRS_Success){
59  _isRunning = true;
60 #if defined(_MSC_VER)
61  InitializeCriticalSection(&dataLock);
62  pollingThread = (HANDLE)_beginthread(serviceMessageLoop, 0, NULL);
63 #else
64  pthread_create(&pollingThread, NULL, serviceMessageLoop, NULL);
65 #endif
66  }
67  }
68  return &connectionHandle;
69 }
70 
71 void CloseConnection(){
72  if(!_isRunning){
73  return;
74  }
75  _isRunning = false;
76  LeapCloseConnection(connectionHandle);
77 #if defined(_MSC_VER)
78  WaitForSingleObject(pollingThread, INFINITE);
79  CloseHandle(pollingThread);
80 #else
81  pthread_join(pollingThread, NULL);
82 #endif
83 }
84 
85 void DestroyConnection(){
86  CloseConnection();
87  LeapDestroyConnection(connectionHandle);
88 }
89 
90 
91 /** Close the connection and let message thread function end. */
92 void CloseConnectionHandle(LEAP_CONNECTION* connectionHandle){
93  LeapDestroyConnection(*connectionHandle);
94  _isRunning = false;
95 }
96 
97 /** Called by serviceMessageLoop() when a connection event is returned by LeapPollConnection(). */
98 static void handleConnectionEvent(const LEAP_CONNECTION_EVENT *connection_event){
99  IsConnected = true;
100  if(ConnectionCallbacks.on_connection){
101  ConnectionCallbacks.on_connection();
102  }
103 }
104 
105 /** Called by serviceMessageLoop() when a connection lost event is returned by LeapPollConnection(). */
106 static void handleConnectionLostEvent(const LEAP_CONNECTION_LOST_EVENT *connection_lost_event){
107  IsConnected = false;
108  if(ConnectionCallbacks.on_connection_lost){
109  ConnectionCallbacks.on_connection_lost();
110  }
111 }
112 
113 /**
114  * Called by serviceMessageLoop() when a device event is returned by LeapPollConnection()
115  * Demonstrates how to access device properties.
116  */
117 static void handleDeviceEvent(const LEAP_DEVICE_EVENT *device_event){
118  LEAP_DEVICE deviceHandle;
119  //Open device using LEAP_DEVICE_REF from event struct.
120  eLeapRS result = LeapOpenDevice(device_event->device, &deviceHandle);
121  if(result != eLeapRS_Success){
122  printf("Could not open device %s.\n", ResultString(result));
123  return;
124  }
125 
126  //Create a struct to hold the device properties, we have to provide a buffer for the serial string
127  LEAP_DEVICE_INFO deviceProperties = { sizeof(deviceProperties) };
128  // Start with a length of 1 (pretending we don't know a priori what the length is).
129  // Currently device serial numbers are all the same length, but that could change in the future
130  deviceProperties.serial_length = 1;
131  deviceProperties.serial = malloc(deviceProperties.serial_length);
132  //This will fail since the serial buffer is only 1 character long
133  // But deviceProperties is updated to contain the required buffer length
134  result = LeapGetDeviceInfo(deviceHandle, &deviceProperties);
135  if(result == eLeapRS_InsufficientBuffer){
136  //try again with correct buffer size
137  deviceProperties.serial = realloc(deviceProperties.serial, deviceProperties.serial_length);
138  result = LeapGetDeviceInfo(deviceHandle, &deviceProperties);
139  if(result != eLeapRS_Success){
140  printf("Failed to get device info %s.\n", ResultString(result));
141  free(deviceProperties.serial);
142  return;
143  }
144  }
145  setDevice(&deviceProperties);
146  if(ConnectionCallbacks.on_device_found){
147  ConnectionCallbacks.on_device_found(&deviceProperties);
148  }
149 
150  free(deviceProperties.serial);
151  LeapCloseDevice(deviceHandle);
152 }
153 
154 /** Called by serviceMessageLoop() when a device lost event is returned by LeapPollConnection(). */
155 static void handleDeviceLostEvent(const LEAP_DEVICE_EVENT *device_event){
156  if(ConnectionCallbacks.on_device_lost){
157  ConnectionCallbacks.on_device_lost();
158  }
159 }
160 
161 /** Called by serviceMessageLoop() when a device failure event is returned by LeapPollConnection(). */
162 static void handleDeviceFailureEvent(const LEAP_DEVICE_FAILURE_EVENT *device_failure_event){
163  if(ConnectionCallbacks.on_device_failure){
164  ConnectionCallbacks.on_device_failure(device_failure_event->status, device_failure_event->hDevice);
165  }
166 }
167 
168 /** Called by serviceMessageLoop() when a tracking event is returned by LeapPollConnection(). */
169 static void handleTrackingEvent(const LEAP_TRACKING_EVENT *tracking_event){
170  setFrame(tracking_event); //support polling tracking data from different thread
171  if(ConnectionCallbacks.on_frame){
172  ConnectionCallbacks.on_frame(tracking_event);
173  }
174 }
175 
176 /** Called by serviceMessageLoop() when a log event is returned by LeapPollConnection(). */
177 static void handleLogEvent(const LEAP_LOG_EVENT *log_event){
178  if(ConnectionCallbacks.on_log_message){
179  ConnectionCallbacks.on_log_message(log_event->severity, log_event->timestamp, log_event->message);
180  }
181 }
182 
183 /** Called by serviceMessageLoop() when a log event is returned by LeapPollConnection(). */
184 static void handleLogEvents(const LEAP_LOG_EVENTS *log_events){
185  if(ConnectionCallbacks.on_log_message){
186  for (int i = 0; i < (int)(log_events->nEvents); i++) {
187  const LEAP_LOG_EVENT* log_event = &log_events->events[i];
188  ConnectionCallbacks.on_log_message(log_event->severity, log_event->timestamp, log_event->message);
189  }
190  }
191 }
192 
193 /** Called by serviceMessageLoop() when a policy event is returned by LeapPollConnection(). */
194 static void handlePolicyEvent(const LEAP_POLICY_EVENT *policy_event){
195  if(ConnectionCallbacks.on_policy){
196  ConnectionCallbacks.on_policy(policy_event->current_policy);
197  }
198 }
199 
200 /** Called by serviceMessageLoop() when a config change event is returned by LeapPollConnection(). */
201 static void handleConfigChangeEvent(const LEAP_CONFIG_CHANGE_EVENT *config_change_event){
202  if(ConnectionCallbacks.on_config_change){
203  ConnectionCallbacks.on_config_change(config_change_event->requestID, config_change_event->status);
204  }
205 }
206 
207 /** Called by serviceMessageLoop() when a config response event is returned by LeapPollConnection(). */
208 static void handleConfigResponseEvent(const LEAP_CONFIG_RESPONSE_EVENT *config_response_event){
209  if(ConnectionCallbacks.on_config_response){
210  ConnectionCallbacks.on_config_response(config_response_event->requestID, config_response_event->value);
211  }
212 }
213 
214 /** Called by serviceMessageLoop() when a point mapping change event is returned by LeapPollConnection(). */
215 static void handleImageEvent(const LEAP_IMAGE_EVENT *image_event) {
216  if(ConnectionCallbacks.on_image){
217  ConnectionCallbacks.on_image(image_event);
218  }
219 }
220 
221 /** Called by serviceMessageLoop() when a point mapping change event is returned by LeapPollConnection(). */
222 static void handlePointMappingChangeEvent(const LEAP_POINT_MAPPING_CHANGE_EVENT *point_mapping_change_event) {
223  if(ConnectionCallbacks.on_point_mapping_change){
224  ConnectionCallbacks.on_point_mapping_change(point_mapping_change_event);
225  }
226 }
227 
228 /** Called by serviceMessageLoop() when a point mapping change event is returned by LeapPollConnection(). */
229 static void handleHeadPoseEvent(const LEAP_HEAD_POSE_EVENT *head_pose_event) {
230  if(ConnectionCallbacks.on_head_pose){
231  ConnectionCallbacks.on_head_pose(head_pose_event);
232  }
233 }
234 
235 /**
236  * Services the LeapC message pump by calling LeapPollConnection().
237  * The average polling time is determined by the framerate of the Leap Motion service.
238  */
239 #if defined(_MSC_VER)
240 static void serviceMessageLoop(void * unused){
241 #else
242 static void* serviceMessageLoop(void * unused){
243 #endif
244  eLeapRS result;
245  LEAP_CONNECTION_MESSAGE msg;
246  while(_isRunning){
247  unsigned int timeout = 1000;
248  result = LeapPollConnection(connectionHandle, timeout, &msg);
249 
250  if(result != eLeapRS_Success){
251  printf("LeapC PollConnection call was %s.\n", ResultString(result));
252  continue;
253  }
254 
255  switch (msg.type){
256  case eLeapEventType_Connection:
257  handleConnectionEvent(msg.connection_event);
258  break;
259  case eLeapEventType_ConnectionLost:
260  handleConnectionLostEvent(msg.connection_lost_event);
261  break;
262  case eLeapEventType_Device:
263  handleDeviceEvent(msg.device_event);
264  break;
265  case eLeapEventType_DeviceLost:
266  handleDeviceLostEvent(msg.device_event);
267  break;
268  case eLeapEventType_DeviceFailure:
269  handleDeviceFailureEvent(msg.device_failure_event);
270  break;
271  case eLeapEventType_Tracking:
272  handleTrackingEvent(msg.tracking_event);
273  break;
274  case eLeapEventType_ImageComplete:
275  // Ignore
276  break;
277  case eLeapEventType_ImageRequestError:
278  // Ignore
279  break;
280  case eLeapEventType_LogEvent:
281  handleLogEvent(msg.log_event);
282  break;
283  case eLeapEventType_Policy:
284  handlePolicyEvent(msg.policy_event);
285  break;
286  case eLeapEventType_ConfigChange:
287  handleConfigChangeEvent(msg.config_change_event);
288  break;
289  case eLeapEventType_ConfigResponse:
290  handleConfigResponseEvent(msg.config_response_event);
291  break;
292  case eLeapEventType_Image:
293  handleImageEvent(msg.image_event);
294  break;
295  case eLeapEventType_PointMappingChange:
296  handlePointMappingChangeEvent(msg.point_mapping_change_event);
297  break;
298  case eLeapEventType_LogEvents:
299  handleLogEvents(msg.log_events);
300  break;
301  case eLeapEventType_HeadPose:
302  handleHeadPoseEvent(msg.head_pose_event);
303  break;
304  default:
305  //discard unknown message types
306  printf("Unhandled message type %i.\n", msg.type);
307  } //switch on msg.type
308  }
309 #if !defined(_MSC_VER)
310  return NULL;
311 #endif
312 }
313 
314 /* Used in Polling Example: */
315 
316 /**
317  * Caches the newest frame by copying the tracking event struct returned by
318  * LeapC.
319  */
320 void setFrame(const LEAP_TRACKING_EVENT *frame){
321  LockMutex(&dataLock);
322  if(!lastFrame) lastFrame = malloc(sizeof(*frame));
323  *lastFrame = *frame;
324  UnlockMutex(&dataLock);
325 }
326 
327 /** Returns a pointer to the cached tracking frame. */
328 LEAP_TRACKING_EVENT* GetFrame(){
329  LEAP_TRACKING_EVENT *currentFrame;
330 
331  LockMutex(&dataLock);
332  currentFrame = lastFrame;
333  UnlockMutex(&dataLock);
334 
335  return currentFrame;
336 }
337 
338 /**
339  * Caches the last device found by copying the device info struct returned by
340  * LeapC.
341  */
342 static void setDevice(const LEAP_DEVICE_INFO *deviceProps){
343  LockMutex(&dataLock);
344  if(lastDevice){
345  free(lastDevice->serial);
346  } else {
347  lastDevice = malloc(sizeof(*deviceProps));
348  }
349  *lastDevice = *deviceProps;
350  lastDevice->serial = malloc(deviceProps->serial_length);
351  memcpy(lastDevice->serial, deviceProps->serial, deviceProps->serial_length);
352  UnlockMutex(&dataLock);
353 }
354 
355 /** Returns a pointer to the cached device info. */
356 LEAP_DEVICE_INFO* GetDeviceProperties(){
357  LEAP_DEVICE_INFO *currentDevice;
358  LockMutex(&dataLock);
359  currentDevice = lastDevice;
360  UnlockMutex(&dataLock);
361  return currentDevice;
362 }
363 
364 //End of polling example-specific code
365 
366 /** Translates eLeapRS result codes into a human-readable string. */
367 const char* ResultString(eLeapRS r) {
368  switch(r){
369  case eLeapRS_Success: return "eLeapRS_Success";
370  case eLeapRS_UnknownError: return "eLeapRS_UnknownError";
371  case eLeapRS_InvalidArgument: return "eLeapRS_InvalidArgument";
372  case eLeapRS_InsufficientResources: return "eLeapRS_InsufficientResources";
373  case eLeapRS_InsufficientBuffer: return "eLeapRS_InsufficientBuffer";
374  case eLeapRS_Timeout: return "eLeapRS_Timeout";
375  case eLeapRS_NotConnected: return "eLeapRS_NotConnected";
376  case eLeapRS_HandshakeIncomplete: return "eLeapRS_HandshakeIncomplete";
377  case eLeapRS_BufferSizeOverflow: return "eLeapRS_BufferSizeOverflow";
378  case eLeapRS_ProtocolError: return "eLeapRS_ProtocolError";
379  case eLeapRS_InvalidClientID: return "eLeapRS_InvalidClientID";
380  case eLeapRS_UnexpectedClosed: return "eLeapRS_UnexpectedClosed";
381  case eLeapRS_UnknownImageFrameRequest: return "eLeapRS_UnknownImageFrameRequest";
382  case eLeapRS_UnknownTrackingFrameID: return "eLeapRS_UnknownTrackingFrameID";
383  case eLeapRS_RoutineIsNotSeer: return "eLeapRS_RoutineIsNotSeer";
384  case eLeapRS_TimestampTooEarly: return "eLeapRS_TimestampTooEarly";
385  case eLeapRS_ConcurrentPoll: return "eLeapRS_ConcurrentPoll";
386  case eLeapRS_NotAvailable: return "eLeapRS_NotAvailable";
387  case eLeapRS_NotStreaming: return "eLeapRS_NotStreaming";
388  case eLeapRS_CannotOpenDevice: return "eLeapRS_CannotOpenDevice";
389  default: return "unknown result type.";
390  }
391 }
392 /** Cross-platform sleep function */
393 void millisleep(int milliseconds){
394 #ifdef _WIN32
395  Sleep(milliseconds);
396 #else
397  usleep(milliseconds*1000);
398 #endif
399  }
400 //End-of-ExampleConnection.c