[Mac] Match SDL2 element order

Joystick elements (axes, buttons, hats) are now reported in the same
order as SDL2. This fixes potential mismatches in the GamePad
configuration database.

Additionally, elements are now counted correctly (duplicate elements no
longer count towards the total.)
This commit is contained in:
thefiddler 2014-09-15 14:48:01 +02:00
parent fbedac9a16
commit 2a6579032e

View file

@ -81,14 +81,14 @@ namespace OpenTK.Platform.MacOS
{ {
if (!Elements.ContainsKey(e.Cookie)) if (!Elements.ContainsKey(e.Cookie))
{ {
Elements.Add(e.Cookie, new JoystickElement(e.Element, e.Cookie, e.Order, e.Page, e.Usage, e.Min, e.Max)); Elements.Add(e.Cookie, e);
Debug.Print("[{0}] Discovered joystick element {1:x} ({2}/{3})", Debug.Print("Discovered joystick element {0:x} ({1}/{2})",
typeof(HIDInput).Name, e.Cookie, e.Page, e.Usage); e.Cookie, e.Page, e.Usage);
} }
else else
{ {
Debug.Print("[{0}] Attempted to add joystick element {1:x} ({2}/{3}) twice, ignoring.", Debug.Print("Duplicate joystick element {0:x} ({1}/{2}) ignored.",
typeof(HIDInput).Name, e.Cookie, e.Page, e.Usage); e.Cookie, e.Page, e.Usage);
} }
} }
} }
@ -97,8 +97,6 @@ namespace OpenTK.Platform.MacOS
{ {
public IntPtr Element; public IntPtr Element;
public IntPtr Cookie; public IntPtr Cookie;
// Order in which this element was reported
public int Order;
public HIDPage Page; public HIDPage Page;
public int Usage; public int Usage;
// Hardware axis range // Hardware axis range
@ -108,14 +106,16 @@ namespace OpenTK.Platform.MacOS
public int MinReported; public int MinReported;
public int MaxReported; public int MaxReported;
// Order in which this element was reported
public int Index;
public JoystickElement( public JoystickElement(
IntPtr element, IntPtr cookie, int order, IntPtr element, IntPtr cookie,
HIDPage page, int usage, HIDPage page, int usage,
int min, int max) int min, int max)
{ {
Element = element; Element = element;
Cookie = cookie; Cookie = cookie;
Order = order;
Page = page; Page = page;
Usage = usage; Usage = usage;
Min = min; Min = min;
@ -652,10 +652,6 @@ namespace OpenTK.Platform.MacOS
if (element_array_ref != IntPtr.Zero) if (element_array_ref != IntPtr.Zero)
{ {
joy = new JoystickData(); joy = new JoystickData();
int axes = 0;
int buttons = 0;
int hats = 0;
int vendor = 0;
CFStringRef name_ref = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDProductKey); CFStringRef name_ref = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDProductKey);
string name = CF.CFStringGetCString(name_ref); string name = CF.CFStringGetCString(name_ref);
@ -666,72 +662,72 @@ namespace OpenTK.Platform.MacOS
button_elements.Clear(); button_elements.Clear();
hat_elements.Clear(); hat_elements.Clear();
vendor_elements.Clear(); vendor_elements.Clear();
AddElements(joy, element_array_ref, ref axes, ref buttons, ref hats, ref vendor); AddElements(joy, element_array_ref);
// Ensure a stable sorting order that matches SDL2. // Ensure a stable sorting order that matches SDL2.
// (This is necessary for the gamepad database). // (This is necessary for the gamepad database).
axis_elements.Sort(); axis_elements.Sort();
for (int i = 0; i < axis_elements.Count; i++) button_elements.Sort();
hat_elements.Sort();
vendor_elements.Sort();
// Store all discovered elements in JoystickData
for (int i = 0; i < Math.Min(axis_elements.Count, JoystickState.MaxAxes); i++)
{ {
JoystickElement e = axis_elements[i]; JoystickElement e = axis_elements[i];
e.Order = i; e.Index = i;
joy.AddElement(e); joy.AddElement(e);
} }
button_elements.Sort(); for (int i = 0; i < Math.Min(button_elements.Count, JoystickState.MaxButtons); i++)
for (int i = 0; i < button_elements.Count; i++)
{ {
JoystickElement e = button_elements[i]; JoystickElement e = button_elements[i];
e.Order = i; e.Index = i;
joy.AddElement(e); joy.AddElement(e);
} }
hat_elements.Sort(); for (int i = 0; i < Math.Min(hat_elements.Count, JoystickState.MaxHats); i++)
for (int i = 0; i < hat_elements.Count; i++)
{ {
JoystickElement e = hat_elements[i]; JoystickElement e = hat_elements[i];
e.Order = i; e.Index = i;
joy.AddElement(e); joy.AddElement(e);
} }
vendor_elements.Sort();
for (int i = 0; i < vendor_elements.Count; i++) for (int i = 0; i < vendor_elements.Count; i++)
{ {
JoystickElement e = vendor_elements[i]; JoystickElement e = vendor_elements[i];
e.Order = i; e.Index = i;
joy.AddElement(e); joy.AddElement(e);
} }
if (axes > JoystickState.MaxAxes) if (axis_elements.Count >= JoystickState.MaxAxes)
{ {
Debug.Print("[Mac] JoystickAxis limit reached ({0} > {1}), please report a bug at http://www.opentk.com", Debug.Print("[Mac] JoystickAxis limit reached ({0} > {1}), please report a bug at http://www.opentk.com",
axes, JoystickState.MaxAxes); axis_elements.Count, JoystickState.MaxAxes);
axes = JoystickState.MaxAxes;
} }
if (buttons > JoystickState.MaxButtons) if (button_elements.Count > JoystickState.MaxButtons)
{ {
Debug.Print("[Mac] JoystickButton limit reached ({0} > {1}), please report a bug at http://www.opentk.com", Debug.Print("[Mac] JoystickButton limit reached ({0} > {1}), please report a bug at http://www.opentk.com",
buttons, JoystickState.MaxButtons); button_elements.Count, JoystickState.MaxButtons);
buttons = JoystickState.MaxButtons;
} }
if (hats > JoystickState.MaxHats) if (hat_elements.Count > JoystickState.MaxHats)
{ {
Debug.Print("[Mac] JoystickHat limit reached ({0} > {1}), please report a bug at http://www.opentk.com", Debug.Print("[Mac] JoystickHat limit reached ({0} > {1}), please report a bug at http://www.opentk.com",
hats, JoystickState.MaxHats); hat_elements.Count, JoystickState.MaxHats);
hats = JoystickState.MaxHats;
} }
joy.Name = name; joy.Name = name;
joy.Guid = guid; joy.Guid = guid;
joy.State.SetIsConnected(true); joy.State.SetIsConnected(true);
joy.Capabilities = new JoystickCapabilities(axes, buttons, hats, true); joy.Capabilities = new JoystickCapabilities(
axis_elements.Count, button_elements.Count, hat_elements.Count, true);
} }
CF.CFRelease(element_array_ref); CF.CFRelease(element_array_ref);
return joy; return joy;
} }
void AddElements(JoystickData joy, CFArrayRef element_array_ref, ref int axes, ref int buttons, ref int hats, ref int vendor) void AddElements(JoystickData joy, CFArrayRef element_array_ref)
{ {
CFArray element_array = new CFArray(element_array_ref); CFArray element_array = new CFArray(element_array_ref);
for (int i = 0; i < element_array.Count; i++) for (int i = 0; i < element_array.Count; i++)
@ -743,6 +739,7 @@ namespace OpenTK.Platform.MacOS
IOHIDElementCookie cookie = NativeMethods.IOHIDElementGetCookie(element_ref); IOHIDElementCookie cookie = NativeMethods.IOHIDElementGetCookie(element_ref);
HIDPage page = NativeMethods.IOHIDElementGetUsagePage(element_ref); HIDPage page = NativeMethods.IOHIDElementGetUsagePage(element_ref);
int usage = NativeMethods.IOHIDElementGetUsage(element_ref); int usage = NativeMethods.IOHIDElementGetUsage(element_ref);
JoystickElement e = null;
switch (NativeMethods.IOHIDElementGetType(element_ref)) switch (NativeMethods.IOHIDElementGetType(element_ref))
{ {
@ -763,35 +760,19 @@ namespace OpenTK.Platform.MacOS
case HIDUsageGD.Slider: case HIDUsageGD.Slider:
case HIDUsageGD.Dial: case HIDUsageGD.Dial:
case HIDUsageGD.Wheel: case HIDUsageGD.Wheel:
if (axes < JoystickState.MaxAxes) e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
{
var e = new JoystickElement(element_ref, cookie, axes++, page, usage, 0, 0);
if (!axis_elements.Contains(e)) if (!axis_elements.Contains(e))
{ {
axis_elements.Add(e); axis_elements.Add(e);
} }
}
else
{
Debug.Print("[{0}] Failed to add axis (limit of {1} has been reached).",
GetType().Name, JoystickState.MaxAxes);
}
break; break;
case HIDUsageGD.Hatswitch: case HIDUsageGD.Hatswitch:
if (hats < JoystickState.MaxHats) e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
{
var e = new JoystickElement(element_ref, cookie, axes++, page, usage, 0, 0);
if (!hat_elements.Contains(e)) if (!hat_elements.Contains(e))
{ {
hat_elements.Add(e); hat_elements.Add(e);
} }
}
else
{
Debug.Print("[{0}] Failed to add hat (limit of {1} has been reached).",
GetType().Name, JoystickState.MaxHats);
}
break; break;
} }
break; break;
@ -801,47 +782,29 @@ namespace OpenTK.Platform.MacOS
{ {
case HIDUsageSim.Rudder: case HIDUsageSim.Rudder:
case HIDUsageSim.Throttle: case HIDUsageSim.Throttle:
if (axes < JoystickState.MaxAxes) e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
{
JoystickElement e = new JoystickElement(element_ref, cookie, axes++, page, usage, 0, 0);
if (!axis_elements.Contains(e)) if (!axis_elements.Contains(e))
{ {
axis_elements.Add(e); axis_elements.Add(e);
} }
}
else
{
Debug.Print("[{0}] Failed to add axis (limit of {1} has been reached).",
GetType().Name, JoystickState.MaxAxes);
}
break; break;
} }
break; break;
case HIDPage.Button: case HIDPage.Button:
if (buttons < JoystickState.MaxButtons) e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
{
JoystickElement e = new JoystickElement(element_ref, cookie, buttons++, page, usage, 0, 0);
if (!button_elements.Contains(e)) if (!button_elements.Contains(e))
{ {
button_elements.Add(e); button_elements.Add(e);
} }
}
else
{
Debug.Print("[{0}] Failed to add button (limit of {1} has been reached).",
GetType().Name, JoystickState.MaxButtons);
}
break; break;
case HIDPage.VendorDefinedStart: case HIDPage.VendorDefinedStart:
{ e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
JoystickElement e = new JoystickElement(element_ref, cookie, vendor++, page, usage, 0, 0);
if (!vendor_elements.Contains(e)) if (!vendor_elements.Contains(e))
{ {
vendor_elements.Add(e); vendor_elements.Add(e);
} }
}
break; break;
} }
break; break;
@ -850,7 +813,7 @@ namespace OpenTK.Platform.MacOS
CFArrayRef children_array_ref = NativeMethods.IOHIDElementGetChildren(element_ref); CFArrayRef children_array_ref = NativeMethods.IOHIDElementGetChildren(element_ref);
if (children_array_ref != IntPtr.Zero) if (children_array_ref != IntPtr.Zero)
{ {
AddElements(joy, children_array_ref, ref axes, ref buttons, ref hats, ref vendor); AddElements(joy, children_array_ref);
} }
break; break;
} }
@ -875,6 +838,10 @@ namespace OpenTK.Platform.MacOS
void AddJoystick(CFAllocatorRef sender, CFAllocatorRef device) void AddJoystick(CFAllocatorRef sender, CFAllocatorRef device)
{ {
Debug.Print("Joystick device {0:x} discovered, sender is {1:x}", device, sender); Debug.Print("Joystick device {0:x} discovered, sender is {1:x}", device, sender);
Debug.Indent();
try
{
JoystickData joy = CreateJoystick(sender, device); JoystickData joy = CreateJoystick(sender, device);
if (joy != null) if (joy != null)
{ {
@ -916,6 +883,11 @@ namespace OpenTK.Platform.MacOS
} }
} }
} }
finally
{
Debug.Unindent();
}
}
void RemoveJoystick(CFAllocatorRef sender, CFAllocatorRef device) void RemoveJoystick(CFAllocatorRef sender, CFAllocatorRef device)
{ {
@ -954,7 +926,7 @@ namespace OpenTK.Platform.MacOS
case HIDUsageGD.Dial: case HIDUsageGD.Dial:
case HIDUsageGD.Wheel: case HIDUsageGD.Wheel:
short offset = GetJoystickAxis(val, elem); short offset = GetJoystickAxis(val, elem);
JoystickAxis axis = JoystickAxis.Axis0 + joy.Elements[cookie].Order; JoystickAxis axis = JoystickAxis.Axis0 + joy.Elements[cookie].Index;
if (axis >= JoystickAxis.Axis0 && axis <= JoystickAxis.Last) if (axis >= JoystickAxis.Axis0 && axis <= JoystickAxis.Last)
{ {
joy.State.SetAxis(axis, offset); joy.State.SetAxis(axis, offset);
@ -963,7 +935,7 @@ namespace OpenTK.Platform.MacOS
case HIDUsageGD.Hatswitch: case HIDUsageGD.Hatswitch:
HatPosition position = GetJoystickHat(val, elem); HatPosition position = GetJoystickHat(val, elem);
JoystickHat hat = JoystickHat.Hat0 + joy.Elements[cookie].Order; JoystickHat hat = JoystickHat.Hat0 + joy.Elements[cookie].Index;
if (hat >= JoystickHat.Hat0 && hat <= JoystickHat.Last) if (hat >= JoystickHat.Hat0 && hat <= JoystickHat.Last)
{ {
joy.State.SetHat(hat, new JoystickHatState(position)); joy.State.SetHat(hat, new JoystickHatState(position));
@ -978,7 +950,7 @@ namespace OpenTK.Platform.MacOS
case HIDUsageSim.Rudder: case HIDUsageSim.Rudder:
case HIDUsageSim.Throttle: case HIDUsageSim.Throttle:
short offset = GetJoystickAxis(val, elem); short offset = GetJoystickAxis(val, elem);
JoystickAxis axis = JoystickAxis.Axis0 + joy.Elements[cookie].Order; JoystickAxis axis = JoystickAxis.Axis0 + joy.Elements[cookie].Index;
if (axis >= JoystickAxis.Axis0 && axis <= JoystickAxis.Last) if (axis >= JoystickAxis.Axis0 && axis <= JoystickAxis.Last)
{ {
joy.State.SetAxis(axis, offset); joy.State.SetAxis(axis, offset);
@ -990,7 +962,7 @@ namespace OpenTK.Platform.MacOS
case HIDPage.Button: case HIDPage.Button:
{ {
bool pressed = GetJoystickButton(val, elem); bool pressed = GetJoystickButton(val, elem);
JoystickButton button = JoystickButton.Button0 + joy.Elements[cookie].Order; JoystickButton button = JoystickButton.Button0 + joy.Elements[cookie].Index;
if (button >= JoystickButton.Button0 && button <= JoystickButton.Last) if (button >= JoystickButton.Button0 && button <= JoystickButton.Last)
{ {
joy.State.SetButton(button, pressed); joy.State.SetButton(button, pressed);