[Win] Completed raw input IJoystickDriver2
authorStefanos A <stapostol@gmail.com>
Sat, 18 Jan 2014 15:00:27 +0000 (16:00 +0100)
committerthefiddler <stapostol@gmail.com>
Thu, 11 Sep 2014 10:51:47 +0000 (12:51 +0200)
For improved safety, we are now using managed memory buffers instead of
stack allocations and pointers.

Source/OpenTK/Platform/Windows/API.cs
Source/OpenTK/Platform/Windows/Bindings/HidProtocol.cs
Source/OpenTK/Platform/Windows/WinFactory.cs
Source/OpenTK/Platform/Windows/WinRawInput.cs
Source/OpenTK/Platform/Windows/WinRawJoystick.cs
Source/OpenTK/Platform/Windows/WinRawKeyboard.cs
Source/OpenTK/Platform/Windows/WinRawMouse.cs

index 41248c3..fe17602 100644 (file)
@@ -1500,22 +1500,22 @@ namespace OpenTK.Platform.Windows
         /// <para>If Data is not large enough for the data, the function returns -1. If Data is NULL, the function returns a value of zero. In both of these cases, Size is set to the minimum size required for the Data buffer.</para>
         /// <para>Call GetLastError to identify any other errors.</para>
         /// </returns>
-        [CLSCompliant(false)]
         [System.Security.SuppressUnmanagedCodeSecurity]
         [DllImport("user32.dll", SetLastError = true)]
-        internal static extern UINT GetRawInputDeviceInfo(
+        internal static extern INT GetRawInputDeviceInfo(
             HANDLE Device,
             [MarshalAs(UnmanagedType.U4)] RawInputDeviceInfoEnum Command,
             [In, Out] LPVOID Data,
-            [In, Out] ref UINT Size
+            [In, Out] ref INT Size
         );
 
+        [CLSCompliant(false)]
         [System.Security.SuppressUnmanagedCodeSecurity]
         [DllImport("user32.dll", SetLastError = true)]
         internal static extern INT GetRawInputDeviceInfo(
             HANDLE Device,
             [MarshalAs(UnmanagedType.U4)] RawInputDeviceInfoEnum Command,
-            [In, Out] LPVOID Data,
+            [In, Out] byte[] Data,
             [In, Out] ref INT Size
         );
 
@@ -2791,7 +2791,7 @@ namespace OpenTK.Platform.Windows
         /// <summary>
         /// Size, in bytes, of the RawInputDeviceInfo structure.
         /// </summary>
-        DWORD Size = Marshal.SizeOf(typeof(RawInputDeviceInfo)); 
+        internal DWORD Size = Marshal.SizeOf(typeof(RawInputDeviceInfo)); 
         /// <summary>
         /// Type of raw input data.
         /// </summary>
index ce4f34f..75a5122 100644 (file)
@@ -43,38 +43,54 @@ namespace OpenTK.Platform.Windows
         [SuppressUnmanagedCodeSecurity]
         [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetButtonCaps")]
         public static extern HidProtocolStatus GetButtonCaps(HidProtocolReportType hidProtocolReportType,
-            IntPtr button_caps, ref ushort p, IntPtr preparsed_data);
+            IntPtr button_caps, ref ushort p, byte[] preparsed_data);
+
+        [SuppressUnmanagedCodeSecurity]
+        [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetButtonCaps")]
+        public static extern HidProtocolStatus GetButtonCaps(HidProtocolReportType hidProtocolReportType,
+            HidProtocolButtonCaps[] button_caps, ref ushort p, byte[] preparsed_data);
 
         [SuppressUnmanagedCodeSecurity]
         [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetCaps")]
-        public static extern HidProtocolStatus GetCaps(IntPtr preparsed_data, ref HidProtocolCaps capabilities);
+        public static extern HidProtocolStatus GetCaps(byte[] preparsed_data, ref HidProtocolCaps capabilities);
 
         [SuppressUnmanagedCodeSecurity]
         [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetData")]
         public static extern HidProtocolStatus GetData(HidProtocolReportType type,
             IntPtr data, ref int data_length,
-            IntPtr preparsed_data, IntPtr report, int report_length);
+            byte[] preparsed_data, IntPtr report, int report_length);
+
+        [SuppressUnmanagedCodeSecurity]
+        [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetData")]
+        public static extern HidProtocolStatus GetData(HidProtocolReportType type,
+            HidProtocolData[] data, ref int data_length,
+            byte[] preparsed_data, IntPtr report, int report_length);
 
         [SuppressUnmanagedCodeSecurity]
         [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetScaledUsageValue")]
         static public extern HidProtocolStatus GetScaledUsageValue(HidProtocolReportType type,
             HIDPage usage_page, short link_collection, short usage, ref int usage_value,
-            IntPtr preparsed_data, IntPtr report, int report_length);
+            byte[] preparsed_data, IntPtr report, int report_length);
 
         [SuppressUnmanagedCodeSecurity]
         [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetUsageValue")]
         public static extern HidProtocolStatus GetUsageValue(HidProtocolReportType type,
             HIDPage usage_page, short link_collection, short usage, ref uint usage_value,
-            IntPtr preparsed_data, IntPtr report, int report_length);
+            byte[] preparsed_data, IntPtr report, int report_length);
+
+        [SuppressUnmanagedCodeSecurity]
+        [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetValueCaps")]
+        public static extern HidProtocolStatus GetValueCaps(HidProtocolReportType type,
+            IntPtr caps, ref ushort caps_length, byte[] preparsed_data);
 
         [SuppressUnmanagedCodeSecurity]
         [DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetValueCaps")]
-        public static extern HidProtocolStatus GetValueCaps(HidProtocolReportType type, IntPtr caps,
-            ref ushort caps_length, IntPtr preparsed_data);
+        public static extern HidProtocolStatus GetValueCaps(HidProtocolReportType type,
+            HidProtocolValueCaps[] caps, ref ushort caps_length, byte[] preparsed_data);
 
         [SuppressUnmanagedCodeSecurity]
         [DllImport(lib, SetLastError = true, EntryPoint = "HidP_MaxDataListLength")]
-        public static extern int MaxDataListLength(HidProtocolReportType type, IntPtr preparsed_data);
+        public static extern int MaxDataListLength(HidProtocolReportType type, byte[] preparsed_data);
     }
 
     enum HidProtocolReportType : ushort
index 978c0d1..d09b4de 100644 (file)
@@ -45,7 +45,6 @@ namespace OpenTK.Platform.Windows
         // WinFactory constructor has finished running. The reason is
         // that they call WinFactory methods internally.
         WinRawInput rawinput_driver; // For keyboard and mouse input
-        WinCombinedJoystick joystick_driver; // For joystick input
 
         internal static IntPtr OpenGLHandle { get; private set; }
         const string OpenGLName = "OPENGL32.DLL";
@@ -132,7 +131,7 @@ namespace OpenTK.Platform.Windows
 
         public override IJoystickDriver2 CreateJoystickDriver()
         {
-            return CombinedJoystickDriver;
+            return RawInputDriver.JoystickDriver;
         }
 
         #endregion
@@ -154,22 +153,6 @@ namespace OpenTK.Platform.Windows
             }
         }
 
-        WinCombinedJoystick CombinedJoystickDriver
-        {
-            get
-            {
-                lock (SyncRoot)
-                {
-                    if (joystick_driver == null)
-                    {
-                        joystick_driver = new WinCombinedJoystick(
-                            new XInputJoystick(), new WinMMJoystick());
-                    }
-                    return joystick_driver;
-                }
-            }
-        }
-
         #endregion
 
         #region IDisposable Members
@@ -181,7 +164,6 @@ namespace OpenTK.Platform.Windows
                 if (manual)
                 {
                     rawinput_driver.Dispose();
-                    joystick_driver.Dispose();
                 }
 
                 base.Dispose(manual);
index 2bdd305..d262e4b 100644 (file)
@@ -89,48 +89,59 @@ namespace OpenTK.Platform.Windows
         protected unsafe override IntPtr WindowProcedure(
             IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
         {
-            switch (message)
+            try
             {
-                case WindowMessage.INPUT:
-                    int size = 0;
-                    // Get the size of the input buffer
-                    Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
-                        IntPtr.Zero, ref size, API.RawInputHeaderSize);
-
-                    void* data_ptr = stackalloc byte[size];
-                    RawInput* data = (RawInput*)data_ptr;
-
-                    // Read the actual raw input structure
-                    if (size == Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
-                        (IntPtr)data_ptr, ref size, API.RawInputHeaderSize))
-                    {
-                        switch (data->Header.Type)
+                switch (message)
+                {
+                    case WindowMessage.INPUT:
+                        int size = 0;
+
+#if false
+                        // Get the size of the input buffer
+                        Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
+                            IntPtr.Zero, ref size, API.RawInputHeaderSize);
+
+                        void* data_ptr = stackalloc byte[size];
+                        RawInput* data = (RawInput*)data_ptr;
+#endif
+                        RawInput data;
+                        // Read the actual raw input structure
+                        if (size == Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
+                            out data, ref size, API.RawInputHeaderSize))
                         {
-                            case RawInputDeviceType.KEYBOARD:
-                                if (((WinRawKeyboard)KeyboardDriver).ProcessKeyboardEvent(ref *data))
-                                    return IntPtr.Zero;
-                                break;
-
-                            case RawInputDeviceType.MOUSE:
-                                if (((WinRawMouse)MouseDriver).ProcessMouseEvent(ref *data))
-                                    return IntPtr.Zero;
-                                break;
-
-                            case RawInputDeviceType.HID:
-                                if (((WinRawJoystick)JoystickDriver).ProcessEvent(data))
-                                    return IntPtr.Zero;
-                                break;
+                            switch (data.Header.Type)
+                            {
+                                case RawInputDeviceType.KEYBOARD:
+                                    if (((WinRawKeyboard)KeyboardDriver).ProcessKeyboardEvent(ref data))
+                                        return IntPtr.Zero;
+                                    break;
+
+                                case RawInputDeviceType.MOUSE:
+                                    if (((WinRawMouse)MouseDriver).ProcessMouseEvent(ref data))
+                                        return IntPtr.Zero;
+                                    break;
+
+                                case RawInputDeviceType.HID:
+                                    if (((WinRawJoystick)JoystickDriver).ProcessEvent(ref data))
+                                        return IntPtr.Zero;
+                                    break;
+                            }
                         }
-                    }
-                    break;
-
-                case WindowMessage.DEVICECHANGE:
-                    ((WinRawKeyboard)KeyboardDriver).RefreshDevices();
-                    ((WinRawMouse)MouseDriver).RefreshDevices();
-                    ((WinRawJoystick)JoystickDriver).RefreshDevices();
-                    break;
+                        break;
+
+                    case WindowMessage.DEVICECHANGE:
+                        ((WinRawKeyboard)KeyboardDriver).RefreshDevices();
+                        ((WinRawMouse)MouseDriver).RefreshDevices();
+                        ((WinRawJoystick)JoystickDriver).RefreshDevices();
+                        break;
+                }
+                return base.WindowProcedure(handle, message, wParam, lParam);
+            }
+            catch (Exception e)
+            {
+                Debug.Print("[WinRawInput] Caught unhandled exception {0}", e);
+                return IntPtr.Zero;
             }
-            return base.WindowProcedure(handle, message, wParam, lParam);
         }
 
         #endregion
