/******************************************************************************
 * Copyright (C) Ultraleap, Inc. 2011-2024.                                   *
 *                                                                            *
 * Use subject to the terms of the Apache License 2.0 available at            *
 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement           *
 * between Ultraleap and you, your company or other organization.             *
 ******************************************************************************/


namespace LeapInternal
{
    using System;
    using System.Runtime.InteropServices;

    public enum eLeapConnectionFlag : uint
    {
        /// <summary>
        /// Allows subscription to multiple devices
        /// </summary>
        eLeapConnectionFlag_MultipleDevicesAware = 0x00000001,
    };

    public enum eLeapConnectionStatus : uint
    {
        /// <summary>
        /// A connection has been established.
        /// </summary>
        eLeapConnectionStatus_NotConnected = 0,
        /// <summary>
        /// The connection has not been completed. Call OpenConnection.
        /// </summary>
        eLeapConnectionStatus_Connected,
        /// <summary>
        /// The connection handshake has not completed.
        /// </summary>
        eLeapConnectionStatus_HandshakeIncomplete,
        /// <summary>
        /// A connection could not be established because the server does not appear to be running.
        /// </summary>
        eLeapConnectionStatus_NotRunning = 0xE7030004
    };

    public enum eLeapDeviceCaps : uint
    {
        /// <summary>
        /// The device can send color images.
        /// </summary>
        eLeapDeviceCaps_Color = 0x00000001,
    };

    public enum eLeapDeviceType : uint
    {
        /// <summary>
        /// The Leap Motion consumer peripheral
        /// </summary>
        eLeapDeviceType_Peripheral = 0x0003,
        /// <summary>
        /// Internal research product codename "Dragonfly".
        /// </summary>
        eLeapDeviceType_Dragonfly = 0x1102,
        /// <summary>
        /// Internal research product codename "Nightcrawler".
        /// </summary>
        eLeapDeviceType_Nightcrawler = 0x1201,
        /// <summary>
        /// Research product codename "Rigel".
        /// </summary>
        eLeapDevicePID_Rigel = 0x1202,
        /// <summary>
        /// The Ultraleap Stereo IR 170 (SIR170) hand tracking module.
        /// </summary>
        eLeapDevicePID_SIR170 = 0x1203,
        /// <summary>
        /// The Ultraleap 3Di hand tracking camera.
        /// </summary>
        eLeapDevicePID_3Di = 0x1204,
        /// <summary>
        /// The Ultraleap Leap Motion Controller 2 hand tracking camera.
        /// </summary>
        eLeapDevicePID_LMC2 = 0x1206
    };

    public enum eLeapServiceDisposition : uint
    {
        /// <summary>
        /// The service cannot receive frames fast enough from the underlying hardware.
        /// @since 3.1.3
        /// </summary>
        eLeapServiceState_LowFpsDetected = 0x00000001,

        /// <summary>
        /// The service has paused itself due to an insufficient frame rate from the hardware.
        /// @since 3.1.3
        /// </summary>
        eLeapServiceState_PoorPerformancePause = 0x00000002,

        /// <summary>
        /// The service has failed to start tracking due to unknown reasons.
        /// </summary>
        eLeapServiceState_TrackingErrorUnknown = 0x00000004,

        /// <summary>
        /// The combination of all valid flags in this enumeration
        /// </summary>
        eLeapServiceState_ALL = eLeapServiceState_LowFpsDetected | eLeapServiceState_PoorPerformancePause | eLeapServiceState_TrackingErrorUnknown
    };

    public enum eDistortionMatrixType
    {
        /// <summary>
        /// A 64x64 matrix of pairs of points.
        /// </summary>
        eDistortionMatrixType_64x64
    };

    public enum eLeapCameraCalibrationType
    {
        /// <summary>
        /// Infrared calibration (default)
        /// </summary>
        eLeapCameraCalibrationType_infrared = 0,

        /// <summary>
        /// Visual calibration. 
        /// </summary>
        eLeapCameraCalibrationType_visual = 1
    }


    public enum eLeapPolicyFlag : uint
    {
        /// <summary>
        /// Allows frame receipt even when this application is not the foreground application.
        /// </summary>
        eLeapPolicyFlag_BackgroundFrames = 0x00000001,
        /// <summary>
        /// Allow streaming images
        /// </summary>
        eLeapPolicyFlag_Images = 0x00000002,
        /// <summary>
        /// Optimize HMD Policy Flag.
        /// </summary>
        eLeapPolicyFlag_OptimizeHMD = 0x00000004,
        /// <summary>
        /// Modifies the security token to allow calls to LeapPauseDevice to succeed
        /// </summary>
        eLeapPolicyFlag_AllowPauseResume = 0x00000008,
        /// <summary>
        /// Allows streaming map points.
        /// </summary>
        eLeapPolicyFlag_MapPoints = 0x00000080,
        /// <summary>
        /// The policy specifying whether to optimize tracking for screen-top device.
        /// @since 5.0.0
        /// </summary>
        eLeapPolicyFlag_ScreenTop = 0x00000100,
    };

    public enum eLeapDeviceStatus : uint
    {
        /// <summary>
        /// Presently sending frames to all clients that have requested them.
        /// </summary>
        eLeapDeviceStatus_Streaming = 0x00000001,
        /// <summary>
        /// Device streaming has been paused.
        /// </summary>
        eLeapDeviceStatus_Paused = 0x00000002,
        /// <summary>
        /// There are known sources of infrared interference. Device has transitioned to
        /// robust mode in order to compensate.
        /// </summary>
        eLeapDeviceStatus_Robust = 0x00000004,
        /// <summary>
        /// The device's window is smudged, tracking may be degraded.
        /// </summary>
        eLeapDeviceStatus_Smudged = 0x00000008,
        /// <summary>
        /// The device has entered low-resource mode.
        /// </summary>
        eLeapDeviceStatus_LowResource = 0x00000010,
        /// <summary>
        /// The device has failed, but the failure reason is not known.
        /// </summary>
        eLeapDeviceStatus_UnknownFailure = 0xE8010000,
        /// <summary>
        /// Bad calibration, cannot send frames.
        /// </summary>
        eLeapDeviceStatus_BadCalibration = 0xE8010001,
        /// <summary>
        /// Corrupt firmware and/or cannot receive a required firmware update.
        /// </summary>
        eLeapDeviceStatus_BadFirmware = 0xE8010002,
        /// <summary>
        /// Exhibiting USB communications issues.
        /// </summary>
        eLeapDeviceStatus_BadTransport = 0xE8010003,
        /// <summary>
        /// Missing critical control interfaces needed for communication.
        /// </summary>
        eLeapDeviceStatus_BadControl = 0xE8010004,
    };

    public enum eLeapImageType
    {
        eLeapImageType_Unknown = 0,
        /// <summary>
        /// Default processed IR image
        /// </summary>
        eLeapImageType_Default,
        /// <summary>
        /// Image from raw sensor values
        /// </summary>
        eLeapImageType_Raw
    };

    public enum eLeapImageFormat : uint
    {
        /// <summary>
        /// An invalid or unknown format.
        /// </summary>
        eLeapImageFormat_UNKNOWN = 0,
        /// <summary>
        /// An infrared image.
        /// </summary>
        eLeapImageType_IR = 0x317249,
        /// <summary>
        /// A Bayer RGBIr image with uncorrected RGB channels
        /// </summary>
        eLeapImageType_RGBIr_Bayer = 0x49425247,
    };

    public enum eLeapPerspectiveType
    {
        /// <summary>
        /// An unknown or invalid type.
        /// </summary>
        eLeapPerspectiveType_invalid = 0,
        /// <summary>
        /// A canonically left image.
        /// </summary>
        eLeapPerspectiveType_stereo_left = 1,
        /// <summary>
        /// A canonically right image.
        /// </summary>
        eLeapPerspectiveType_stereo_right = 2,
        /// <summary>
        /// Reserved for future use.
        /// </summary>
        eLeapPerspectiveType_mono = 3,
    };

    public enum eLeapHandType
    {
        eLeapHandType_Left,
        eLeapHandType_Right
    };

    public enum eLeapLogSeverity
    {
        /// <summary>
        /// The message severity is not known or was not specified.
        /// </summary>
        eLeapLogSeverity_Unknown = 0,
        /// <summary>
        /// A message about a fault that could render the software or device non-functional.
        /// </summary>
        eLeapLogSeverity_Critical,
        /// <summary>
        /// A message warning about a condition that could degrade device capabilities.
        /// </summary>
        eLeapLogSeverity_Warning,
        /// <summary>
        /// A system status message.
        /// </summary>
        eLeapLogSeverity_Information
    };

    public enum eLeapValueType : int
    {
        /// <summary>
        /// The type is unknown (which is an abnormal condition).
        /// </summary>
        eLeapValueType_Unknown,
        eLeapValueType_Boolean,
        eLeapValueType_Int32,
        eLeapValueType_Float,
        eLeapValueType_String
    };

    public enum eLeapAllocatorType : uint
    {
        eLeapAllocatorType_Int8 = 0,
        eLeapAllocatorType_Uint8 = 1,
        eLeapAllocatorType_Int16 = 2,
        eLeapAllocatorType_UInt16 = 3,
        eLeapAllocatorType_Int32 = 4,
        eLeapAllocatorType_UInt32 = 5,
        eLeapAllocatorType_Float = 6,
        eLeapAllocatorType_Int64 = 8,
        eLeapAllocatorType_UInt64 = 9,
        eLeapAllocatorType_Double = 10,
    };

