mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-23 14:31:04 +00:00
[Win] Completed raw input IJoystickDriver2
For improved safety, we are now using managed memory buffers instead of stack allocations and pointers.
This commit is contained in:
parent
f6b382c929
commit
cec48ab20a
|
@ -1500,16 +1500,6 @@ 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>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>
|
/// <para>Call GetLastError to identify any other errors.</para>
|
||||||
/// </returns>
|
/// </returns>
|
||||||
[CLSCompliant(false)]
|
|
||||||
[System.Security.SuppressUnmanagedCodeSecurity]
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
|
||||||
internal static extern UINT GetRawInputDeviceInfo(
|
|
||||||
HANDLE Device,
|
|
||||||
[MarshalAs(UnmanagedType.U4)] RawInputDeviceInfoEnum Command,
|
|
||||||
[In, Out] LPVOID Data,
|
|
||||||
[In, Out] ref UINT Size
|
|
||||||
);
|
|
||||||
|
|
||||||
[System.Security.SuppressUnmanagedCodeSecurity]
|
[System.Security.SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
internal static extern INT GetRawInputDeviceInfo(
|
internal static extern INT GetRawInputDeviceInfo(
|
||||||
|
@ -1519,6 +1509,16 @@ namespace OpenTK.Platform.Windows
|
||||||
[In, Out] ref INT 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] byte[] Data,
|
||||||
|
[In, Out] ref INT Size
|
||||||
|
);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets information about the raw input device.
|
/// Gets information about the raw input device.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2791,7 +2791,7 @@ namespace OpenTK.Platform.Windows
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Size, in bytes, of the RawInputDeviceInfo structure.
|
/// Size, in bytes, of the RawInputDeviceInfo structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DWORD Size = Marshal.SizeOf(typeof(RawInputDeviceInfo));
|
internal DWORD Size = Marshal.SizeOf(typeof(RawInputDeviceInfo));
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of raw input data.
|
/// Type of raw input data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -43,38 +43,54 @@ namespace OpenTK.Platform.Windows
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetButtonCaps")]
|
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetButtonCaps")]
|
||||||
public static extern HidProtocolStatus GetButtonCaps(HidProtocolReportType hidProtocolReportType,
|
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]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetCaps")]
|
[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]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetData")]
|
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetData")]
|
||||||
public static extern HidProtocolStatus GetData(HidProtocolReportType type,
|
public static extern HidProtocolStatus GetData(HidProtocolReportType type,
|
||||||
IntPtr data, ref int data_length,
|
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]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetScaledUsageValue")]
|
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetScaledUsageValue")]
|
||||||
static public extern HidProtocolStatus GetScaledUsageValue(HidProtocolReportType type,
|
static public extern HidProtocolStatus GetScaledUsageValue(HidProtocolReportType type,
|
||||||
HIDPage usage_page, short link_collection, short usage, ref int usage_value,
|
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]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetUsageValue")]
|
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetUsageValue")]
|
||||||
public static extern HidProtocolStatus GetUsageValue(HidProtocolReportType type,
|
public static extern HidProtocolStatus GetUsageValue(HidProtocolReportType type,
|
||||||
HIDPage usage_page, short link_collection, short usage, ref uint usage_value,
|
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]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetValueCaps")]
|
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetValueCaps")]
|
||||||
public static extern HidProtocolStatus GetValueCaps(HidProtocolReportType type, IntPtr caps,
|
public static extern HidProtocolStatus GetValueCaps(HidProtocolReportType type,
|
||||||
ref ushort caps_length, IntPtr preparsed_data);
|
IntPtr caps, ref ushort caps_length, byte[] preparsed_data);
|
||||||
|
|
||||||
|
[SuppressUnmanagedCodeSecurity]
|
||||||
|
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetValueCaps")]
|
||||||
|
public static extern HidProtocolStatus GetValueCaps(HidProtocolReportType type,
|
||||||
|
HidProtocolValueCaps[] caps, ref ushort caps_length, byte[] preparsed_data);
|
||||||
|
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_MaxDataListLength")]
|
[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
|
enum HidProtocolReportType : ushort
|
||||||
|
|
|
@ -45,7 +45,6 @@ namespace OpenTK.Platform.Windows
|
||||||
// WinFactory constructor has finished running. The reason is
|
// WinFactory constructor has finished running. The reason is
|
||||||
// that they call WinFactory methods internally.
|
// that they call WinFactory methods internally.
|
||||||
WinRawInput rawinput_driver; // For keyboard and mouse input
|
WinRawInput rawinput_driver; // For keyboard and mouse input
|
||||||
WinCombinedJoystick joystick_driver; // For joystick input
|
|
||||||
|
|
||||||
internal static IntPtr OpenGLHandle { get; private set; }
|
internal static IntPtr OpenGLHandle { get; private set; }
|
||||||
const string OpenGLName = "OPENGL32.DLL";
|
const string OpenGLName = "OPENGL32.DLL";
|
||||||
|
@ -132,7 +131,7 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
public override IJoystickDriver2 CreateJoystickDriver()
|
public override IJoystickDriver2 CreateJoystickDriver()
|
||||||
{
|
{
|
||||||
return CombinedJoystickDriver;
|
return RawInputDriver.JoystickDriver;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#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
|
#endregion
|
||||||
|
|
||||||
#region IDisposable Members
|
#region IDisposable Members
|
||||||
|
@ -181,7 +164,6 @@ namespace OpenTK.Platform.Windows
|
||||||
if (manual)
|
if (manual)
|
||||||
{
|
{
|
||||||
rawinput_driver.Dispose();
|
rawinput_driver.Dispose();
|
||||||
joystick_driver.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Dispose(manual);
|
base.Dispose(manual);
|
||||||
|
|
|
@ -89,48 +89,59 @@ namespace OpenTK.Platform.Windows
|
||||||
protected unsafe override IntPtr WindowProcedure(
|
protected unsafe override IntPtr WindowProcedure(
|
||||||
IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
{
|
{
|
||||||
switch (message)
|
try
|
||||||
{
|
{
|
||||||
case WindowMessage.INPUT:
|
switch (message)
|
||||||
int size = 0;
|
{
|
||||||
// Get the size of the input buffer
|
case WindowMessage.INPUT:
|
||||||
Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
|
int size = 0;
|
||||||
IntPtr.Zero, ref size, API.RawInputHeaderSize);
|
|
||||||
|
|
||||||
void* data_ptr = stackalloc byte[size];
|
#if false
|
||||||
RawInput* data = (RawInput*)data_ptr;
|
// Get the size of the input buffer
|
||||||
|
Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
|
||||||
|
IntPtr.Zero, ref size, API.RawInputHeaderSize);
|
||||||
|
|
||||||
// Read the actual raw input structure
|
void* data_ptr = stackalloc byte[size];
|
||||||
if (size == Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
|
RawInput* data = (RawInput*)data_ptr;
|
||||||
(IntPtr)data_ptr, ref size, API.RawInputHeaderSize))
|
#endif
|
||||||
{
|
RawInput data;
|
||||||
switch (data->Header.Type)
|
// Read the actual raw input structure
|
||||||
|
if (size == Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
|
||||||
|
out data, ref size, API.RawInputHeaderSize))
|
||||||
{
|
{
|
||||||
case RawInputDeviceType.KEYBOARD:
|
switch (data.Header.Type)
|
||||||
if (((WinRawKeyboard)KeyboardDriver).ProcessKeyboardEvent(ref *data))
|
{
|
||||||
return IntPtr.Zero;
|
case RawInputDeviceType.KEYBOARD:
|
||||||
break;
|
if (((WinRawKeyboard)KeyboardDriver).ProcessKeyboardEvent(ref data))
|
||||||
|
return IntPtr.Zero;
|
||||||
|
break;
|
||||||
|
|
||||||
case RawInputDeviceType.MOUSE:
|
case RawInputDeviceType.MOUSE:
|
||||||
if (((WinRawMouse)MouseDriver).ProcessMouseEvent(ref *data))
|
if (((WinRawMouse)MouseDriver).ProcessMouseEvent(ref data))
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RawInputDeviceType.HID:
|
case RawInputDeviceType.HID:
|
||||||
if (((WinRawJoystick)JoystickDriver).ProcessEvent(data))
|
if (((WinRawJoystick)JoystickDriver).ProcessEvent(ref data))
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case WindowMessage.DEVICECHANGE:
|
case WindowMessage.DEVICECHANGE:
|
||||||
((WinRawKeyboard)KeyboardDriver).RefreshDevices();
|
((WinRawKeyboard)KeyboardDriver).RefreshDevices();
|
||||||
((WinRawMouse)MouseDriver).RefreshDevices();
|
((WinRawMouse)MouseDriver).RefreshDevices();
|
||||||
((WinRawJoystick)JoystickDriver).RefreshDevices();
|
((WinRawJoystick)JoystickDriver).RefreshDevices();
|
||||||
break;
|
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
|
#endregion
|
||||||
|
|
|
@ -76,6 +76,12 @@ namespace OpenTK.Platform.Windows
|
||||||
State.SetButton(button, value);
|
State.SetButton(button, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetConnected(bool value)
|
||||||
|
{
|
||||||
|
Capabilities.SetIsConnected(value);
|
||||||
|
State.SetIsConnected(value);
|
||||||
|
}
|
||||||
|
|
||||||
public JoystickCapabilities GetCapabilities()
|
public JoystickCapabilities GetCapabilities()
|
||||||
{
|
{
|
||||||
return Capabilities;
|
return Capabilities;
|
||||||
|
@ -134,6 +140,11 @@ namespace OpenTK.Platform.Windows
|
||||||
readonly Dictionary<int, IntPtr> IndexToDevice =
|
readonly Dictionary<int, IntPtr> IndexToDevice =
|
||||||
new Dictionary<int, IntPtr>();
|
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)
|
public WinRawJoystick(IntPtr window)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Using WinRawJoystick.");
|
Debug.WriteLine("Using WinRawJoystick.");
|
||||||
|
@ -148,6 +159,17 @@ namespace OpenTK.Platform.Windows
|
||||||
new RawInputDevice(HIDUsageGD.Joystick, RawInputDeviceFlags.INPUTSINK, window),
|
new RawInputDevice(HIDUsageGD.Joystick, RawInputDeviceFlags.INPUTSINK, window),
|
||||||
new RawInputDevice(HIDUsageGD.GamePad, 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();
|
RefreshDevices();
|
||||||
|
|
||||||
Debug.Unindent();
|
Debug.Unindent();
|
||||||
|
@ -157,20 +179,34 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
public void RefreshDevices()
|
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}.",
|
Devices[IndexToDevice[i]].SetConnected(false);
|
||||||
Marshal.GetLastWin32Error());
|
|
||||||
}
|
}
|
||||||
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);
|
Device stick = GetDevice(handle);
|
||||||
if (stick == null)
|
if (stick == null)
|
||||||
{
|
{
|
||||||
|
@ -178,49 +214,20 @@ namespace OpenTK.Platform.Windows
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query the size of the _HIDP_PREPARSED_DATA structure for this event.
|
if (!GetPreparsedData(handle, ref PreparsedData))
|
||||||
int preparsed_size = 0;
|
|
||||||
Functions.GetRawInputDeviceInfo(rin->Header.Device, RawInputDeviceInfoEnum.PREPARSEDDATA,
|
|
||||||
IntPtr.Zero, ref preparsed_size);
|
|
||||||
if (preparsed_size == 0)
|
|
||||||
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)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Query joystick capabilities
|
|
||||||
HidProtocolCaps caps = new HidProtocolCaps();
|
|
||||||
if (HidProtocol.GetCaps(preparsed_data, ref caps) != HidProtocolStatus.Success)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Axis capabilities
|
|
||||||
HidProtocolValueCaps* axes_caps = stackalloc HidProtocolValueCaps[caps.NumberInputValueCaps];
|
|
||||||
if (HidProtocol.GetValueCaps(HidProtocolReportType.Input,
|
|
||||||
(IntPtr)axes_caps, ref caps.NumberInputValueCaps, preparsed_data) !=
|
|
||||||
HidProtocolStatus.Success)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button capabilities
|
HidProtocolCaps caps;
|
||||||
HidProtocolButtonCaps* button_caps = stackalloc HidProtocolButtonCaps[caps.NumberInputButtonCaps];
|
if (!GetDeviceCaps(PreparsedData, out caps, ref AxisCaps, ref ButtonCaps))
|
||||||
if (HidProtocol.GetButtonCaps(HidProtocolReportType.Input,
|
|
||||||
(IntPtr)button_caps, ref caps.NumberInputButtonCaps, preparsed_data) !=
|
|
||||||
HidProtocolStatus.Success)
|
|
||||||
{
|
{
|
||||||
Debug.Print("[WinRawJoystick] HidProtocol.GetButtonCaps() failed with {0}",
|
|
||||||
Marshal.GetLastWin32Error());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query current state
|
// Query current state
|
||||||
// Allocate enough storage to hold the data of the current report
|
// Allocate enough storage to hold the data of the current report
|
||||||
int size = HidProtocol.MaxDataListLength(HidProtocolReportType.Input, preparsed_data);
|
int size = HidProtocol.MaxDataListLength(HidProtocolReportType.Input, PreparsedData);
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
Debug.Print("[WinRawJoystick] HidProtocol.MaxDataListLength() failed with {0}",
|
Debug.Print("[WinRawJoystick] HidProtocol.MaxDataListLength() failed with {0}",
|
||||||
|
@ -229,37 +236,218 @@ namespace OpenTK.Platform.Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill the data buffer
|
// Fill the data buffer
|
||||||
HidProtocolData* data = stackalloc HidProtocolData[size];
|
if (DataBuffer.Length < size)
|
||||||
if (HidProtocol.GetData(HidProtocolReportType.Input,
|
|
||||||
(IntPtr)data, ref size, preparsed_data,
|
|
||||||
new IntPtr(&rin->Data.HID.RawData), rin->Data.HID.Size) != HidProtocolStatus.Success)
|
|
||||||
{
|
{
|
||||||
Debug.Print("[WinRawJoystick] HidProtocol.GetData() failed with {0}",
|
Array.Resize(ref DataBuffer, size);
|
||||||
Marshal.GetLastWin32Error());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateAxes(stick, caps, axes_caps, data);
|
fixed (void* pdata = &rin.Data.HID.RawData)
|
||||||
UpdateButtons(stick, caps, button_caps, data);
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if false
|
UpdateAxes(stick, caps, AxisCaps, DataBuffer);
|
||||||
// Button state
|
UpdateButtons(stick, caps, ButtonCaps, DataBuffer);
|
||||||
//g_NumberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe static void UpdateAxes(Device stick, HidProtocolCaps caps, HidProtocolValueCaps* axes_caps, HidProtocolData* data)
|
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(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.
|
||||||
|
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
|
||||||
|
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
|
||||||
|
if (HidProtocol.GetValueCaps(HidProtocolReportType.Input,
|
||||||
|
axes, ref caps.NumberInputValueCaps, preparsed_data) !=
|
||||||
|
HidProtocolStatus.Success)
|
||||||
|
{
|
||||||
|
Debug.Print("[WinRawJoystick] HidProtocol.GetValueCaps() failed with {0}",
|
||||||
|
Marshal.GetLastWin32Error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Button capabilities
|
||||||
|
if (HidProtocol.GetButtonCaps(HidProtocolReportType.Input,
|
||||||
|
buttons, ref caps.NumberInputButtonCaps, preparsed_data) !=
|
||||||
|
HidProtocolStatus.Success)
|
||||||
|
{
|
||||||
|
Debug.Print("[WinRawJoystick] HidProtocol.GetButtonCaps() failed with {0}",
|
||||||
|
Marshal.GetLastWin32Error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UpdateAxes(Device stick, HidProtocolCaps caps, HidProtocolValueCaps[] axes, HidProtocolData[] data)
|
||||||
{
|
{
|
||||||
// Use the data indices in the axis and button caps arrays to
|
// Use the data indices in the axis and button caps arrays to
|
||||||
// access the data buffer we just filled.
|
// access the data buffer we just filled.
|
||||||
for (int i = 0; i < caps.NumberInputValueCaps; i++)
|
for (int i = 0; i < caps.NumberInputValueCaps; i++)
|
||||||
{
|
{
|
||||||
HidProtocolValueCaps* axis = axes_caps + i;
|
if (!axes[i].IsRange)
|
||||||
if (!axis->IsRange)
|
|
||||||
{
|
{
|
||||||
int index = axis->NotRange.DataIndex;
|
int index = axes[i].NotRange.DataIndex;
|
||||||
if (index < 0 || index >= caps.NumberInputValueCaps)
|
if (index < 0 || index >= caps.NumberInputValueCaps)
|
||||||
{
|
{
|
||||||
// Should never happen
|
// Should never happen
|
||||||
|
@ -267,20 +455,19 @@ namespace OpenTK.Platform.Windows
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HidProtocolData* d = (data + index);
|
if (data[i].DataIndex != index)
|
||||||
if (d->DataIndex != index)
|
|
||||||
{
|
{
|
||||||
// Should also never happen
|
// Should also never happen
|
||||||
Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
|
Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
|
||||||
d->DataIndex, index);
|
data[i].DataIndex, index);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
short value = (short)HidHelper.ScaleValue(d->RawValue,
|
short value = (short)HidHelper.ScaleValue(data[i].RawValue,
|
||||||
axis->LogicalMin, axis->LogicalMax,
|
axes[i].LogicalMin, axes[i].LogicalMax,
|
||||||
short.MinValue, short.MaxValue);
|
short.MinValue, short.MaxValue);
|
||||||
|
|
||||||
stick.SetAxis(axis->UsagePage, axis->NotRange.Usage, value);
|
stick.SetAxis(axes[i].UsagePage, axes[i].NotRange.Usage, value);
|
||||||
}
|
}
|
||||||
else
|
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++)
|
for (int i = 0; i < caps.NumberInputButtonCaps; i++)
|
||||||
{
|
{
|
||||||
HidProtocolButtonCaps* button = button_caps + i;
|
if (!buttons[i].IsRange)
|
||||||
if (!button->IsRange)
|
|
||||||
{
|
{
|
||||||
int index = button->NotRange.DataIndex;
|
int index = buttons[i].NotRange.DataIndex;
|
||||||
if (index < 0 || index >= caps.NumberInputButtonCaps)
|
if (index < 0 || index >= caps.NumberInputButtonCaps)
|
||||||
{
|
{
|
||||||
// Should never happen
|
// Should never happen
|
||||||
|
@ -304,18 +490,16 @@ namespace OpenTK.Platform.Windows
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HidProtocolData* d = (data + index);
|
if (data[i].DataIndex != index)
|
||||||
if (d->DataIndex != index)
|
|
||||||
{
|
{
|
||||||
// Should also never happen
|
// Should also never happen
|
||||||
Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
|
Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
|
||||||
d->DataIndex, index);
|
data[i].DataIndex, index);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool value = d->On;
|
bool value = data[i].On;
|
||||||
|
stick.SetButton(buttons[i].UsagePage, buttons[i].NotRange.Usage, value);
|
||||||
stick.SetButton(button->UsagePage, button->NotRange.Usage, value);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -231,7 +231,7 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
static string GetDeviceName(RawInputDeviceList dev)
|
static string GetDeviceName(RawInputDeviceList dev)
|
||||||
{
|
{
|
||||||
uint size = 0;
|
int size = 0;
|
||||||
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
|
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
|
||||||
IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size);
|
IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size);
|
||||||
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, name_ptr, ref size);
|
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, name_ptr, ref size);
|
||||||
|
|
|
@ -252,7 +252,7 @@ namespace OpenTK.Platform.Windows
|
||||||
static string GetDeviceName(RawInputDeviceList dev)
|
static string GetDeviceName(RawInputDeviceList dev)
|
||||||
{
|
{
|
||||||
// get name size
|
// get name size
|
||||||
uint size = 0;
|
int size = 0;
|
||||||
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
|
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
|
||||||
|
|
||||||
// get actual name
|
// get actual name
|
||||||
|
|
Loading…
Reference in a new issue