diff --git a/Program.cs b/Program.cs index ba12055..4e58fe1 100644 --- a/Program.cs +++ b/Program.cs @@ -1,20 +1,41 @@ -using System; -using spnavwrapper; +using System; -namespace spnavcsharpwrapper +namespace SpaceNavWrapper { class Program { static void Main(string[] args) { - SpaceNav.Instance.Threshold = 5; - SpaceNav.Instance.Sensitivity = 0.1; + //spnavwrapper.SpaceNav.Instance.Threshold = 5; + //spnavwrapper.SpaceNav.Instance.Sensitivity = 0.1; + + //for (; ; ) + //{ + // var ev = spnavwrapper.SpaceNav.Instance.WaitEvent(100); + // Console.WriteLine(ev); + //} + SpaceNavDriver navDriver = new SpaceNavDriver(); + navDriver.InitDevice(); + navDriver.Button += OnButton; + navDriver.Motion += OnMotion; + + Console.CancelKeyPress += delegate { + navDriver.Dispose(); + }; for (; ; ) { - var ev = SpaceNav.Instance.WaitEvent(100); - Console.WriteLine(ev); } } + + private static void OnMotion(object sender, MotionEventArgs e) + { + Console.WriteLine(e); + } + + private static void OnButton(object sender, EventArgs e) + { + Console.WriteLine("Button pressed"); + } } } diff --git a/SpaceNav.cs b/SpaceNav.cs index 0d4eaae..09f83b6 100644 --- a/SpaceNav.cs +++ b/SpaceNav.cs @@ -1,176 +1,147 @@ using System; using System.Runtime.InteropServices; +using System.Threading; -namespace spnavwrapper +namespace SpaceNavWrapper { - public sealed class SpaceNav : IDisposable - { + public class SpaceNavDriver : IDisposable + { + const string DLL_NAME = "spnavhdi"; + + #region Constants + private const int SPNAV_EVENT_MOTION = 1; + private const int SPNAV_EVENT_BUTTON = 2; + private const ushort SPNAV_VENDOR_ID = 0x046d; + private const ushort SPNAV_PRODUCT_ID = 0x0c627; + #endregion - #region Constants - private const int SPNAV_EVENT_MOTION = 1; - private const int SPNAV_EVENT_BUTTON = 2; - private const ushort SPNAV_VENDOR_ID = 0x046d; - private const ushort SPNAV_PRODUCT_ID = 0x0c627; - #endregion - - private double _sensitivity = 1.0; - private int _threshold = 5; - private static SpaceNav instance; + public event EventHandler Motion; + public event EventHandler Button; + + private Thread eventThread; + private bool deviceReady; + private double _sensitivity = 1.0; + private int _threshold = 5; + private bool isDisposed; #region Structures private struct SpNavEventMotion - { - public int type; - public int x, y, z; - public int rx, ry, rz; - public uint period; - public IntPtr data; - } + { + public int type; + public int x, y, z; + public int rx, ry, rz; + public uint period; + public IntPtr data; + } - private struct SpNavEventButton - { - public int type; - public int press; - public int bnum; - } + private struct SpNavEventButton + { + public int type; + public int press; + public int bnum; + } - [StructLayout(LayoutKind.Explicit)] - private struct SpNavEvent - { - [FieldOffset(0)] public int type; - [FieldOffset(0)] public SpNavEventMotion motion; - [FieldOffset(0)] public SpNavEventButton button; - } - #endregion - - #region DLL Imports - [DllImport(DLL_NAME)] - private static extern int spnav_open(ushort vendor_id, ushort product_id); - [DllImport(DLL_NAME)] - private static extern int spnav_close(); - [DllImport(DLL_NAME)] - private static extern int spnav_wait_event(ref SpNavEvent ev); - [DllImport(DLL_NAME)] - private static extern int spnav_wait_event_timeout(ref SpNavEvent ev, int timeout); - [DllImport(DLL_NAME)] - private static extern int spnav_sensitivity(double sens); - [DllImport(DLL_NAME)] - private static extern int spnav_deadzone(int threshold); - #endregion - - private SpaceNav() - { - // TODO : handle retcode + [StructLayout(LayoutKind.Explicit)] + private struct SpNavEvent + { + [FieldOffset(0)] public int type; + [FieldOffset(0)] public SpNavEventMotion motion; + [FieldOffset(0)] public SpNavEventButton button; + } + #endregion + + #region DLL Imports + [DllImport(DLL_NAME)] + private static extern int spnav_open(ushort vendor_id, ushort product_id); + [DllImport(DLL_NAME)] + private static extern int spnav_close(); + [DllImport(DLL_NAME)] + private static extern int spnav_wait_event(ref SpNavEvent ev); + [DllImport(DLL_NAME)] + private static extern int spnav_wait_event_timeout(ref SpNavEvent ev, int timeout); + [DllImport(DLL_NAME)] + private static extern int spnav_sensitivity(double sens); + [DllImport(DLL_NAME)] + private static extern int spnav_deadzone(int threshold); + #endregion + + public SpaceNavDriver() + { + eventThread = new Thread(HandleEvents) + { + IsBackground = true, + Name = "3Dconnexion-Event-Dispatcher" + }; + eventThread.Start(); + } + + public void InitDevice() + { spnav_open(SPNAV_VENDOR_ID, SPNAV_PRODUCT_ID); - } + spnav_deadzone(5); + deviceReady = true; + } - #region IDisposable Support - private bool disposedValue = false; // To detect redundant calls - - private void Dispose(bool disposing) - { - if (!disposedValue) - { - // Free unmanaged resources - spnav_close(); - disposedValue = true; - } - } - - ~SpaceNav() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } - - // This code added to correctly implement the disposable pattern. - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - #endregion - - #region Methods - public static SpaceNav Instance - { - get - { - if (instance == null) - { - instance = new SpaceNav(); - } - return instance; - } - } - - public void CloseDevice() - { - spnav_close(); - instance = null; - } - - public SpaceNavEvent WaitEvent() - { - SpNavEvent sev = new SpNavEvent(); - spnav_wait_event(ref sev); - switch (sev.type) - { - case SPNAV_EVENT_BUTTON: - return new SpaceNavButtonEvent(Convert.ToBoolean(sev.button.press), sev.button.bnum); - case SPNAV_EVENT_MOTION: - var ev = sev.motion; - return new SpaceNavMotionEvent(ev.x, ev.y, ev.z, ev.rx, ev.ry, ev.rz); - default: - return null; - } - } - - public SpaceNavEvent WaitEvent(int milliseconds) - { - SpNavEvent sev = new SpNavEvent(); - int ev_type = spnav_wait_event_timeout(ref sev, milliseconds); - switch (ev_type) - { - case SPNAV_EVENT_BUTTON: - return new SpaceNavButtonEvent(Convert.ToBoolean(sev.button.press), sev.button.bnum); - case SPNAV_EVENT_MOTION: - var ev = sev.motion; - return new SpaceNavMotionEvent(ev.x, ev.y, ev.z, ev.rx, ev.ry, ev.rz); - default: - return null; - } + private void HandleEvents(object obj) + { + // Block while the device isn't ready + while (!deviceReady) {} + Console.WriteLine("Device ready !"); + while (!isDisposed) + { + SpNavEvent sev = new SpNavEvent(); + int ev_type = spnav_wait_event(ref sev); + Console.WriteLine("Event type : {0}", sev.type); + switch (ev_type) + { + case SPNAV_EVENT_BUTTON: + //return new SpaceNavButtonEvent(Convert.ToBoolean(sev.button.press), sev.button.bnum); + Button(this, new EventArgs()); + break; + case SPNAV_EVENT_MOTION: + var ev = sev.motion; + Motion(this, new MotionEventArgs(ev.x, ev.y, ev.z, ev.rx, ev.ry, ev.rz)); + break; + } + } } public double Sensitivity { - get - { - return _sensitivity; - } - + get => _sensitivity; set { - // TODO : handle retcode - spnav_sensitivity(value); _sensitivity = value; + spnav_sensitivity(value); } } public int Threshold { - get - { - return _threshold; - } + get => _threshold; set { - // TODO : handle retcode - spnav_deadzone(value); _threshold = value; + spnav_deadzone(value); } } - #endregion + + public void Dispose() + { + if (!isDisposed) + { + CloseDevice(); + Button = null; + Motion = null; + } + isDisposed = true; + } + + private void CloseDevice() + { + // TODO : handle retcode and errors + spnav_close(); + } } } diff --git a/SpaceNavEvent.cs b/SpaceNavEvent.cs index ae53694..fd3ec4b 100644 --- a/SpaceNavEvent.cs +++ b/SpaceNavEvent.cs @@ -1,49 +1,37 @@ -namespace spnavwrapper +using System; + +namespace SpaceNavWrapper { - public abstract class SpaceNavEvent + public class MotionEventArgs : EventArgs { - } - - public class SpaceNavButtonEvent : SpaceNavEvent - { - public bool Pressed { get; } - public int Button { get; } - - public SpaceNavButtonEvent(bool pressed, int button) - { - Pressed = pressed; - Button = button; - } - - public override string ToString() - { - return "pressed=" + Pressed + " button=" + Button; - } - } - - public class SpaceNavMotionEvent : SpaceNavEvent - { - public int X { get; } - public int Y { get; } - public int Z { get; } - public int Rx { get; } - public int Ry { get; } - public int Rz { get; } - - public SpaceNavMotionEvent(int x, int y, int z, int rx, int ry, int rz) - { - X = x; - Y = y; - Z = z; - Rx = rx; - Ry = ry; - Rz = rz; - } - + public readonly int X, Y, Z; + public readonly int Rx, Ry, Rz; + + public MotionEventArgs(int x, int y, int z, int rx, int ry, int rz) + { + X = x; + Y = y; + Z = z; + Rx = rx; + Ry = ry; + Rz = rz; + } + public override string ToString() { return "x=" + X + " y=" + Y + " z=" + Z + " rx=" + Rz + " ry=" + Ry + " rz=" + Rz; } } + + public class ButtonEventArgs : EventArgs + { + public readonly int button; + public readonly bool pressed; + + public override string ToString() + { + return string.Format("[ButtonEventArgs: button={0}, pressed={1}]", button, pressed); + } + } }