[Win] Implemented joystick button updates
Due to the way we segregate axes from buttons, the easiest approach is to retrieve the current button state via HidP_GetUsages(). Axes, buttons and hats are now allocated sequentially based on their order of appearance in the device capability reports.
This commit is contained in:
parent
3fee0bd8d0
commit
cbb2807959
3 changed files with 106 additions and 60 deletions
|
@ -223,6 +223,11 @@ namespace OpenTK.Input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void ClearButtons()
|
||||||
|
{
|
||||||
|
buttons = 0;
|
||||||
|
}
|
||||||
|
|
||||||
internal void SetButton(JoystickButton button, bool value)
|
internal void SetButton(JoystickButton button, bool value)
|
||||||
{
|
{
|
||||||
int index = (int)button;
|
int index = (int)button;
|
||||||
|
|
|
@ -86,6 +86,12 @@ namespace OpenTK.Platform.Windows
|
||||||
[Out] HidProtocolButtonCaps[] ButtonCaps, ref ushort ButtonCapsLength,
|
[Out] HidProtocolButtonCaps[] ButtonCaps, ref ushort ButtonCapsLength,
|
||||||
[In] byte[] PreparsedData);
|
[In] byte[] PreparsedData);
|
||||||
|
|
||||||
|
[SuppressUnmanagedCodeSecurity]
|
||||||
|
[DllImport(lib, SetLastError = true, EntryPoint = "HidP_GetUsages")]
|
||||||
|
unsafe public static extern HidProtocolStatus GetUsages(HidProtocolReportType type,
|
||||||
|
HIDPage usage_page, short link_collection, short* usage_list, ref int usage_length,
|
||||||
|
[In] 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,
|
||||||
|
|
|
@ -50,20 +50,26 @@ namespace OpenTK.Platform.Windows
|
||||||
new Dictionary<int,JoystickAxis>();
|
new Dictionary<int,JoystickAxis>();
|
||||||
readonly Dictionary<int, JoystickButton> buttons =
|
readonly Dictionary<int, JoystickButton> buttons =
|
||||||
new Dictionary<int, JoystickButton>();
|
new Dictionary<int, JoystickButton>();
|
||||||
|
readonly Dictionary<int, JoystickHat> hats =
|
||||||
|
new Dictionary<int, JoystickHat>();
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public Device(IntPtr handle, Guid guid, JoystickCapabilities caps)
|
public Device(IntPtr handle, Guid guid)
|
||||||
{
|
{
|
||||||
Handle = handle;
|
Handle = handle;
|
||||||
Guid = guid;
|
Guid = guid;
|
||||||
Capabilities = caps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Members
|
#region Public Members
|
||||||
|
|
||||||
|
public void ClearButtons()
|
||||||
|
{
|
||||||
|
State.ClearButtons();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetAxis(HIDPage page, short usage, short value)
|
public void SetAxis(HIDPage page, short usage, short value)
|
||||||
{
|
{
|
||||||
JoystickAxis axis = GetAxis(page, usage);
|
JoystickAxis axis = GetAxis(page, usage);
|
||||||
|
@ -76,6 +82,12 @@ namespace OpenTK.Platform.Windows
|
||||||
State.SetButton(button, value);
|
State.SetButton(button, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetHat(HIDPage page, short usage, HatPosition pos)
|
||||||
|
{
|
||||||
|
JoystickHat hat = GetHat(page, usage);
|
||||||
|
State.SetHat(hat, new JoystickHatState(pos));
|
||||||
|
}
|
||||||
|
|
||||||
public void SetConnected(bool value)
|
public void SetConnected(bool value)
|
||||||
{
|
{
|
||||||
Capabilities.SetIsConnected(value);
|
Capabilities.SetIsConnected(value);
|
||||||
|
@ -84,9 +96,17 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
public JoystickCapabilities GetCapabilities()
|
public JoystickCapabilities GetCapabilities()
|
||||||
{
|
{
|
||||||
|
Capabilities = new JoystickCapabilities(
|
||||||
|
axes.Count, buttons.Count, hats.Count,
|
||||||
|
Capabilities.IsConnected);
|
||||||
return Capabilities;
|
return Capabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void SetCapabilities(JoystickCapabilities caps)
|
||||||
|
{
|
||||||
|
Capabilities = caps;
|
||||||
|
}
|
||||||
|
|
||||||
public Guid GetGuid()
|
public Guid GetGuid()
|
||||||
{
|
{
|
||||||
return Guid;
|
return Guid;
|
||||||
|
@ -97,7 +117,6 @@ namespace OpenTK.Platform.Windows
|
||||||
return State;
|
return State;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Members
|
#region Private Members
|
||||||
|
@ -127,6 +146,16 @@ namespace OpenTK.Platform.Windows
|
||||||
return buttons[key];
|
return buttons[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JoystickHat GetHat(HIDPage page, short usage)
|
||||||
|
{
|
||||||
|
int key = MakeKey(page, usage);
|
||||||
|
if (!hats.ContainsKey(key))
|
||||||
|
{
|
||||||
|
hats.Add(key, JoystickHat.Hat0 + hats.Count);
|
||||||
|
}
|
||||||
|
return hats[key];
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,15 +233,17 @@ namespace OpenTK.Platform.Windows
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
device = new Device(handle, guid);
|
||||||
|
|
||||||
// This is a new device, query its capabilities and add it
|
// This is a new device, query its capabilities and add it
|
||||||
// to the device list
|
// to the device list
|
||||||
JoystickCapabilities caps = GetDeviceCaps(handle);
|
QueryDeviceCaps(device);
|
||||||
|
|
||||||
device = new Device(handle, guid, caps);
|
|
||||||
device.SetConnected(true);
|
device.SetConnected(true);
|
||||||
Devices.Add(hardware_id, device);
|
Devices.Add(hardware_id, device);
|
||||||
|
|
||||||
Debug.Print("[{0}] Connected joystick {1} ({2})", GetType().Name, guid, caps);
|
Debug.Print("[{0}] Connected joystick {1} ({2})",
|
||||||
|
GetType().Name, device.GetGuid(), device.GetCapabilities());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,6 +305,7 @@ namespace OpenTK.Platform.Windows
|
||||||
Array.Resize(ref DataBuffer, report_count);
|
Array.Resize(ref DataBuffer, report_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (HidProtocol.GetData(HidProtocolReportType.Input,
|
if (HidProtocol.GetData(HidProtocolReportType.Input,
|
||||||
DataBuffer, ref size, PreparsedData,
|
DataBuffer, ref size, PreparsedData,
|
||||||
new IntPtr((void*)&rin->Data.HID.RawData),
|
new IntPtr((void*)&rin->Data.HID.RawData),
|
||||||
|
@ -283,9 +315,11 @@ namespace OpenTK.Platform.Windows
|
||||||
Marshal.GetLastWin32Error());
|
Marshal.GetLastWin32Error());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
UpdateAxes(stick, caps, AxisCaps, axis_caps_count, DataBuffer);
|
UpdateButtons(rin, stick, button_caps_count);
|
||||||
UpdateButtons(stick, caps, ButtonCaps, button_caps_count, DataBuffer);
|
|
||||||
|
//UpdateAxes(stick, caps, AxisCaps, axis_caps_count, DataBuffer, size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,6 +327,37 @@ namespace OpenTK.Platform.Windows
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe void UpdateButtons(RawInput* rin, Device stick, int button_caps_count)
|
||||||
|
{
|
||||||
|
stick.ClearButtons();
|
||||||
|
|
||||||
|
for (int i = 0; i < button_caps_count; i++)
|
||||||
|
{
|
||||||
|
short* usage_list = stackalloc short[(int)JoystickButton.Last];
|
||||||
|
int usage_length = (int)JoystickButton.Last;
|
||||||
|
HIDPage page = ButtonCaps[i].UsagePage;
|
||||||
|
|
||||||
|
HidProtocolStatus status = HidProtocol.GetUsages(
|
||||||
|
HidProtocolReportType.Input,
|
||||||
|
page, 0, usage_list, ref usage_length,
|
||||||
|
PreparsedData,
|
||||||
|
new IntPtr((void*)&rin->Data.HID.RawData),
|
||||||
|
rin->Data.HID.Size);
|
||||||
|
|
||||||
|
if (status != HidProtocolStatus.Success)
|
||||||
|
{
|
||||||
|
Debug.Print("[WinRawJoystick] HidProtocol.GetUsages() failed with {0}",
|
||||||
|
Marshal.GetLastWin32Error());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < usage_length; j++)
|
||||||
|
{
|
||||||
|
stick.SetButton(page, *(usage_list + j), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Members
|
#region Private Members
|
||||||
|
@ -328,21 +393,22 @@ namespace OpenTK.Platform.Windows
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JoystickCapabilities GetDeviceCaps(IntPtr handle)
|
void QueryDeviceCaps(Device stick)
|
||||||
{
|
{
|
||||||
HidProtocolCaps caps;
|
HidProtocolCaps caps;
|
||||||
int axis_count;
|
int axis_count;
|
||||||
int button_count;
|
int button_count;
|
||||||
|
|
||||||
if (GetPreparsedData(handle, ref PreparsedData) &&
|
// Discovered elements
|
||||||
|
int axes = 0;
|
||||||
|
int dpads = 0;
|
||||||
|
int buttons = 0;
|
||||||
|
|
||||||
|
if (GetPreparsedData(stick.Handle, ref PreparsedData) &&
|
||||||
GetDeviceCaps(PreparsedData, out caps,
|
GetDeviceCaps(PreparsedData, out caps,
|
||||||
ref AxisCaps, out axis_count,
|
ref AxisCaps, out axis_count,
|
||||||
ref ButtonCaps, out button_count))
|
ref ButtonCaps, out button_count))
|
||||||
{
|
{
|
||||||
int axes = 0;
|
|
||||||
int dpads = 0;
|
|
||||||
int buttons = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < axis_count; i++)
|
for (int i = 0; i < axis_count; i++)
|
||||||
{
|
{
|
||||||
if (AxisCaps[i].IsRange)
|
if (AxisCaps[i].IsRange)
|
||||||
|
@ -351,7 +417,8 @@ namespace OpenTK.Platform.Windows
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (AxisCaps[i].UsagePage)
|
HIDPage page = AxisCaps[i].UsagePage;
|
||||||
|
switch (page)
|
||||||
{
|
{
|
||||||
case HIDPage.GenericDesktop:
|
case HIDPage.GenericDesktop:
|
||||||
switch ((HIDUsageGD)AxisCaps[i].NotRange.Usage)
|
switch ((HIDUsageGD)AxisCaps[i].NotRange.Usage)
|
||||||
|
@ -365,11 +432,11 @@ namespace OpenTK.Platform.Windows
|
||||||
case HIDUsageGD.Slider:
|
case HIDUsageGD.Slider:
|
||||||
case HIDUsageGD.Dial:
|
case HIDUsageGD.Dial:
|
||||||
case HIDUsageGD.Wheel:
|
case HIDUsageGD.Wheel:
|
||||||
axes++;
|
stick.SetAxis(page, AxisCaps[i].NotRange.Usage, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIDUsageGD.Hatswitch:
|
case HIDUsageGD.Hatswitch:
|
||||||
dpads++;
|
stick.SetHat(page, AxisCaps[i].NotRange.Usage, HatPosition.Centered);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -379,14 +446,10 @@ namespace OpenTK.Platform.Windows
|
||||||
{
|
{
|
||||||
case HIDUsageSim.Rudder:
|
case HIDUsageSim.Rudder:
|
||||||
case HIDUsageSim.Throttle:
|
case HIDUsageSim.Throttle:
|
||||||
axes++;
|
stick.SetAxis(page, AxisCaps[i].NotRange.Usage, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIDPage.Button:
|
|
||||||
buttons++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,11 +462,16 @@ namespace OpenTK.Platform.Windows
|
||||||
case HIDPage.Button:
|
case HIDPage.Button:
|
||||||
if (is_range)
|
if (is_range)
|
||||||
{
|
{
|
||||||
buttons += ButtonCaps[i].Range.UsageMax - ButtonCaps[i].Range.UsageMin + 1;
|
for (short usage = ButtonCaps[i].Range.UsageMin; usage < ButtonCaps[i].Range.UsageMax; usage++)
|
||||||
|
{
|
||||||
|
buttons++;
|
||||||
|
stick.SetButton(page, usage, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buttons++;
|
buttons++;
|
||||||
|
stick.SetButton(page, ButtonCaps[i].NotRange.Usage, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -412,10 +480,9 @@ namespace OpenTK.Platform.Windows
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JoystickCapabilities(axes, buttons, dpads, true);
|
|
||||||
}
|
}
|
||||||
return new JoystickCapabilities();
|
|
||||||
|
stick.SetCapabilities(new JoystickCapabilities(axes, buttons, dpads, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetDeviceCaps(byte[] preparsed_data, out HidProtocolCaps caps,
|
static bool GetDeviceCaps(byte[] preparsed_data, out HidProtocolCaps caps,
|
||||||
|
@ -533,11 +600,11 @@ namespace OpenTK.Platform.Windows
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[i].DataIndex != index)
|
if (data[index].DataIndex != i)
|
||||||
{
|
{
|
||||||
// Should also never happen
|
// Should also never happen
|
||||||
Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
|
Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
|
||||||
data[i].DataIndex, index);
|
data[index].DataIndex, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,38 +621,6 @@ namespace OpenTK.Platform.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe static void UpdateButtons(Device stick, HidProtocolCaps caps, HidProtocolButtonCaps[] buttons, int buttons_count, HidProtocolData[] data)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < buttons_count; i++)
|
|
||||||
{
|
|
||||||
if (!buttons[i].IsRange)
|
|
||||||
{
|
|
||||||
int index = buttons[i].NotRange.DataIndex;
|
|
||||||
if (index < 0 || index >= caps.NumberInputButtonCaps)
|
|
||||||
{
|
|
||||||
// Should never happen
|
|
||||||
Debug.Print("[WinRawJoystick] Error: DataIndex out of range");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data[i].DataIndex != index)
|
|
||||||
{
|
|
||||||
// Should also never happen
|
|
||||||
Debug.Print("[WinRawJoystick] DataIndex != index ({0} != {1})",
|
|
||||||
data[i].DataIndex, index);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool value = data[i].On;
|
|
||||||
stick.SetButton(buttons[i].UsagePage, buttons[i].NotRange.Usage, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Todo: fall back to HidProtocol.GetLinkCollectionNodes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Device GetDevice(IntPtr handle)
|
Device GetDevice(IntPtr handle)
|
||||||
{
|
{
|
||||||
long hardware_id = handle.ToInt64();
|
long hardware_id = handle.ToInt64();
|
||||||
|
|
Loading…
Reference in a new issue