index 0bf9580..787ffde 100644 (file)
@@ -76,6 +76,12 @@ namespace OpenTK.Platform.Windows
                 State.SetButton(button, value);
             }
 
+            public void SetConnected(bool value)
+            {
+                Capabilities.SetIsConnected(value);
+                State.SetIsConnected(value);
+            }
+
             public JoystickCapabilities GetCapabilities()
             {
                 return Capabilities;
@@ -134,6 +140,11 @@ namespace OpenTK.Platform.Windows
         readonly Dictionary<int, IntPtr> IndexToDevice =
             new Dictionary<int, IntPtr>();
 
+        byte[] PreparsedData = new byte[1024];
+        HidProtocolValueCaps[] AxisCaps = new HidProtocolValueCaps[4];
+        HidProtocolButtonCaps[] ButtonCaps = new HidProtocolButtonCaps[4];
+        HidProtocolData[] DataBuffer = new HidProtocolData[16];
+
         public WinRawJoystick(IntPtr window)
         {
             Debug.WriteLine("Using WinRawJoystick.");
@@ -148,6 +159,17 @@ namespace OpenTK.Platform.Windows
                 new RawInputDevice(HIDUsageGD.Joystick, RawInputDeviceFlags.INPUTSINK, window),
                 new RawInputDevice(HIDUsageGD.GamePad, RawInputDeviceFlags.INPUTSINK, window),
             };
+
+            if (!Functions.RegisterRawInputDevices(DeviceTypes, DeviceTypes.Length, API.RawInputDeviceSize))
+            {
+                Debug.Print("[Warning] Raw input registration failed with error: {0}.",
+                    Marshal.GetLastWin32Error());
+            }
+            else
+            {
+                Debug.Print("[WinRawJoystick] Registered for raw input");
+            }
+
             RefreshDevices();
 
             Debug.Unindent();
@@ -157,20 +179,34 @@ namespace OpenTK.Platform.Windows
 
         public void RefreshDevices()
         {
-            if (!Functions.RegisterRawInputDevices(DeviceTypes, DeviceTypes.Length, API.RawInputDeviceSize))
+            // Mark all devices as disconnected. We will check which of those
+            // are connected later on.
+            for (int i = 0; i < IndexToDevice.Count; i++)
             {
-                Debug.Print("[Warning] Raw input registration failed with error: {0}.",
-                    Marshal.GetLastWin32Error());
+                Devices[IndexToDevice[i]].SetConnected(false);
             }
-            else
+
+            foreach (RawInputDeviceList dev in WinRawInput.GetDeviceList())
             {
-                Debug.Print("Registered for raw joystick input");
+                if (dev.Type != RawInputDeviceType.HID)
+                    continue;
+
+                IntPtr handle = dev.Device;
+                Guid guid = GetDeviceGuid(handle);
+                JoystickCapabilities caps = GetDeviceCaps(handle);
+
+                if (!Devices.ContainsKey(handle))
+                    Devices.Add(handle, new Device(handle, guid, caps));
+                
+                Device stick = Devices[handle];
+                stick.SetConnected(true);
             }
+
         }
 
-        public unsafe bool ProcessEvent(RawInput* rin)
+        public unsafe bool ProcessEvent(ref RawInput rin)
         {
-            IntPtr handle = rin->Header.Device;
+            IntPtr handle = rin.Header.Device;
             Device stick = GetDevice(handle);
             if (stick == null)
             {
@@ -178,39 +214,175 @@ namespace OpenTK.Platform.Windows
                 return false;
             }
 
+            if (!GetPreparsedData(handle, ref PreparsedData))
+            {
+                return false;
+            }
+
+            HidProtocolCaps caps;
+            if (!GetDeviceCaps(PreparsedData, out caps, ref AxisCaps, ref ButtonCaps))
+            {
+                return false;
+            }
+
+            // Query current state
+            // Allocate enough storage to hold the data of the current report
+            int size = HidProtocol.MaxDataListLength(HidProtocolReportType.Input, PreparsedData);
+            if (size == 0)
+            {
+                Debug.Print("[WinRawJoystick] HidProtocol.MaxDataListLength() failed with {0}",
+                    Marshal.GetLastWin32Error());
+                return false;
+            }
+
+            // Fill the data buffer
+            if (DataBuffer.Length < size)
+            {
+                Array.Resize(ref DataBuffer, size);
+            }
+
+            fixed (void* pdata = &rin.Data.HID.RawData)
+            {
+                if (HidProtocol.GetData(HidProtocolReportType.Input,
+                    DataBuffer, ref size, PreparsedData,
+                    (IntPtr)pdata, rin.Data.HID.Size) != HidProtocolStatus.Success)
+                {
+                    Debug.Print("[WinRawJoystick] HidProtocol.GetData() failed with {0}",
+                        Marshal.GetLastWin32Error());
+                    return false;
+                }
+            }
+
+            UpdateAxes(stick, caps, AxisCaps, DataBuffer);
+            UpdateButtons(stick, caps, ButtonCaps, DataBuffer);
+
+            return true;
+        }
+
+        static bool GetPreparsedData(IntPtr handle, ref byte[] prepared_data)
+        {
             // Query the size of the _HIDP_PREPARSED_DATA structure for this event.
             int preparsed_size = 0;
-            Functions.GetRawInputDeviceInfo(rin->Header.Device, RawInputDeviceInfoEnum.PREPARSEDDATA,
+            Functions.GetRawInputDeviceInfo(handle, RawInputDeviceInfoEnum.PREPARSEDDATA,
                 IntPtr.Zero, ref preparsed_size);
             if (preparsed_size == 0)
+            {
+                Debug.Print("[WinRawJoystick] Functions.GetRawInputDeviceInfo(PARSEDDATA) failed with {0}",
+                    Marshal.GetLastWin32Error());
                 return false;
+            }
 
             // Allocate space for _HIDP_PREPARSED_DATA.
             // This is an untyped blob of data.
-            void* preparsed_data_ptr = stackalloc byte[preparsed_size];
-            IntPtr preparsed_data = (IntPtr)preparsed_data_ptr;
-            if (Functions.GetRawInputDeviceInfo(rin->Header.Device, RawInputDeviceInfoEnum.PREPARSEDDATA,
-                preparsed_data, ref preparsed_size) < 0)
+            if (prepared_data.Length < preparsed_size)
+            {
+                Array.Resize(ref prepared_data, preparsed_size);
+            }
+
+            if (Functions.GetRawInputDeviceInfo(handle, RawInputDeviceInfoEnum.PREPARSEDDATA,
+                prepared_data, ref preparsed_size) < 0)
+            {
+                Debug.Print("[WinRawJoystick] Functions.GetRawInputDeviceInfo(PARSEDDATA) failed with {0}",
+                    Marshal.GetLastWin32Error());
                 return false;
+            }
+
+            return true;
+        }
+
+        JoystickCapabilities GetDeviceCaps(IntPtr handle)
+        {
+            HidProtocolCaps caps;
+            if (GetPreparsedData(handle, ref PreparsedData) &&
+                GetDeviceCaps(PreparsedData, out caps, ref AxisCaps, ref ButtonCaps))
+            {
+                int axes = 0;
+                int dpads = 0;
+                int buttons = 0;
+                for (int i = 0; i < caps.NumberInputValueCaps; i++)
+                {
+                    if (AxisCaps[i].IsRange)
+                        continue; // Todo: range values not currently supported
+
+                    switch (AxisCaps[i].UsagePage)
+                    {
+                        case HIDPage.GenericDesktop:
+                            switch ((HIDUsageGD)AxisCaps[i].NotRange.Usage)
+                            {
+                                case HIDUsageGD.X:
+                                case HIDUsageGD.Y:
+                                case HIDUsageGD.Z:
+                                case HIDUsageGD.Rx:
+                                case HIDUsageGD.Ry:
+                                case HIDUsageGD.Rz:
+                                case HIDUsageGD.Slider:
+                                case HIDUsageGD.Dial:
+                                case HIDUsageGD.Wheel:
+                                    axes++;
+                                    break;
+
+                                case HIDUsageGD.Hatswitch:
+                                    dpads++;
+                                    break;
+                            }
+                            break;
+
+                        case HIDPage.Simulation:
+                            switch ((HIDUsageSim)AxisCaps[i].NotRange.Usage)
+                            {
+                                case HIDUsageSim.Rudder:
+                                case HIDUsageSim.Throttle:
+                                    axes++;
+                                    break;
+                            }
+                            break;
+
+                        case HIDPage.Button:
+                            buttons++;
+                            break;
+                    }
+                }
+
+                return new JoystickCapabilities(axes, buttons, true);
+            }
+            return new JoystickCapabilities();
+        }
 
+        static bool GetDeviceCaps(byte[] preparsed_data, out HidProtocolCaps caps,
+            ref HidProtocolValueCaps[] axes, ref HidProtocolButtonCaps[] buttons)
+        {
             // Query joystick capabilities
-            HidProtocolCaps caps = new HidProtocolCaps();
+            caps = new HidProtocolCaps();
             if (HidProtocol.GetCaps(preparsed_data, ref caps) != HidProtocolStatus.Success)
+            {
+                Debug.Print("[WinRawJoystick] HidProtocol.GetCaps() failed with {0}",
+                    Marshal.GetLastWin32Error());
                 return false;
+            }
+
+            // Make sure our caps arrays are big enough
+            if (axes.Length < caps.NumberInputValueCaps)
+            {
+                Array.Resize(ref axes, caps.NumberInputValueCaps);
+            }
+            if (buttons.Length < caps.NumberInputButtonCaps)
+            {
+                Array.Resize(ref buttons, caps.NumberInputButtonCaps);
+            }
 
             // Axis capabilities
-            HidProtocolValueCaps* axes_caps = stackalloc HidProtocolValueCaps[caps.NumberInputValueCaps];
             if (HidProtocol.GetValueCaps(HidProtocolReportType.Input,
-                (IntPtr)axes_caps, ref caps.NumberInputValueCaps, preparsed_data) !=
+                axes, ref caps.NumberInputValueCaps, preparsed_data) !=
                 HidProtocolStatus.Success)
             {
+                Debug.Print("[WinRawJoystick] HidProtocol.GetValueCaps() failed with {0}",
+                    Marshal.GetLastWin32Error());
                 return false;
             }
 
             // Button capabilities
-            HidProtocolButtonCaps* button_caps = stackalloc HidProtocolButtonCaps[caps.NumberInputButtonCaps];
             if (HidProtocol.GetButtonCaps(HidProtocolReportType.Input,
-                (IntPtr)button_caps, ref caps.NumberInputButtonCaps, preparsed_data) !=
+                buttons, ref caps.NumberInputButtonCaps, preparsed_data) !=
                 HidProtocolStatus.Success)
             {
                 Debug.Print("[WinRawJoystick] HidProtocol.GetButtonCaps() failed with {0}",
@@ -218,48 +390,64 @@ namespace OpenTK.Platform.Windows
                 return false;
             }
 
-            // Query current state
-            // Allocate enough storage to hold the data of the current report
-            int size = HidProtocol.MaxDataListLength(HidProtocolReportType.Input, preparsed_data);
-            if (size == 0)
-            {
-                Debug.Print("[WinRawJoystick] HidProtocol.MaxDataListLength() failed with {0}",
-                    Marshal.GetLastWin32Error());
-                return false;
-            }
+            return true;
+        }
 
-            // Fill the data buffer
-            HidProtocolData* data = stackalloc HidProtocolData[size];
-            if (HidProtocol.GetData(HidProtocolReportType.Input,
-                (IntPtr)data, ref size, preparsed_data,
-                new IntPtr(&rin->Data.HID.RawData), rin->Data.HID.Size) != HidProtocolStatus.Success)
+        // Retrieves the GUID of a device, which is stored
+        // in the last part of the DEVICENAME string
+        Guid GetDeviceGuid(IntPtr handle)
+        {
+            Guid guid = new Guid();
+
+            unsafe
             {
-                Debug.Print("[WinRawJoystick] HidProtocol.GetData() failed with {0}",
-                    Marshal.GetLastWin32Error());
-                return false;
-            }
+                // Find out how much memory we need to allocate
+                // for the DEVICENAME string
+                int size = 0;
+                if (Functions.GetRawInputDeviceInfo(handle, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size) < 0 || size == 0)
+                {
+                    Debug.Print("[WinRawJoystick] Functions.GetRawInputDeviceInfo(DEVICENAME) failed with error {0}",
+                        Marshal.GetLastWin32Error());
+                    return guid;
+                }
+
+                // Allocate memory and retrieve the DEVICENAME string
+                char* pname = stackalloc char[size + 1];
+                if (Functions.GetRawInputDeviceInfo(handle, RawInputDeviceInfoEnum.DEVICENAME, (IntPtr)pname, ref size) < 0)
+                {
+                    Debug.Print("[WinRawJoystick] Functions.GetRawInputDeviceInfo(DEVICENAME) failed with error {0}",
+                        Marshal.GetLastWin32Error());
+                    return guid;
+                }
 
-            UpdateAxes(stick, caps, axes_caps, data);
-            UpdateButtons(stick, caps, button_caps, data);
+                // Convert the buffer to a .Net string, and split it into parts
+                string name = new string(pname);
+                if (String.IsNullOrEmpty(name))
+                {
+                    Debug.Print("[WinRawJoystick] Failed to construct device name");
+                    return guid;
+                }
 
-#if false
-            // Button state
-            //g_NumberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1;
-#endif
+                // The GUID is stored in the last part of the string
+                string[] parts = name.Split('#');
+                if (parts.Length >= 3)
+                {
+                    guid = new Guid(parts[2]);
+                }
+            }
 
-            return true;
+            return guid;
         }
 
