Implemented thumbsticks and trigger caps
authorStefanos A <stapostol@gmail.com>
Tue, 24 Dec 2013 11:47:09 +0000 (12:47 +0100)
committerthefiddler <stapostol@gmail.com>
Tue, 24 Dec 2013 16:18:04 +0000 (17:18 +0100)
Source/OpenTK/Input/GamePadAxes.cs [new file with mode: 0644]
Source/OpenTK/Input/GamePadAxis.cs [deleted file]
Source/OpenTK/Input/GamePadCapabilities.cs
Source/OpenTK/Input/GamePadState.cs
Source/OpenTK/Input/GamePadType.cs
Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs
Source/OpenTK/Platform/Windows/WinMMJoystick.cs
Source/OpenTK/Platform/Windows/XInputJoystick.cs

diff --git a/Source/OpenTK/Input/GamePadAxes.cs b/Source/OpenTK/Input/GamePadAxes.cs
new file mode 100644 (file)
index 0000000..3ddea30
--- /dev/null
@@ -0,0 +1,41 @@
+//
+// GamePadAxis.cs
+//
+// Author:
+//       robert <${AuthorEmail}>
+//
+// Copyright (c) 2012 robert
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+namespace OpenTK.Input
+{
+    [Flags]
+    internal enum GamePadAxes : byte
+    {
+        LeftX = 1 << 0,
+        LeftY = 1 << 1,
+        LeftTrigger = 1 << 2,
+        RightX = 1 << 3,
+        RightY = 1 << 4,
+        RightTrigger = 1 << 5,
+    }
+}
+
diff --git a/Source/OpenTK/Input/GamePadAxis.cs b/Source/OpenTK/Input/GamePadAxis.cs
deleted file mode 100644 (file)
index f619ab6..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// GamePadAxis.cs
-//
-// Author:
-//       robert <${AuthorEmail}>
-//
-// Copyright (c) 2012 robert
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-
-namespace OpenTK.Input
-{
-    internal enum GamePadAxis
-    {
-        LeftX,
-        LeftY,
-        RightX,
-        RightY
-    }
-}
-
index c637f77129800c85d974b228b72036163f3a9ce7..2db7b612cc5435ba34b0bb7394813b92cb6f234f 100644 (file)
@@ -35,15 +35,17 @@ namespace OpenTK.Input
     public struct GamePadCapabilities : IEquatable<GamePadCapabilities>
     {
         Buttons buttons;
+        GamePadAxes axes;
         byte gamepad_type;
         bool is_connected;
 
         #region Constructors
 
-        public GamePadCapabilities(GamePadType type, Buttons buttons, bool is_connected)
+        internal GamePadCapabilities(GamePadType type, GamePadAxes axes, Buttons buttons, bool is_connected)
             : this()
         {
             gamepad_type = (byte)type;
+            this.axes = axes;
             this.buttons = buttons;
             this.is_connected = is_connected;
         }
@@ -134,32 +136,32 @@ namespace OpenTK.Input
 
         public bool HasLeftXThumbStick
         {
-            get { return false; }
+            get { return (axes & GamePadAxes.LeftX) != 0; }
         }
 
         public bool HasLeftYThumbStick
         {
-            get { return false; }
+            get { return (axes & GamePadAxes.LeftY) != 0; }
         }
 
         public bool HasRightXThumbStick
         {
-            get { return false; }
+            get { return (axes & GamePadAxes.RightX) != 0; }
         }
 
         public bool HasRightYThumbStick
         {
-            get { return false; }
+            get { return (axes & GamePadAxes.RightY) != 0; }
         }
 
         public bool HasLeftTrigger
         {
-            get { return false; }
+            get { return (axes & GamePadAxes.LeftTrigger) != 0; }
         }
 
         public bool HasRightTrigger
         {
-            get { return false; }
+            get { return (axes & GamePadAxes.RightTrigger) != 0; }
         }
 
         public bool HasLeftVibrationMotor
@@ -195,8 +197,11 @@ namespace OpenTK.Input
         public override string ToString()
         {
             return String.Format(
-                "{{Type: {0}; Buttons: {1}; Connected: {2}}}",
-                GamePadType, Convert.ToString((int)buttons, 2), IsConnected);
+                "{{Type: {0}; Axes: {1}; Buttons: {2}; Connected: {3}}}",
+                GamePadType,
+                Convert.ToString((int)axes, 2),
+                Convert.ToString((int)buttons, 2),
+                IsConnected);
         }
 
         public override int GetHashCode()