    public enum eLeapRS : uint
    {
        /// <summary>
        /// The operation completed successfully.
        /// </summary>
        eLeapRS_Success = 0x00000000,
        /// <summary>
        /// An undetermined error has occurred.
        /// This is usually the result of an abnormal operating condition in LeapC,
        /// the Leap Motion service, or the host computer itself.
        /// </summary>
        eLeapRS_UnknownError = 0xE2010000,
        /// <summary>
        /// An invalid argument was specified.
        /// </summary>
        eLeapRS_InvalidArgument = 0xE2010001,
        /// <summary>
        /// Insufficient resources existed to complete the request.
        /// </summary>
        eLeapRS_InsufficientResources = 0xE2010002,
        /// <summary>
        /// The specified buffer was not large enough to complete the request.
        /// </summary>
        eLeapRS_InsufficientBuffer = 0xE2010003,
        /// <summary>
        /// The requested operation has timed out.
        /// </summary>
        eLeapRS_Timeout = 0xE2010004,
        /// <summary>
        /// The operation is invalid because there is no current connection.
        /// </summary>
        eLeapRS_NotConnected = 0xE2010005,
        /// <summary>
        /// The operation is invalid because the connection is not complete.
        /// </summary>
        eLeapRS_HandshakeIncomplete = 0xE2010006,
        /// <summary>
        /// The specified buffer size is too large.
        /// </summary>
        eLeapRS_BufferSizeOverflow = 0xE2010007,
        /// <summary>
        /// A communications protocol error occurred.
        /// </summary>
        eLeapRS_ProtocolError = 0xE2010008,
        /// <summary>
        /// The server incorrectly specified zero as a client ID.
        /// </summary>
        eLeapRS_InvalidClientID = 0xE2010009,
        /// <summary>
        /// The connection to the service was unexpectedly closed while reading or writing a message.
        /// The server may have terminated.
        /// </summary>
        eLeapRS_UnexpectedClosed = 0xE201000A,
        /// <summary>
        /// The specified request token does not appear to be valid
        /// 
        /// Provided that the token value which identifies the request itself was, at one point, valid, this
        /// error condition occurs when the request to which the token refers has already been satisfied or
        /// is currently being satisfied.
        /// </summary>
        eLeapRS_UnknownImageFrameRequest = 0xE201000B,
        /// <summary>
        /// The specified frame ID is not valid or is no longer valid
        /// 
        /// Provided that frame ID was, at one point, valid, this error condition occurs when the identifier
        /// refers to a frame that occurred further in the past than is currently recorded in the rolling
        /// frame window.
        /// </summary>
        eLeapRS_UnknownTrackingFrameID = 0xE201000C,
        /// <summary>
        /// The specified timestamp references a future point in time
        /// 
        /// The related routine can only operate on time points having occurred in the past, and the
        /// provided timestamp occurs in the future.
        /// </summary>
        eLeapRS_RoutineIsNotSeer = 0xE201000D,
        /// <summary>
        /// The specified timestamp references a point too far in the past
        /// 
        /// The related routine can only operate on time points occurring within its immediate record of
        /// the past.
        /// </summary>
        eLeapRS_TimestampTooEarly = 0xE201000E,
        /// <summary>
        /// LeapPollConnection is called concurrently.
        /// </summary>
        eLeapRS_ConcurrentPoll = 0xE201000F,
        /// <summary>
        /// A connection to the Leap Motion service could not be established.
        /// </summary>
        eLeapRS_NotAvailable = 0xE7010002,
        /// <summary>
        /// The requested operation can only be performed while the device is sending data.
        /// </summary>
        eLeapRS_NotStreaming = 0xE7010004,
        /// <summary>
        /// The specified device could not be opened. It is possible that the device identifier
        /// is invalid, or that the device has been disconnected since being enumerated.
        /// </summary>
        eLeapRS_CannotOpenDevice = 0xE7010005,
        /// <summary>
        /// The request is not supported by this version of the service.
        /// </summary>
        eLeapRS_Unsupported = 0xE7010006
    };

    public enum eLeapTrackingMode
    {
        /// <summary>
        /// The tracking mode optimised for desktop devices 
        /// </summary>
        eLeapTrackingMode_Desktop = 0,

        /// <summary>
        /// The tracking mode optimised for head-mounted devices
        /// </summary>
        eLeapTrackingMode_HMD = 1,

        /// <summary>
        /// The tracking mode optimised for screen top-mounted devices
        /// </summary>
        eLeapTrackingMode_ScreenTop = 2,

        /// <summary>
        /// Tracking mode is not known (allows triggering of a new LEAP_TRACKING_MODE_EVENT) 
        /// </summary>
        eLeapTrackingMode_Unknown = 3
    }

    public enum eLeapEventType
    {
        /// <summary>
        /// No event has occurred within the timeout period specified when calling LeapPollConnection().
        /// </summary>
        eLeapEventType_None = 0,
        /// <summary>
        /// A connection to the Leap Motion service has been established.
        /// </summary>
        eLeapEventType_Connection,
        /// <summary>
        /// The connection to the Leap Motion service has been lost.
        /// </summary>
        eLeapEventType_ConnectionLost,
        /// <summary>
        /// A device has been detected or plugged-in.
        /// A device event is dispatched after a connection is established for any
        /// devices already plugged in. (The system currently only supports one
        /// streaming device at a time.)
        /// </summary>
        eLeapEventType_Device,
        /// <summary>
        /// Note that unplugging a device generates an eLeapEventType_DeviceLost event
        /// message, not a failure message.
        /// </summary>
        eLeapEventType_DeviceFailure,
        /// <summary>
        /// A policy change has occurred.
        /// This can be due to setting a policy with LeapSetPolicyFlags() or due to changing
        /// or policy-related config settings, including images_mode.
        /// (A user can also change these policies using the Leap Motion Control Panel.)
        /// </summary>
        eLeapEventType_Policy,
        /// <summary>
        /// A tracking frame. The message contains the tracking data for the frame.
        /// </summary>
        eLeapEventType_Tracking = 0x100,
        /// <summary>
        /// The request for an image has failed.
        /// The message contains information about the failure. The client application
        /// will not receive the requested image set.
        /// </summary>
        eLeapEventType_ImageRequestError,
        /// <summary>
        /// The request for an image is complete.
        /// The image data has been completely written to the application-provided
        /// buffer.
        /// </summary>
        eLeapEventType_ImageComplete,
        /// <summary>
        /// A system message.
        /// </summary>
        eLeapEventType_LogEvent,
        /// <summary>
        ///  The device connection has been lost.
        /// 
        /// This event is generally asserted when the device has been detached from the system, when the
        /// connection to the service has been lost, or if the device is closed while streaming. Generally,
        /// any event where the system can conclude no further frames will be received will result in this
        /// message. The DeviceEvent field will be filled with the id of the formerly attached device.
        /// </summary>
        eLeapEventType_DeviceLost,
        /// <summary>
        /// The asynchronous response to a call to LeapRequestConfigValue().
        /// Contains the value of requested configuration item.
        /// </summary>
        eLeapEventType_ConfigResponse,
        /// <summary>
        /// The asynchronous response to a call to LeapSaveConfigValue().
        /// Reports whether the change succeeded or failed.
        /// </summary>
        eLeapEventType_ConfigChange,
        /// <summary>
        /// Notification that a status change has been detected on an attached device.
        /// </summary>
        eLeapEventType_DeviceStatusChange,
        /// <summary>
        /// A tracking frame has been dropped by the service.
        /// </summary>
        eLeapEventType_DroppedFrame,
        /// <summary>
        /// Notification that an unrequested stereo image pair is available.
        /// </summary>
        eLeapEventType_Image,
        /// <summary>
        /// Notification that point mapping has changed.
        /// </summary>
        eLeapEventType_PointMappingChange,
        /// <summary>
        /// A tracking mode change has occurred.
        /// This can be due to changing the hmd or screentop policy with SetPolicyFlags().
        /// or setting the tracking mode using SetTrackingMode().
        /// </summary>
        eLeapEventType_TrackingMode,
        /// <summary>
        /// An array of system messages.
        /// </summary>
        eLeapEventType_LogEvents,
        /// <summary>
        /// A new head pose is available.
        /// </summary>
        [Obsolete("Head pose events are not supported and will never be raised")]
        eLeapEventType_HeadPose,
        /// <summary>
        /// A new head pose is available.
        /// </summary>
        [Obsolete("Eye pose events are not supported and will never be raised")]
        eLeapEventType_Eyes,
        /// <summary>
        /// A new IMU information frame is available.
        /// </summary>
        eLeapEventType_IMU,
        /// <summary>
        /// Notification that the service received a new device transformation matrix
        /// Use LeapGetDeviceTransform to update your cached information.
        /// </summary>
        eLeapEventType_NewDeviceTransform,
        /// <summary>
        /// An event provided when a fiducial marker has been tracked
        /// </summary>
        eLeapEventType_Fiducial
    };