-        unsafe static void UpdateAxes(Device stick, HidProtocolCaps caps, HidProtocolValueCaps* axes_caps, HidProtocolData* data)
+        static void UpdateAxes(Device stick, HidProtocolCaps caps, HidProtocolValueCaps[] axes, HidProtocolData[] data)
         {
             // Use the data indices in the axis and button caps arrays to
             // access the data buffer we just filled.
             for (int i = 0; i < caps.NumberInputValueCaps; i++)
             {
-                HidProtocolValueCaps* axis = axes_caps + i;
-                if (!axis->IsRange)
+                if (!axes[i].IsRange)
                 {
-                    int index = axis->NotRange.DataIndex;
+                    int index = axes[i].NotRange.DataIndex;
                     if (index < 0 || index >= caps.NumberInputValueCaps)
                     {
                         // Should never happen
@@ -267,20 +455,19 @@ namespace OpenTK.Platform.Windows
                         continue;
                     }
 
-                    HidProtocolData* d = (data + index);
-                    if (d->DataIndex != index)
+                    if (data[i].DataIndex != index)
                     {
                         // Should also never happen
                         Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
-                            d->DataIndex, index);
+                            data[i].DataIndex, index);
                         continue;
                     }
 
-                    short value = (short)HidHelper.ScaleValue(d->RawValue,
-                        axis->LogicalMin, axis->LogicalMax,
+                    short value = (short)HidHelper.ScaleValue(data[i].RawValue,
+                        axes[i].LogicalMin, axes[i].LogicalMax,
                         short.MinValue, short.MaxValue);
 
-                    stick.SetAxis(axis->UsagePage, axis->NotRange.Usage, value);
+                    stick.SetAxis(axes[i].UsagePage, axes[i].NotRange.Usage, value);
                 }
                 else
                 {
@@ -289,14 +476,13 @@ namespace OpenTK.Platform.Windows
             }
         }
 