index 22111b5310d4e1eca94398205793eac6af66679f..bd196982546fe3e48f593439b8d8b6e470cd9be1 100644 (file)
@@ -62,6 +62,11 @@ namespace OpenTK.Input
             get { return new GamePadDPad(buttons); }
         }
 
+        public GamePadTriggers Triggers
+        {
+            get { return new GamePadTriggers(left_trigger, right_trigger); }
+        }
+
         public bool IsConnected
         {
             get { return is_connected; }
@@ -104,23 +109,23 @@ namespace OpenTK.Input
 
         #region Internal Members
 
-        internal void SetAxis(GamePadAxis axis, short value)
+        internal void SetAxis(GamePadAxes axis, short value)
         {
             switch (axis)
             {
-                case GamePadAxis.LeftX:
+                case GamePadAxes.LeftX:
                     left_stick_x = value;
                     break;
 
-                case GamePadAxis.LeftY:
+                case GamePadAxes.LeftY:
                     left_stick_y = value;
                     break;
 
-                case GamePadAxis.RightX:
+                case GamePadAxes.RightX:
                     right_stick_x = value;
                     break;
 
-                case GamePadAxis.RightY:
+                case GamePadAxes.RightY:
                     right_stick_y = value;
                     break;
 
@@ -146,11 +151,17 @@ namespace OpenTK.Input
             is_connected = connected;
         }
 
+        internal void SetTriggers(byte left, byte right)
+        {
+            left_trigger = left;
+            right_trigger = right;
+        }
+
         #endregion
 
         #region Private Members
 
-        bool IsAxisValid(GamePadAxis axis)
+        bool IsAxisValid(GamePadAxes axis)
         {
             int index = (int)axis;
             return index >= 0 && index < GamePad.MaxAxisCount;
index 1524e0242bca00869b9a38a9ca87147fe7ff870e..37311627e6fa37571dc99bad2f75fb51d20d89d4 100644 (file)
@@ -41,5 +41,7 @@ namespace OpenTK.Input
         BigButtonPad,
         DrumKit,
         GamePad,
+        ArcadePad,
+        BassGuitar,
     }
 }
index 701c38d6f9bbf4550ce919bc12d8003add118f3f..d5caa2c105a2b7957a29bf24da1edd7a1e1a9b35 100644 (file)
@@ -258,7 +258,7 @@ namespace OpenTK.Platform.SDL2
             int id = ev.Which;
             if (IsControllerValid(id))
             {
-                controllers[id].State.SetAxis((GamePadAxis)ev.Axis, ev.Value);
+                controllers[id].State.SetAxis((GamePadAxes)ev.Axis, ev.Value);
             }
             else
             {
index e7c7154199d3d04378f66654048041e6308076ba..1821b136782501ed47171f156c6590e991c55c2d 100644 (file)
@@ -470,10 +470,10 @@ namespace OpenTK.Platform.Windows
                 info.Flags = JoystickFlags.All;
                 UnsafeNativeMethods.joyGetPosEx(index, ref info);
 
-                state.SetAxis(GamePadAxis.LeftX, (short)info.XPos);
-                state.SetAxis(GamePadAxis.LeftY, (short)info.YPos);
-                state.SetAxis(GamePadAxis.RightX, (short)info.ZPos);
-                state.SetAxis(GamePadAxis.RightY, (short)info.RPos);
+                state.SetAxis(GamePadAxes.LeftX, (short)info.XPos);
+                state.SetAxis(GamePadAxes.LeftY, (short)info.YPos);
+                state.SetAxis(GamePadAxes.RightX, (short)info.ZPos);
+                state.SetAxis(GamePadAxes.RightY, (short)info.RPos);
                 //state.SetAxis(GamePadAxis.RightX, (short)info.ZPos);
                 //state.SetAxis(GamePadAxis.RightY, (short)info.RPos);
 
index c6d7def135efb31bae097587c81fb9c8e3e09be9..23710df0bdd8a1cd6e06b229dff03d1e312a1015 100644 (file)
@@ -33,41 +33,56 @@ using System.Text;
 using OpenTK.Input;
 using System.Runtime.InteropServices;
 using System.Security;
+using System.Diagnostics;
 
 namespace OpenTK.Platform.Windows
 {
-    class XInputJoystick : IGamePadDriver
+    class XInputJoystick : IGamePadDriver, IDisposable
     {
+        XInput xinput = new XInput();
+
         #region IGamePadDriver Members
 
         public GamePadState GetState(int index)
         {
             XInputState xstate;
-            XInput910.GetState((XInputUserIndex)index, out xstate);
+            XInputErrorCode error = xinput.GetState((XInputUserIndex)index, out xstate);
 
             GamePadState state = new GamePadState();
-            state.SetButton(Buttons.A, (xstate.GamePad.Buttons & XInputButtons.A) != 0);
-            state.SetButton(Buttons.B, (xstate.GamePad.Buttons & XInputButtons.B) != 0);
-            state.SetButton(Buttons.X, (xstate.GamePad.Buttons & XInputButtons.X) != 0);
-            state.SetButton(Buttons.Y, (xstate.GamePad.Buttons & XInputButtons.Y) != 0);
-            state.SetButton(Buttons.Start, (xstate.GamePad.Buttons & XInputButtons.Start) != 0);
-            state.SetButton(Buttons.Back, (xstate.GamePad.Buttons & XInputButtons.Back) != 0);
-            //state.SetButton(Buttons.BigButton, (xstate.GamePad.Buttons & XInputButtons.???) != 0);
-            state.SetButton(Buttons.LeftShoulder, (xstate.GamePad.Buttons & XInputButtons.LeftShoulder) != 0);
-            state.SetButton(Buttons.RightShoulder, (xstate.GamePad.Buttons & XInputButtons.RightShoulder) != 0);
-            state.SetButton(Buttons.LeftStick, (xstate.GamePad.Buttons & XInputButtons.LeftThumb) != 0);
-            state.SetButton(Buttons.RightStick, (xstate.GamePad.Buttons & XInputButtons.RightThumb) != 0);
-            state.SetButton(Buttons.DPadDown, (xstate.GamePad.Buttons & XInputButtons.DPadDown) != 0);
-            state.SetButton(Buttons.DPadUp, (xstate.GamePad.Buttons & XInputButtons.DPadUp) != 0);
-            state.SetButton(Buttons.DPadLeft, (xstate.GamePad.Buttons & XInputButtons.DPadLeft) != 0);
-            state.SetButton(Buttons.DPadRight, (xstate.GamePad.Buttons & XInputButtons.DPadRight) != 0);
+            if (error == XInputErrorCode.Success)
+            {
+                state.SetConnected(true);
+
+                state.SetAxis(GamePadAxes.LeftX, xstate.GamePad.ThumbLX);
+                state.SetAxis(GamePadAxes.LeftY, xstate.GamePad.ThumbLY);
+                state.SetAxis(GamePadAxes.RightX, xstate.GamePad.ThumbRX);
+                state.SetAxis(GamePadAxes.RightY, xstate.GamePad.ThumbRY);
+
+                state.SetTriggers(xstate.GamePad.LeftTrigger, xstate.GamePad.RightTrigger);
+
+                state.SetButton(TranslateButtons(xstate.GamePad.Buttons), true);
+            }
 
             return state;
         }
 
         public GamePadCapabilities GetCapabilities(int index)
         {
-            throw new NotImplementedException();
+            XInputDeviceCapabilities xcaps;
+            XInputErrorCode error = xinput.GetCapabilities(
+                (XInputUserIndex)index,
+                XInputCapabilitiesFlags.Default,
+                out xcaps);
+
+            if (error == XInputErrorCode.Success)
+            {
+                GamePadType type = TranslateSubType(xcaps.SubType);
+                Buttons buttons = TranslateButtons(xcaps.GamePad.Buttons);
+                GamePadAxes axes = TranslateAxes(ref xcaps.GamePad);
+
+                return new GamePadCapabilities(type, axes, buttons, true);
+            }
+            return new GamePadCapabilities();
         }
 
         public string GetName(int index)
@@ -78,6 +93,58 @@ namespace OpenTK.Platform.Windows
         #endregion
 
         #region Private Members
+        GamePadAxes TranslateAxes(ref XInputGamePad pad)
+        {
+            GamePadAxes axes = 0;
+            axes |= pad.ThumbLX != 0 ? GamePadAxes.LeftX : 0;
+            axes |= pad.ThumbLY != 0 ? GamePadAxes.LeftY : 0;
+            axes |= pad.LeftTrigger != 0 ? GamePadAxes.LeftTrigger : 0;
+            axes |= pad.ThumbRX != 0 ? GamePadAxes.RightX : 0;
+            axes |= pad.ThumbRY != 0 ? GamePadAxes.RightY : 0;
+            axes |= pad.RightTrigger != 0 ? GamePadAxes.RightTrigger : 0;
+            return axes;
+        }
+
+        Buttons TranslateButtons(XInputButtons xbuttons)
+        {
+            Buttons buttons = 0;
+            buttons |= (xbuttons & XInputButtons.A) != 0 ? Buttons.A : 0;
+            buttons |= (xbuttons & XInputButtons.B) != 0 ? Buttons.B : 0;
+            buttons |= (xbuttons & XInputButtons.X) != 0 ? Buttons.X : 0;
+            buttons |= (xbuttons & XInputButtons.Y) != 0 ? Buttons.Y : 0;
+            buttons |= (xbuttons & XInputButtons.Start) != 0 ? Buttons.Start : 0;
+            buttons |= (xbuttons & XInputButtons.Back) != 0 ? Buttons.Back : 0;
+            //buttons |= (xbuttons & XInputButtons.BigButton) != 0 ? Buttons.BigButton : 0;
+            buttons |= (xbuttons & XInputButtons.LeftShoulder) != 0 ? Buttons.LeftShoulder : 0;
+            buttons |= (xbuttons & XInputButtons.RightShoulder) != 0 ? Buttons.RightShoulder : 0;
+            buttons |= (xbuttons & XInputButtons.LeftThumb) != 0 ? Buttons.LeftStick : 0;
+            buttons |= (xbuttons & XInputButtons.RightThumb) != 0 ? Buttons.RightStick : 0;
+            buttons |= (xbuttons & XInputButtons.DPadDown) != 0 ? Buttons.DPadDown : 0;
+            buttons |= (xbuttons & XInputButtons.DPadUp) != 0 ? Buttons.DPadUp : 0;
+            buttons |= (xbuttons & XInputButtons.DPadLeft) != 0 ? Buttons.DPadLeft : 0;
+            buttons |= (xbuttons & XInputButtons.DPadRight) != 0 ? Buttons.DPadRight : 0;
+            return buttons;
+        }
+
+        GamePadType TranslateSubType(XInputDeviceSubType xtype)
+        {
+            switch (xtype)
+            {
+                case XInputDeviceSubType.ArcadePad: return GamePadType.ArcadePad;
+                case XInputDeviceSubType.ArcadeStick: return GamePadType.ArcadeStick;
+                case XInputDeviceSubType.DancePad: return GamePadType.DancePad;
+                case XInputDeviceSubType.DrumKit: return GamePadType.DrumKit;
+                case XInputDeviceSubType.FlightStick: return GamePadType.FlightStick;
+                case XInputDeviceSubType.GamePad: return GamePadType.GamePad;
+                case XInputDeviceSubType.Guitar: return GamePadType.Guitar;
+                case XInputDeviceSubType.GuitarAlternate: return GamePadType.AlternateGuitar;
+                case XInputDeviceSubType.GuitarBass: return GamePadType.BassGuitar;
+                case XInputDeviceSubType.Wheel: return GamePadType.Wheel;
+                case XInputDeviceSubType.Unknown:
+                default:
+                    return GamePadType.Unknown;
+            }
+        }
 
         enum XInputErrorCode
         {
@@ -85,12 +152,12 @@ namespace OpenTK.Platform.Windows
             DeviceNotConnected
         }
 
-        enum XInputType
+        enum XInputDeviceType : byte
         {
             GamePad
         }
 
-        enum XInputSubType
+        enum XInputDeviceSubType : byte
         {
             Unknown = 0,
             GamePad = 1,
@@ -107,10 +174,10 @@ namespace OpenTK.Platform.Windows
 
         enum XInputCapabilities
         {
-            Ffb = 0x0001,
+            ForceFeedback = 0x0001,
             Wireless = 0x0002,
             Voice = 0x0004,
-            Pmd = 0x0008,
+            PluginModules = 0x0008,
             NoNavigation = 0x0010,
         }
 
@@ -197,8 +264,8 @@ namespace OpenTK.Platform.Windows
 
         struct XInputDeviceCapabilities
         {
-            public byte Type;
-            public byte SubType;
+            public XInputDeviceType Type;
+            public XInputDeviceSubType SubType;
             public short Flags;
             public XInputGamePad GamePad;
             public XInputVibration Vibration;
@@ -210,89 +277,123 @@ namespace OpenTK.Platform.Windows
             public XInputBatteryLevel Level;
         }
 
-        static class XInput910
+        class XInput : IDisposable
         {
-            const string dll = "XINPUT9_1_0";
+            IntPtr dll;
+
+            internal XInput()
+            {
+                // Try to load the newest XInput***.dll installed on the system
+                // The delegates below will be loaded dynamically from that dll
+                dll = Functions.LoadLibrary("XINPUT1_4");
+                if (dll == IntPtr.Zero)
+                    dll = Functions.LoadLibrary("XINPUT1_3");
+                if (dll == IntPtr.Zero)
+                    dll = Functions.LoadLibrary("XINPUT1_2");
+                if (dll == IntPtr.Zero)
+                    dll = Functions.LoadLibrary("XINPUT1_1");
+                if (dll == IntPtr.Zero)
+                    dll = Functions.LoadLibrary("XINPUT9_1_0");
+                if (dll == IntPtr.Zero)
+                    throw new NotSupportedException("XInput was not found on this platform");
+
+                // Load the entry points we are interested in from that dll
+                GetCapabilities = (XInputGetCapabilities)Load("XInputGetCapabilities", typeof(XInputGetCapabilities));
+                GetState = (XInputGetState)Load("XInputGetState", typeof(XInputGetState));
+                SetState = (XInputSetState)Load("XInputSetState", typeof(XInputSetState));
+            }
+
+            #region Private Members
+
+            Delegate Load(string name, Type type)
+            {
+                IntPtr pfunc = Functions.GetProcAddress(dll, name);
+                if (pfunc != IntPtr.Zero)
+                    return Marshal.GetDelegateForFunctionPointer(pfunc, type);
+                return null;
+            }
+
+            #endregion
+
+            #region Internal Members
+
+            internal XInputGetCapabilities GetCapabilities;
+            internal XInputGetState GetState;
+            internal XInputSetState SetState;
 
             [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode GetCapabilities(
+            internal delegate XInputErrorCode XInputGetCapabilities(
                 XInputUserIndex dwUserIndex,
                 XInputCapabilitiesFlags dwFlags,
-                ref XInputDeviceCapabilities pCapabilities);
+                out XInputDeviceCapabilities pCapabilities);
 
             [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode GetState
+            internal delegate XInputErrorCode XInputGetState
             (
                 XInputUserIndex dwUserIndex,
                 out XInputState pState
             );
 
             [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode SetState
+            internal delegate XInputErrorCode XInputSetState
             (
                 XInputUserIndex dwUserIndex,
                 ref XInputVibration pVibration
             );
-        }
 
-        static class XInput13
-        {
-            const string dll = "XINPUT1_3";
+            #endregion
+
+            #region IDisposable Members
+
+            public void Dispose()
+            {
+                Dispose(true);
+                GC.SuppressFinalize(this);
+            }
+
+            void Dispose(bool manual)
+            {
+                if (manual)
+                {
+                    if (dll != IntPtr.Zero)
+                    {
+                        Functions.FreeLibrary(dll);
+                        dll = IntPtr.Zero;
+                    }
+                }
+            }
+
+            #endregion
+        }
 
-            [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode GetCapabilities(
-                XInputUserIndex dwUserIndex,
-                XInputCapabilitiesFlags dwFlags,
-                ref XInputDeviceCapabilities pCapabilities);
+        #endregion
 
-            [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode GetState
-            (
-                XInputUserIndex dwUserIndex,
-                out XInputState pState
-            );
+        #region IDisposable Members
 
-            [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode SetState
-            (
-                XInputUserIndex dwUserIndex,
-                ref XInputVibration pVibration
-            );
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
         }
 
-        static class XInput14
+        void Dispose(bool manual)
         {
-            const string dll = "XINPUT1_4";
-
-            [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode GetCapabilities(
-                XInputUserIndex dwUserIndex,
-                XInputCapabilitiesFlags dwFlags,
-                ref XInputDeviceCapabilities pCapabilities);
-
-            [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode GetState
-            (
-                XInputUserIndex dwUserIndex,
-                out XInputState pState
-            );
+            if (manual)
+            {
+                xinput.Dispose();
+            }
+            else
+            {
+                Debug.Print("{0} leaked, did you forget to call Dispose()?", typeof(XInputJoystick).Name);
+            }
+        }
 
-            [SuppressUnmanagedCodeSecurity]
-            [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)]
-            public static extern XInputErrorCode SetState
-            (
-                XInputUserIndex dwUserIndex,
-                ref XInputVibration pVibration
-            );
+#if DEBUG
+        ~XInputJoystick()
+        {
+            Dispose(false);
         }
+#endif
 
         #endregion
     }