diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..70d3d6a --- /dev/null +++ b/Program.cs @@ -0,0 +1,10 @@ +using System; +namespace spnavcsharpwrapper +{ + class Program + { + static void Main(string[] args) + { + } + } +} diff --git a/SpaceNav.cs b/SpaceNav.cs new file mode 100644 index 0000000..62a955e --- /dev/null +++ b/SpaceNav.cs @@ -0,0 +1,167 @@ +using System; +using System.Runtime.InteropServices; + +namespace spnavwrapper +{ + public sealed class SpaceNav + { + double _sensitivity = 1.0; + int _threshold = 5; + + static SpaceNav instance = null; + static readonly object padlock = new object(); + + const int SPNAV_EVENT_MOTION = 1; + const int SPNAV_EVENT_BUTTON = 2; + const ushort SPNAV_VENDOR_ID = 0x046d; + const ushort SPNAV_PRODUCT_ID = 0x0c627; + + const string DLL_NAME = "spnavhdi"; + + struct SpNavEventMotion + { + public int type; + public int x, y, z; + public int rx, ry, rz; + public uint period; + public IntPtr data; + } + + struct SpNavEventButton + { + public int type; + public int press; + public int bnum; + } + + [StructLayout(LayoutKind.Explicit)] + struct SpNavEvent + { + [FieldOffset(0)] public int type; + [FieldOffset(0)] public SpNavEventMotion motion; + [FieldOffset(0)] public SpNavEventButton button; + } + + [DllImport(DLL_NAME)] + static extern int spnav_open(ushort vendor_id, ushort product_id); + [DllImport(DLL_NAME)] + static extern int spnav_close(); + [DllImport(DLL_NAME)] + static extern int spnav_wait_event(ref SpNavEvent ev); + [DllImport(DLL_NAME)] + static extern int spnav_wait_event_timeout(ref SpNavEvent ev, int timeout); + [DllImport(DLL_NAME)] + static extern int spnav_sensitivity(double sens); + [DllImport(DLL_NAME)] + static extern int spnav_deadzone(int threshold); + + SpaceNav() + { + // TODO : handle retcode + spnav_open(SPNAV_VENDOR_ID, SPNAV_PRODUCT_ID); + } + + ~SpaceNav() + { + // TODO : handle retcode + spnav_close(); + } + + public static SpaceNav Instance + { + get + { + lock (padlock) + { + if (instance == null) + { + instance = new SpaceNav(); + } + return instance; + } + } + } + + public void CloseDevice() + { + lock (padlock) + { + spnav_close(); + instance = null; + } + } + + public SpaceNavEvent WaitEvent() + { + lock (padlock) + { + 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) + { + lock (padlock) + { + 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; + } + } + } + + public double Sensitivity + { + get + { + return _sensitivity; + } + + set + { + lock (padlock) + { + // TODO : handle retcode + spnav_sensitivity(value); + _sensitivity = value; + } + } + } + + public int Threshold + { + get + { + return _threshold; + } + set + { + lock (padlock) + { + // TODO : handle retcode + spnav_deadzone(value); + _threshold = value; + } + } + } + } +} diff --git a/SpaceNavEvent.cs b/SpaceNavEvent.cs new file mode 100644 index 0000000..ae53694 --- /dev/null +++ b/SpaceNavEvent.cs @@ -0,0 +1,49 @@ +namespace spnavwrapper +{ + public abstract class SpaceNavEvent + { + } + + 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 override string ToString() + { + return "x=" + X + " y=" + Y + " z=" + Z + + " rx=" + Rz + " ry=" + Ry + " rz=" + Rz; + } + } +} diff --git a/spnav-csharp-wrapper.csproj b/spnav-csharp-wrapper.csproj new file mode 100644 index 0000000..ae1abf0 --- /dev/null +++ b/spnav-csharp-wrapper.csproj @@ -0,0 +1,35 @@ + + + + Debug + x86 + {BC0B9CC5-C678-4DBF-AA73-FD98C1D6BF60} + Exe + spnavcsharpwrapper + spnav-csharp-wrapper + v4.7 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + x86 + + + true + bin\Release + prompt + 4 + x86 + + + + + + + + \ No newline at end of file diff --git a/spnav-csharp-wrapper.sln b/spnav-csharp-wrapper.sln new file mode 100644 index 0000000..16137f6 --- /dev/null +++ b/spnav-csharp-wrapper.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spnav-csharp-wrapper", "spnav-csharp-wrapper.csproj", "{BC0B9CC5-C678-4DBF-AA73-FD98C1D6BF60}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BC0B9CC5-C678-4DBF-AA73-FD98C1D6BF60}.Debug|x86.ActiveCfg = Debug|x86 + {BC0B9CC5-C678-4DBF-AA73-FD98C1D6BF60}.Debug|x86.Build.0 = Debug|x86 + {BC0B9CC5-C678-4DBF-AA73-FD98C1D6BF60}.Release|x86.ActiveCfg = Release|x86 + {BC0B9CC5-C678-4DBF-AA73-FD98C1D6BF60}.Release|x86.Build.0 = Release|x86 + EndGlobalSection +EndGlobal