mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-23 09:31:08 +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>Call GetLastError to identify any other errors.</para>
|
||||
/// </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]
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern INT GetRawInputDeviceInfo(
|
||||
|
@ -1519,6 +1509,16 @@ namespace OpenTK.Platform.Windows
|
|||
[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>
|
||||
/// Gets information about the raw input device.
|
||||
/// </summary>
|
||||
|
@ -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>
|
||||
|
|
|
@ -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, IntPtr preparsed_data);
|
||||
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,
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
switch (message)
|
||||
{
|
||||
case WindowMessage.INPUT:
|
||||
int size = 0;
|
||||
|
||||
void* data_ptr = stackalloc byte[size];
|
||||
RawInput* data = (RawInput*)data_ptr;
|
||||
#if false
|
||||
// Get the size of the input buffer
|
||||
Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
|
||||
IntPtr.Zero, ref size, API.RawInputHeaderSize);
|
||||
|
||||
// Read the actual raw input structure
|
||||
if (size == Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
|
||||
(IntPtr)data_ptr, ref size, API.RawInputHeaderSize))
|
||||
{
|
||||
switch (data->Header.Type)
|
||||
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;
|
||||
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.MOUSE:
|
||||
if (((WinRawMouse)MouseDriver).ProcessMouseEvent(ref data))
|
||||
return IntPtr.Zero;
|
||||
break;
|
||||
|
||||
case RawInputDeviceType.HID:
|
||||
if (((WinRawJoystick)JoystickDriver).ProcessEvent(data))
|
||||
return IntPtr.Zero;
|
||||
break;
|
||||
case RawInputDeviceType.HID:
|
||||
if (((WinRawJoystick)JoystickDriver).ProcessEvent(ref data))
|
||||
return IntPtr.Zero;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case WindowMessage.DEVICECHANGE:
|
||||
((WinRawKeyboard)KeyboardDriver).RefreshDevices();
|
||||
((WinRawMouse)MouseDriver).RefreshDevices();
|
||||
((WinRawJoystick)JoystickDriver).RefreshDevices();
|
||||
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
|
||||
|
|
|
@ -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,49 +214,20 @@ namespace OpenTK.Platform.Windows
|
|||
return false;
|
||||
}
|
||||
|
||||
// Query the size of the _HIDP_PREPARSED_DATA structure for this event.
|
||||
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)
|
||||
if (!GetPreparsedData(handle, ref PreparsedData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Button capabilities
|
||||
HidProtocolButtonCaps* button_caps = stackalloc HidProtocolButtonCaps[caps.NumberInputButtonCaps];
|
||||
if (HidProtocol.GetButtonCaps(HidProtocolReportType.Input,
|
||||
(IntPtr)button_caps, ref caps.NumberInputButtonCaps, preparsed_data) !=
|
||||
HidProtocolStatus.Success)
|
||||
HidProtocolCaps caps;
|
||||
if (!GetDeviceCaps(PreparsedData, out caps, ref AxisCaps, ref ButtonCaps))
|
||||
{
|
||||
Debug.Print("[WinRawJoystick] HidProtocol.GetButtonCaps() failed with {0}",
|
||||
Marshal.GetLastWin32Error());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Query current state
|
||||
// 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)
|
||||
{
|
||||
Debug.Print("[WinRawJoystick] HidProtocol.MaxDataListLength() failed with {0}",
|
||||
|
@ -229,37 +236,218 @@ namespace OpenTK.Platform.Windows
|
|||
}
|
||||
|
||||
// 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)
|
||||
if (DataBuffer.Length < size)
|
||||
{
|
||||
Debug.Print("[WinRawJoystick] HidProtocol.GetData() failed with {0}",
|
||||
Marshal.GetLastWin32Error());
|
||||
return false;
|
||||
Array.Resize(ref DataBuffer, size);
|
||||
}
|
||||
|
||||
UpdateAxes(stick, caps, axes_caps, data);
|
||||
UpdateButtons(stick, caps, button_caps, data);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
// Button state
|
||||
//g_NumberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1;
|
||||
#endif
|
||||
UpdateAxes(stick, caps, AxisCaps, DataBuffer);
|
||||
UpdateButtons(stick, caps, ButtonCaps, DataBuffer);
|
||||
|
||||
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
|
||||
// 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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue