From 2a6579032eba329be141fed8e224e31e17b43b94 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 15 Sep 2014 14:48:01 +0200 Subject: [PATCH] [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.) --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 218 ++++++++++------------- 1 file changed, 95 insertions(+), 123 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index e40da70a..b423ab97 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -81,14 +81,14 @@ namespace OpenTK.Platform.MacOS { 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)); - Debug.Print("[{0}] Discovered joystick element {1:x} ({2}/{3})", - typeof(HIDInput).Name, e.Cookie, e.Page, e.Usage); + Elements.Add(e.Cookie, e); + Debug.Print("Discovered joystick element {0:x} ({1}/{2})", + e.Cookie, e.Page, e.Usage); } else { - Debug.Print("[{0}] Attempted to add joystick element {1:x} ({2}/{3}) twice, ignoring.", - typeof(HIDInput).Name, e.Cookie, e.Page, e.Usage); + Debug.Print("Duplicate joystick element {0:x} ({1}/{2}) ignored.", + e.Cookie, e.Page, e.Usage); } } } @@ -97,8 +97,6 @@ namespace OpenTK.Platform.MacOS { public IntPtr Element; public IntPtr Cookie; - // Order in which this element was reported - public int Order; public HIDPage Page; public int Usage; // Hardware axis range @@ -108,14 +106,16 @@ namespace OpenTK.Platform.MacOS public int MinReported; public int MaxReported; + // Order in which this element was reported + public int Index; + public JoystickElement( - IntPtr element, IntPtr cookie, int order, + IntPtr element, IntPtr cookie, HIDPage page, int usage, int min, int max) { Element = element; Cookie = cookie; - Order = order; Page = page; Usage = usage; Min = min; @@ -652,10 +652,6 @@ namespace OpenTK.Platform.MacOS if (element_array_ref != IntPtr.Zero) { joy = new JoystickData(); - int axes = 0; - int buttons = 0; - int hats = 0; - int vendor = 0; CFStringRef name_ref = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDProductKey); string name = CF.CFStringGetCString(name_ref); @@ -666,72 +662,72 @@ namespace OpenTK.Platform.MacOS button_elements.Clear(); hat_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. // (This is necessary for the gamepad database). 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]; - e.Order = i; + e.Index = i; joy.AddElement(e); } - button_elements.Sort(); - for (int i = 0; i < button_elements.Count; i++) + for (int i = 0; i < Math.Min(button_elements.Count, JoystickState.MaxButtons); i++) { JoystickElement e = button_elements[i]; - e.Order = i; + e.Index = i; joy.AddElement(e); } - hat_elements.Sort(); - for (int i = 0; i < hat_elements.Count; i++) + for (int i = 0; i < Math.Min(hat_elements.Count, JoystickState.MaxHats); i++) { JoystickElement e = hat_elements[i]; - e.Order = i; + e.Index = i; joy.AddElement(e); } - vendor_elements.Sort(); for (int i = 0; i < vendor_elements.Count; i++) { JoystickElement e = vendor_elements[i]; - e.Order = i; + e.Index = i; 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", - axes, JoystickState.MaxAxes); - axes = JoystickState.MaxAxes; + axis_elements.Count, 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", - buttons, JoystickState.MaxButtons); - buttons = JoystickState.MaxButtons; + button_elements.Count, 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", - hats, JoystickState.MaxHats); - hats = JoystickState.MaxHats; + hat_elements.Count, JoystickState.MaxHats); } joy.Name = name; joy.Guid = guid; 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); 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); for (int i = 0; i < element_array.Count; i++) @@ -743,6 +739,7 @@ namespace OpenTK.Platform.MacOS IOHIDElementCookie cookie = NativeMethods.IOHIDElementGetCookie(element_ref); HIDPage page = NativeMethods.IOHIDElementGetUsagePage(element_ref); int usage = NativeMethods.IOHIDElementGetUsage(element_ref); + JoystickElement e = null; switch (NativeMethods.IOHIDElementGetType(element_ref)) { @@ -763,34 +760,18 @@ namespace OpenTK.Platform.MacOS case HIDUsageGD.Slider: case HIDUsageGD.Dial: case HIDUsageGD.Wheel: - if (axes < JoystickState.MaxAxes) + e = new JoystickElement(element_ref, cookie, page, usage, 0, 0); + if (!axis_elements.Contains(e)) { - var e = new JoystickElement(element_ref, cookie, axes++, page, usage, 0, 0); - if (!axis_elements.Contains(e)) - { - axis_elements.Add(e); - } - } - else - { - Debug.Print("[{0}] Failed to add axis (limit of {1} has been reached).", - GetType().Name, JoystickState.MaxAxes); + axis_elements.Add(e); } break; case HIDUsageGD.Hatswitch: - if (hats < JoystickState.MaxHats) + e = new JoystickElement(element_ref, cookie, page, usage, 0, 0); + if (!hat_elements.Contains(e)) { - var e = new JoystickElement(element_ref, cookie, axes++, page, usage, 0, 0); - if (!hat_elements.Contains(e)) - { - hat_elements.Add(e); - } - } - else - { - Debug.Print("[{0}] Failed to add hat (limit of {1} has been reached).", - GetType().Name, JoystickState.MaxHats); + hat_elements.Add(e); } break; } @@ -801,46 +782,28 @@ namespace OpenTK.Platform.MacOS { case HIDUsageSim.Rudder: case HIDUsageSim.Throttle: - if (axes < JoystickState.MaxAxes) + e = new JoystickElement(element_ref, cookie, page, usage, 0, 0); + if (!axis_elements.Contains(e)) { - JoystickElement e = new JoystickElement(element_ref, cookie, axes++, page, usage, 0, 0); - if (!axis_elements.Contains(e)) - { - axis_elements.Add(e); - } - } - else - { - Debug.Print("[{0}] Failed to add axis (limit of {1} has been reached).", - GetType().Name, JoystickState.MaxAxes); + axis_elements.Add(e); } break; } break; case HIDPage.Button: - if (buttons < JoystickState.MaxButtons) + e = new JoystickElement(element_ref, cookie, page, usage, 0, 0); + if (!button_elements.Contains(e)) { - JoystickElement e = new JoystickElement(element_ref, cookie, buttons++, page, usage, 0, 0); - if (!button_elements.Contains(e)) - { - button_elements.Add(e); - } - } - else - { - Debug.Print("[{0}] Failed to add button (limit of {1} has been reached).", - GetType().Name, JoystickState.MaxButtons); + button_elements.Add(e); } break; case HIDPage.VendorDefinedStart: + e = new JoystickElement(element_ref, cookie, page, usage, 0, 0); + if (!vendor_elements.Contains(e)) { - JoystickElement e = new JoystickElement(element_ref, cookie, vendor++, page, usage, 0, 0); - if (!vendor_elements.Contains(e)) - { - vendor_elements.Add(e); - } + vendor_elements.Add(e); } break; } @@ -850,7 +813,7 @@ namespace OpenTK.Platform.MacOS CFArrayRef children_array_ref = NativeMethods.IOHIDElementGetChildren(element_ref); 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; } @@ -875,45 +838,54 @@ namespace OpenTK.Platform.MacOS void AddJoystick(CFAllocatorRef sender, CFAllocatorRef device) { Debug.Print("Joystick device {0:x} discovered, sender is {1:x}", device, sender); - JoystickData joy = CreateJoystick(sender, device); - if (joy != null) - { - // Add a device->joy lookup entry for this device. - if (!JoystickDevices.ContainsKey(device)) - { - // First time we've seen this device. - JoystickDevices.Add(device, joy); - } - else - { - // This is an old device that is replugged. - // This branch does not appear to be executed, ever. - JoystickDevices[device] = joy; - } + Debug.Indent(); - // Add an index->device lookup entry for this device. - // Use the first free (i.e. disconnected) index. - // If all indices are connected, append a new one. - int i; - for (i = 0; i < JoystickIndexToDevice.Count; i++) + try + { + JoystickData joy = CreateJoystick(sender, device); + if (joy != null) { - IntPtr candidate = JoystickIndexToDevice[i]; - if (!JoystickDevices[candidate].State.IsConnected) + // Add a device->joy lookup entry for this device. + if (!JoystickDevices.ContainsKey(device)) { - break; + // First time we've seen this device. + JoystickDevices.Add(device, joy); + } + else + { + // This is an old device that is replugged. + // This branch does not appear to be executed, ever. + JoystickDevices[device] = joy; + } + + // Add an index->device lookup entry for this device. + // Use the first free (i.e. disconnected) index. + // If all indices are connected, append a new one. + int i; + for (i = 0; i < JoystickIndexToDevice.Count; i++) + { + IntPtr candidate = JoystickIndexToDevice[i]; + if (!JoystickDevices[candidate].State.IsConnected) + { + break; + } + } + + if (i == JoystickDevices.Count) + { + // All indices connected, append a new one. + JoystickIndexToDevice.Add(JoystickDevices.Count, device); + } + else + { + // Replace joystick at that index + JoystickIndexToDevice[i] = device; } } - - if (i == JoystickDevices.Count) - { - // All indices connected, append a new one. - JoystickIndexToDevice.Add(JoystickDevices.Count, device); - } - else - { - // Replace joystick at that index - JoystickIndexToDevice[i] = device; - } + } + finally + { + Debug.Unindent(); } } @@ -954,7 +926,7 @@ namespace OpenTK.Platform.MacOS case HIDUsageGD.Dial: case HIDUsageGD.Wheel: 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) { joy.State.SetAxis(axis, offset); @@ -963,7 +935,7 @@ namespace OpenTK.Platform.MacOS case HIDUsageGD.Hatswitch: 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) { joy.State.SetHat(hat, new JoystickHatState(position)); @@ -978,7 +950,7 @@ namespace OpenTK.Platform.MacOS case HIDUsageSim.Rudder: case HIDUsageSim.Throttle: 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) { joy.State.SetAxis(axis, offset); @@ -990,7 +962,7 @@ namespace OpenTK.Platform.MacOS case HIDPage.Button: { 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) { joy.State.SetButton(button, pressed);