    public enum eLeapDeviceFlag : uint
    {
        /// <summary>
        /// Flag set if the device is presently streaming frames
        /// 
        /// This flag is updated when the user pauses or resumes tracking on the device from the Leap control
        /// panel. Modification of this flag will fail if the AllowPauseResume policy is not set on this device
        /// object.
        /// </summary>
        eLeapDeviceFlag_Stream = 0x00000001
    };

    public enum eLeapDroppedFrameType
    {
        eLeapDroppedFrameType_PreprocessingQueue,
        eLeapDroppedFrameType_TrackingQueue,
        eLeapDroppedFrameType_Other
    };

    public enum eLeapVersionPart
    {
        eLeapVersionPart_ClientLibrary = 0,
        eLeapVersionPart_ClientProtocol = 1,
        eLeapVersionPart_ServerLibrary = 2,
        eLeapVersionPart_ServerProtocol = 3
    };

    //Note the following LeapC structs are just IntPtrs in C#:
    // LEAP_CONNECTION is an IntPtr
    // LEAP_DEVICE is an IntPtr
    // LEAP_CLOCK_REBASER is an IntPtr

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct LEAP_VERSION
    {
        public Int32 major;
        public Int32 minor;
        public Int32 patch;

        public new string ToString()
        {
            return major + "." + minor + "." + patch;
        }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_CONNECTION_CONFIG
    {
        public UInt32 size;
        public UInt32 flags;
        public IntPtr server_namespace; //char*
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_CONNECTION_INFO
    {
        public UInt32 size;
        public eLeapConnectionStatus status;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_CONNECTION_EVENT
    {
        public eLeapServiceDisposition flags;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_DEVICE_REF
    {
        public IntPtr handle; //void *
        public UInt32 id;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_CONNECTION_LOST_EVENT
    {
        public UInt32 flags;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_ALLOCATOR
    {
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public Allocate allocate;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public Deallocate deallocate;
        public IntPtr state;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_DEVICE_EVENT
    {
        public UInt32 flags;
        public LEAP_DEVICE_REF device;
        public eLeapDeviceStatus status;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_DEVICE_STATUS_CHANGE_EVENT
    {
        public LEAP_DEVICE_REF device;
        public eLeapDeviceStatus last_status;
        public eLeapDeviceStatus status;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_DEVICE_FAILURE_EVENT
    {
        public eLeapDeviceStatus status;
        public IntPtr hDevice;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_TRACKING_EVENT
    {
        public LEAP_FRAME_HEADER info;
        public Int64 tracking_id;
        public UInt32 nHands;
        public IntPtr pHands; //LEAP_HAND*
        public float framerate;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_TRACKING_MODE_EVENT
    {
        public UInt32 reserved;
        public eLeapTrackingMode current_tracking_mode;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_DROPPED_FRAME_EVENT
    {
        public Int64 frame_id;
        public eLeapDroppedFrameType reason;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_POINT_MAPPING_CHANGE_EVENT
    {
        public Int64 frame_id;
        public Int64 timestamp;
        public UInt32 nPoints;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_POINT_MAPPING
    {
        public Int64 frame_id;
        public Int64 timestamp;
        public UInt32 nPoints;
        public IntPtr points;  //LEAP_VECTOR*
        public IntPtr ids;     //uint32*
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_EYE_EVENT
    {
        public Int64 frame_id;
        public Int64 timestamp;
        public LEAP_VECTOR left_eye_position;
        public LEAP_VECTOR right_eye_position;
        public float left_eye_estimated_error;
        public float right_eye_estimated_error;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_HEAD_POSE_EVENT
    {
        public Int64 timestamp;
        public LEAP_VECTOR head_position;
        public LEAP_QUATERNION head_orientation;
        public LEAP_VECTOR head_linear_velocity;
        public LEAP_VECTOR head_angular_velocity;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_NEW_DEVICE_TRANSFORM
    {
        public UInt32 reserved;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_CONNECTION_MESSAGE
    {
        public UInt32 size;
        public eLeapEventType type;
        public IntPtr eventStructPtr;
        public UInt32 deviceID;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_DISCONNECTION_EVENT
    {
        public UInt32 reserved;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct LEAP_DEVICE_INFO
    {
        public UInt32 size;
        public UInt32 status;
        public eLeapDeviceCaps caps;
        public eLeapDeviceType type;
        public UInt32 baseline;
        public UInt32 serial_length;
        public IntPtr serial; //char*
        public float h_fov;
        public float v_fov;
        public UInt32 range;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_FRAME_HEADER
    {
        public IntPtr reserved;
        public Int64 frame_id;
        public Int64 timestamp;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_IMAGE_PROPERTIES
    {
        public eLeapImageType type;
        public eLeapImageFormat format;
        public UInt32 bpp;
        public UInt32 width;
        public UInt32 height;
        public float x_scale;
        public float y_scale;
        public float x_offset;
        public float y_offset;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_IMAGE
    {
        public LEAP_IMAGE_PROPERTIES properties;
        public UInt64 matrix_version;

        //LEAP_DISTORTION_MATRIX* 
        //The struct LEAP_DISTORTION_MATRIX cannot exist in c# without using unsafe code
        //This is ok though, since it is just an array of floats
        //so you need to manually marshal this pointer to the correct size and type
        //See LeapC.h for details
        public IntPtr distortionMatrix;
        public IntPtr data; // void* of an allocator-supplied buffer
        public UInt32 offset; // Offset, in bytes, from beginning of buffer to start of image data
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_IMAGE_EVENT
    {
        public LEAP_FRAME_HEADER info;
        public LEAP_IMAGE leftImage;
        public LEAP_IMAGE rightImage;
        public IntPtr calib; //LEAP_CALIBRATION
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_VECTOR
    {
        public float x;
        public float y;
        public float z;

        public UnityEngine.Vector3 ToVector3()
        {
            return new UnityEngine.Vector3(x, y, z);
        }

        public LEAP_VECTOR(UnityEngine.Vector3 vector)
        {
            x = vector.x;
            y = vector.y;
            z = vector.z;
        }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_QUATERNION
    {
        public float x;
        public float y;
        public float z;
        public float w;

        public UnityEngine.Quaternion ToQuaternion()
        {
            return new UnityEngine.Quaternion(x, y, z, w);
        }

        public LEAP_QUATERNION(UnityEngine.Quaternion q)
        {
            x = q.x;
            y = q.y;
            z = q.z;
            w = q.w;
        }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_MATRIX_3x3
    {
        public LEAP_VECTOR m1;
        public LEAP_VECTOR m2;
        public LEAP_VECTOR m3;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_BONE
    {
        public LEAP_VECTOR prev_joint;
        public LEAP_VECTOR next_joint;
        public float width;
        public LEAP_QUATERNION rotation;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_DIGIT
    {
        public Int32 finger_id;
        public LEAP_BONE metacarpal;
        public LEAP_BONE proximal;
        public LEAP_BONE intermediate;
        public LEAP_BONE distal;
        public Int32 is_extended;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_PALM
    {
        public LEAP_VECTOR position;
        public LEAP_VECTOR stabilized_position;
        public LEAP_VECTOR velocity;
        public LEAP_VECTOR normal;
        public float width;
        public LEAP_VECTOR direction;
        public LEAP_QUATERNION orientation;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_HAND
    {
        public UInt32 id;
        public UInt32 flags;
        public eLeapHandType type;
        public float confidence;
        public UInt64 visible_time;
        public float pinch_distance;
        public float grab_angle;
        public float pinch_strength;
        public float grab_strength;
        public LEAP_PALM palm;
        public LEAP_DIGIT thumb;
        public LEAP_DIGIT index;
        public LEAP_DIGIT middle;
        public LEAP_DIGIT ring;
        public LEAP_DIGIT pinky;
        public LEAP_BONE arm;
    }


    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_TIP
    {
        public LEAP_VECTOR position;
        public float radius;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct LEAP_LOG_EVENT
    {
        public eLeapLogSeverity severity;
        public Int64 timestamp;
        public IntPtr message; //char*
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct LEAP_POLICY_EVENT
    {
        public UInt32 reserved;
        public UInt32 current_policy;
    }

    [StructLayout(LayoutKind.Explicit, Pack = 1)]
    public struct LEAP_VARIANT_VALUE_TYPE
    {
        [FieldOffset(0)]
        public eLeapValueType type;
        [FieldOffset(4)]
        public Int32 boolValue;
        [FieldOffset(4)]
        public Int32 intValue;
        [FieldOffset(4)]
        public float floatValue;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct LEAP_VARIANT_REF_TYPE
    {
        public eLeapValueType type;
        public string stringValue;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_CONFIG_RESPONSE_EVENT
    {
        public UInt32 requestId;
        public LEAP_VARIANT_VALUE_TYPE value;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct LEAP_CONFIG_RESPONSE_EVENT_WITH_REF_TYPE
    {
        public UInt32 requestId;
        public LEAP_VARIANT_REF_TYPE value;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct LEAP_CONFIG_CHANGE_EVENT
    {
        public UInt32 requestId;
        public bool status;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct LEAP_TELEMETRY_DATA
    {
        public UInt32 threadId;
        public UInt64 startTime;
        public UInt64 endTime;
        public UInt32 zoneDepth;
        public string fileName;
        public UInt32 lineNumber;
        public string zoneName;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct LEAP_FIDUCIAL_POSE_EVENT
    {
        public int id;
        public IntPtr family; // char*
        public float size;
        public Int64 timestamp;
        public float estimated_error;
        public LEAP_VECTOR translation;
        public LEAP_QUATERNION rotation;
    }

    public class LeapC
    {
        private LeapC() { }
        public static int DistortionSize = 64;

        [DllImport("LeapC", EntryPoint = "LeapSetTrackingMode")]
        public static extern eLeapRS SetTrackingMode(IntPtr hConnection, eLeapTrackingMode mode);

        [DllImport("LeapC", EntryPoint = "LeapSetTrackingModeEx")]
        public static extern eLeapRS SetTrackingModeEx(IntPtr hConnection, IntPtr hDevice, eLeapTrackingMode mode);

        [DllImport("LeapC", EntryPoint = "LeapGetTrackingMode")]
        public static extern eLeapRS LeapGetTrackingMode(IntPtr hConnection);

        [DllImport("LeapC", EntryPoint = "LeapGetTrackingModeEx")]
        public static extern eLeapRS LeapGetTrackingModeEx(IntPtr hConnection, IntPtr hDevice);

        [DllImport("LeapC", EntryPoint = "LeapGetNow")]
        public static extern long GetNow();

        [DllImport("LeapC", EntryPoint = "LeapCreateClockRebaser")]
        public static extern eLeapRS CreateClockRebaser(out IntPtr phClockRebaser);

        [DllImport("LeapC", EntryPoint = "LeapDestroyClockRebaser")]
        public static extern eLeapRS DestroyClockRebaser(IntPtr hClockRebaser);

        [DllImport("LeapC", EntryPoint = "LeapUpdateRebase")]
        public static extern eLeapRS UpdateRebase(IntPtr hClockRebaser, Int64 userClock, Int64 leapClock);

        [DllImport("LeapC", EntryPoint = "LeapRebaseClock")]
        public static extern eLeapRS RebaseClock(IntPtr hClockRebaser, Int64 userClock, out Int64 leapClock);

        [DllImport("LeapC", EntryPoint = "LeapCreateConnection")]
        public static extern eLeapRS CreateConnection(ref LEAP_CONNECTION_CONFIG pConfig, out IntPtr pConnection);

        //Overrides to allow config to be set to null to use default config
        [DllImport("LeapC", EntryPoint = "LeapCreateConnection")]
        private static extern eLeapRS CreateConnection(IntPtr nulled, out IntPtr pConnection);
        public static eLeapRS CreateConnection(out IntPtr pConnection)
        {
            return CreateConnection(IntPtr.Zero, out pConnection);
        }

        [DllImport("LeapC", EntryPoint = "LeapGetConnectionInfo")]
        public static extern eLeapRS GetConnectionInfo(IntPtr hConnection, ref LEAP_CONNECTION_INFO pInfo);

        [DllImport("LeapC", EntryPoint = "LeapOpenConnection")]
        public static extern eLeapRS OpenConnection(IntPtr hConnection);

        [DllImport("LeapC", EntryPoint = "LeapSetConnectionMetadata")]
        public static extern eLeapRS SetConnectionMetadata(IntPtr hConnection, string metadata, UIntPtr len);

        [DllImport("LeapC", EntryPoint = "LeapSetAllocator")]
        public static extern eLeapRS SetAllocator(IntPtr hConnection, ref LEAP_ALLOCATOR pAllocator);

        [DllImport("LeapC", EntryPoint = "LeapGetDeviceList")]
        public static extern eLeapRS GetDeviceList(IntPtr hConnection, [In, Out] LEAP_DEVICE_REF[] pArray, out UInt32 pnArray);

        [DllImport("LeapC", EntryPoint = "LeapGetDeviceList")]
        private static extern eLeapRS GetDeviceList(IntPtr hConnection, [In, Out] IntPtr pArray, out UInt32 pnArray);
        //Override to allow pArray argument to be set to null (IntPtr.Zero) in order to get the device count
        public static eLeapRS GetDeviceCount(IntPtr hConnection, out UInt32 deviceCount)
        {
            return GetDeviceList(hConnection, IntPtr.Zero, out deviceCount);
        }

        [DllImport("LeapC", EntryPoint = "LeapOpenDevice")]
        public static extern eLeapRS OpenDevice(LEAP_DEVICE_REF rDevice, out IntPtr pDevice);

        [DllImport("LeapC", EntryPoint = "LeapSetPrimaryDevice")]
        public static extern eLeapRS LeapSetPrimaryDevice(IntPtr hConnection, IntPtr hDevice, bool unsubscribeOthers);

        [DllImport("LeapC", EntryPoint = "LeapSubscribeEvents")]
        public static extern eLeapRS LeapSubscribeEvents(IntPtr hConnection, IntPtr hDevice);

        [DllImport("LeapC", EntryPoint = "LeapUnsubscribeEvents")]
        public static extern eLeapRS LeapUnsubscribeEvents(IntPtr hConnection, IntPtr hDevice);

        [DllImport("LeapC", EntryPoint = "LeapGetDeviceInfo", CharSet = CharSet.Ansi)]
        public static extern eLeapRS GetDeviceInfo(IntPtr hDevice, ref LEAP_DEVICE_INFO info);

        [DllImport("LeapC", EntryPoint = "LeapDeviceTransformAvailable")]
        public static extern bool GetDeviceTransformAvailable(IntPtr hDevice);

        [DllImport("LeapC", EntryPoint = "LeapGetDeviceTransform")]
        public static extern eLeapRS GetDeviceTransform(IntPtr hDevice, [MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] float[] transform);

        [DllImport("LeapC", EntryPoint = "LeapSetPolicyFlags")]
        public static extern eLeapRS SetPolicyFlags(IntPtr hConnection, UInt64 set, UInt64 clear);

        [DllImport("LeapC", EntryPoint = "LeapSetPolicyFlagsEx")]
        public static extern eLeapRS SetPolicyFlagsEx(IntPtr hConnection, IntPtr hDevice, UInt64 set, UInt64 clear);

        [DllImport("LeapC", EntryPoint = "LeapSetPause")]
        public static extern eLeapRS LeapSetPause(IntPtr hConnection, bool pause);

        [DllImport("LeapC", EntryPoint = "LeapSetDeviceFlags")]
        public static extern eLeapRS SetDeviceFlags(IntPtr hDevice, UInt64 set, UInt64 clear, out UInt64 prior);

        [DllImport("LeapC", EntryPoint = "LeapPollConnection")]
        public static extern eLeapRS PollConnection(IntPtr hConnection, UInt32 timeout, ref LEAP_CONNECTION_MESSAGE msg);

        [DllImport("LeapC", EntryPoint = "LeapGetFrameSize")]
        public static extern eLeapRS GetFrameSize(IntPtr hConnection, Int64 timestamp, out UInt64 pncbEvent);

        [DllImport("LeapC", EntryPoint = "LeapGetFrameSizeEx")]
        public static extern eLeapRS GetFrameSizeEx(IntPtr hConnection, IntPtr hDevice, Int64 timestamp, out UInt64 pncbEvent);

        [DllImport("LeapC", EntryPoint = "LeapInterpolateFrame")]
        public static extern eLeapRS InterpolateFrame(IntPtr hConnection, Int64 timestamp, IntPtr pEvent, UInt64 ncbEvent);

        [DllImport("LeapC", EntryPoint = "LeapInterpolateFrameEx")]
        public static extern eLeapRS InterpolateFrameEx(IntPtr hConnection, IntPtr hDevice, Int64 timestamp, IntPtr pEvent, UInt64 ncbEvent);

        [DllImport("LeapC", EntryPoint = "LeapInterpolateFrameFromTime")]
        public static extern eLeapRS InterpolateFrameFromTime(IntPtr hConnection, Int64 timestamp, Int64 sourceTimestamp, IntPtr pEvent, UInt64 ncbEvent);

        [DllImport("LeapC", EntryPoint = "LeapInterpolateFrameFromTimeEx")]
        public static extern eLeapRS InterpolateFrameFromTimeEx(IntPtr hConnection, IntPtr hDevice, Int64 timestamp, Int64 sourceTimestamp, IntPtr pEvent, UInt64 ncbEvent);

        [DllImport("LeapC", EntryPoint = "LeapInterpolateHeadPose")]
        public static extern eLeapRS InterpolateHeadPose(IntPtr hConnection, Int64 timestamp, ref LEAP_HEAD_POSE_EVENT headPose);

        [DllImport("LeapC", EntryPoint = "LeapInterpolateEyePositions")]
        public static extern eLeapRS InterpolateEyePositions(IntPtr hConnection, Int64 timestamp, ref LEAP_EYE_EVENT eyes);

        [DllImport("LeapC", EntryPoint = "LeapPixelToRectilinear")]
        public static extern LEAP_VECTOR LeapPixelToRectilinear(IntPtr hConnection,
          eLeapPerspectiveType camera, LEAP_VECTOR pixel);

        [Obsolete("Use of calibrationType is not valid. Use alternative LeapPixelToRectilinearEx method."), DllImport("LeapC", EntryPoint = "LeapPixelToRectilinearEx")]
        public static extern LEAP_VECTOR LeapPixelToRectilinearEx(IntPtr hConnection,
          IntPtr hDevice, eLeapPerspectiveType camera, eLeapCameraCalibrationType calibrationType, LEAP_VECTOR pixel);

        [DllImport("LeapC", EntryPoint = "LeapPixelToRectilinearEx")]
        public static extern LEAP_VECTOR LeapPixelToRectilinearEx(IntPtr hConnection,
            IntPtr hDevice, eLeapPerspectiveType camera, LEAP_VECTOR pixel);

        [DllImport("LeapC", EntryPoint = "LeapRectilinearToPixel")]
        public static extern LEAP_VECTOR LeapRectilinearToPixel(IntPtr hConnection,
          eLeapPerspectiveType camera, LEAP_VECTOR rectilinear);

        [DllImport("LeapC", EntryPoint = "LeapRectilinearToPixelEx")]
        public static extern LEAP_VECTOR LeapRectilinearToPixelEx(IntPtr hConnection,
          IntPtr hDevice, eLeapPerspectiveType camera, LEAP_VECTOR rectilinear);

        [DllImport("LeapC", EntryPoint = "LeapExtrinsicCameraMatrix")]
        public static extern eLeapRS LeapExtrinsicCameraMatrix(IntPtr hConnection, eLeapPerspectiveType camera, 
            [MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] float[] extrinsicMatrix);

        [DllImport("LeapC", EntryPoint = "LeapExtrinsicCameraMatrixEx")]
        public static extern eLeapRS LeapExtrinsicCameraMatrixEx(IntPtr hConnection, IntPtr hDevice, eLeapPerspectiveType camera, 
            [MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] float[] extrinsicMatrix);

        [DllImport("LeapC", EntryPoint = "LeapCloseDevice")]
        public static extern void CloseDevice(IntPtr pDevice);

        [DllImport("LeapC", EntryPoint = "LeapCloseConnection")]
        public static extern eLeapRS CloseConnection(IntPtr hConnection);

        [DllImport("LeapC", EntryPoint = "LeapDestroyConnection")]
        public static extern void DestroyConnection(IntPtr connection);

        [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
        [DllImport("LeapC", EntryPoint = "LeapSaveConfigValue")]
        private static extern eLeapRS SaveConfigValue(IntPtr hConnection, string key, IntPtr value, out UInt32 requestId);

        [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
        [DllImport("LeapC", EntryPoint = "LeapRequestConfigValue")]
        public static extern eLeapRS RequestConfigValue(IntPtr hConnection, string name, out UInt32 request_id);

        [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
        public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, bool value, out UInt32 requestId)
        {
            LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE(); //This is a C# approximation of a C union
            valueStruct.type = eLeapValueType.eLeapValueType_Boolean;
            valueStruct.boolValue = value ? 1 : 0;
            return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
        }
        [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
        public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, Int32 value, out UInt32 requestId)
        {
            LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE();
            valueStruct.type = eLeapValueType.eLeapValueType_Int32;
            valueStruct.intValue = value;
            return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
        }
        [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
        public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, float value, out UInt32 requestId)
        {
            LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE();
            valueStruct.type = eLeapValueType.eLeapValueType_Float;
            valueStruct.floatValue = value;
            return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
        }
        [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
        public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, string value, out UInt32 requestId)
        {
            LEAP_VARIANT_REF_TYPE valueStruct;
            valueStruct.type = eLeapValueType.eLeapValueType_String;
            valueStruct.stringValue = value;
            return SaveConfigWithRefType(hConnection, key, valueStruct, out requestId);
        }

        [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
        private static eLeapRS SaveConfigWithValueType(IntPtr hConnection, string key, LEAP_VARIANT_VALUE_TYPE valueStruct, out UInt32 requestId)
        {
            IntPtr configValue = Marshal.AllocHGlobal(Marshal.SizeOf(valueStruct));
            eLeapRS callResult = eLeapRS.eLeapRS_UnknownError;
            try
            {
                Marshal.StructureToPtr(valueStruct, configValue, false);
                callResult = SaveConfigValue(hConnection, key, configValue, out requestId);
            }
            finally
            {
                Marshal.FreeHGlobal(configValue);
            }
            return callResult;
        }

        [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
        private static eLeapRS SaveConfigWithRefType(IntPtr hConnection, string key, LEAP_VARIANT_REF_TYPE valueStruct, out UInt32 requestId)
        {
            IntPtr configValue = Marshal.AllocHGlobal(Marshal.SizeOf(valueStruct));
            eLeapRS callResult = eLeapRS.eLeapRS_UnknownError;
            try
            {
                Marshal.StructureToPtr(valueStruct, configValue, false);
                callResult = SaveConfigValue(hConnection, key, configValue, out requestId);
            }
            finally
            {
                Marshal.FreeHGlobal(configValue);
            }
            return callResult;
        }

        [DllImport("LeapC", EntryPoint = "LeapGetPointMappingSize")]
        public static extern eLeapRS GetPointMappingSize(IntPtr hConnection, ref ulong pSize);

        [DllImport("LeapC", EntryPoint = "LeapGetPointMapping")]
        public static extern eLeapRS GetPointMapping(IntPtr hConnection, IntPtr pointMapping, ref ulong pSize);

        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct LEAP_RECORDING_PARAMETERS
        {
            public UInt32 mode;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct LEAP_RECORDING_STATUS
        {
            public UInt32 mode;
        }

        [DllImport("LeapC", EntryPoint = "LeapRecordingOpen")]
        public static extern eLeapRS RecordingOpen(ref IntPtr ppRecording, string userPath, LEAP_RECORDING_PARAMETERS parameters);

        [DllImport("LeapC", EntryPoint = "LeapRecordingClose")]
        public static extern eLeapRS RecordingClose(ref IntPtr ppRecording);

        [DllImport("LeapC", EntryPoint = "LeapRecordingGetStatus")]
        public static extern eLeapRS LeapRecordingGetStatus(IntPtr pRecording, ref LEAP_RECORDING_STATUS status);

        [DllImport("LeapC", EntryPoint = "LeapRecordingReadSize")]
        public static extern eLeapRS RecordingReadSize(IntPtr pRecording, ref UInt64 pncbEvent);

        [DllImport("LeapC", EntryPoint = "LeapRecordingRead")]
        public static extern eLeapRS RecordingRead(IntPtr pRecording, ref LEAP_TRACKING_EVENT pEvent, UInt64 ncbEvent);

        [DllImport("LeapC", EntryPoint = "LeapRecordingWrite")]
        public static extern eLeapRS RecordingWrite(IntPtr pRecording, ref LEAP_TRACKING_EVENT pEvent, ref UInt64 pnBytesWritten);

        [DllImport("LeapC", EntryPoint = "LeapTelemetryProfiling")]
        public static extern eLeapRS LeapTelemetryProfiling(IntPtr hConnection, ref LEAP_TELEMETRY_DATA telemetryData);

        [DllImport("LeapC", EntryPoint = "LeapTelemetryGetNow")]
        public static extern UInt64 TelemetryGetNow();

        [DllImport("LeapC", EntryPoint = "LeapGetVersion")]
        public static extern eLeapRS GetVersion(IntPtr hConnection, eLeapVersionPart versionPart, ref LEAP_VERSION pVersion);

        [DllImport("LeapC", EntryPoint = "LeapGetServerStatus")]
        public static extern eLeapRS GetServerStatus(UInt32 timeout, ref IntPtr status);

        [DllImport("LeapC", EntryPoint = "LeapReleaseServerStatus")]
        public static extern eLeapRS ReleaseServerStatus(ref LEAP_SERVER_STATUS status);


        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct LEAP_SERVER_STATUS
        {
            public string version;
            public UInt32 device_count;
            public IntPtr devices;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct LEAP_SERVER_STATUS_DEVICE
        {
            public string serial;
            public string type;
        }

        public static eLeapRS SetDeviceHints(IntPtr hConnection, IntPtr hDevice, string[] hints)
        {
            // Ensure the final element of the array is null terminated.
            if (hints.Length == 0 || hints[^1] != null)
            {
                Array.Resize(ref hints, hints.Length + 1);
                hints[^1] = null;
            }

            return SetDeviceHintsInternal(hConnection, hDevice, hints);
        }

        [DllImport("LeapC", EntryPoint = "LeapSetDeviceHints")]
        private static extern eLeapRS SetDeviceHintsInternal(IntPtr hConnection, IntPtr hDevice, string[] hints);
    }
}