-        unsafe static void UpdateButtons(Device stick, HidProtocolCaps caps, HidProtocolButtonCaps* button_caps, HidProtocolData* data)
+        unsafe static void UpdateButtons(Device stick, HidProtocolCaps caps, HidProtocolButtonCaps[] buttons, HidProtocolData[] data)
         {
             for (int i = 0; i < caps.NumberInputButtonCaps; i++)
             {
-                HidProtocolButtonCaps* button = button_caps + i;
-                if (!button->IsRange)
+                if (!buttons[i].IsRange)
                 {
-                    int index = button->NotRange.DataIndex;
+                    int index = buttons[i].NotRange.DataIndex;
                     if (index < 0 || index >= caps.NumberInputButtonCaps)
                     {
                         // Should never happen
@@ -304,18 +490,16 @@ namespace OpenTK.Platform.Windows
                         continue;
                     }
 
-                    HidProtocolData* d = (data + index);
-                    if (d->DataIndex != index)
+                    if (data[i].DataIndex != index)
                     {
                         // Should also never happen
                         Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
-                            d->DataIndex, index);
+                            data[i].DataIndex, index);
                         continue;
                     }
 
-                    bool value = d->On;
-
-                    stick.SetButton(button->UsagePage, button->NotRange.Usage, value);
+                    bool value = data[i].On;
+                    stick.SetButton(buttons[i].UsagePage, buttons[i].NotRange.Usage, value);
                 }
                 else
                 {
index b5ca8ca..9b8e2cb 100644 (file)
@@ -231,7 +231,7 @@ namespace OpenTK.Platform.Windows
 
         static string GetDeviceName(RawInputDeviceList dev)
         {
-            uint size = 0;
+            int size = 0;
             Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
             IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size);
             Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, name_ptr, ref size);
index 6b0db6a..c26bb5e 100644 (file)
@@ -252,7 +252,7 @@ namespace OpenTK.Platform.Windows
         static string GetDeviceName(RawInputDeviceList dev)
         {
             // get name size
-            uint size = 0;
+            int size = 0;
             Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
 
             // get actual name