From d4c6b2e6994a1472a52906269f97ad50027e241d Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 11 Sep 2014 13:18:29 +0200 Subject: [PATCH 1/8] [Mac] Fixed joystick Guid calculation The result now matches the output of SDL2 as well as the entries in the GamePad configuration database. --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index e4a4614d..08223aa9 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -558,7 +558,18 @@ namespace OpenTK.Platform.MacOS guid_bytes.AddRange(name_bytes); } - return new Guid(guid_bytes.ToArray()); + // The Guid(byte[]) constructor performs byte-swapping on the first 4+2+2 bytes, while + // the Guid(string) constructor does not. Since our database is using the string + // constructor, we need to compensate for this difference or the database lookups + // will fail. + byte[] guid_array = guid_bytes.ToArray(); + if (BitConverter.IsLittleEndian) + { + Array.Reverse(guid_array, 0, 4); + Array.Reverse(guid_array, 4, 2); + Array.Reverse(guid_array, 6, 2); + } + return new Guid(guid_array); } JoystickData CreateJoystick(IntPtr sender, IntPtr device) From 4231cf2cdd12fc4b4f663caf95e65ff1dd10f3f3 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 11 Sep 2014 15:57:14 +0200 Subject: [PATCH 2/8] [Mac] Use cookies to match HID joystick elements --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 157 ++++++++++++++++------- 1 file changed, 111 insertions(+), 46 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index 08223aa9..80cfa1d9 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -45,6 +45,7 @@ namespace OpenTK.Platform.MacOS using CFTypeRef = System.IntPtr; using IOHIDDeviceRef = System.IntPtr; using IOHIDElementRef = System.IntPtr; + using IOHIDElementCookie = System.IntPtr; using IOHIDManagerRef = System.IntPtr; using IOHIDValueRef = System.IntPtr; using IOOptionBits = System.IntPtr; @@ -72,10 +73,59 @@ namespace OpenTK.Platform.MacOS public Guid Guid; public JoystickState State; public JoystickCapabilities Capabilities; - readonly public Dictionary ElementUsageToButton = - new Dictionary(); - readonly public Dictionary ElementToHat = - new Dictionary(new IntPtrEqualityComparer()); + + readonly public Dictionary Elements = + new Dictionary(); + + public void AddElement( + IntPtr element, IntPtr cookie, int order, + HIDPage page, int usage, + int min, int max) + { + if (!Elements.ContainsKey(cookie)) + { + Elements.Add(cookie, new JoystickElement(element, cookie, order, page, usage, min, max)); + Debug.Print("[{0}] Discovered joystick element {1:x} ({2}/{3})", + typeof(HIDInput).Name, cookie, page, usage); + } + else + { + Debug.Print("[{0}] Attempted to add joystick element {1:x} ({2}/{3}) twice, ignoring.", + typeof(HIDInput).Name, cookie, page, usage); + } + } + } + + class JoystickElement + { + 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 + public int Min; + public int Max; + // Reported axis range (can sometimes be larger than hardware range) + public int MinReported; + public int MaxReported; + + public JoystickElement( + IntPtr element, IntPtr cookie, int order, + HIDPage page, int usage, + int min, int max) + { + Element = element; + Cookie = cookie; + Order = order; + Page = page; + Usage = usage; + Min = min; + Max = max; + MinReported = min; + MaxReported = max; + } } IOHIDManagerRef hidmanager; @@ -584,18 +634,18 @@ namespace OpenTK.Platform.MacOS 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); Guid guid = CreateJoystickGuid(device, name); - List button_elements = new List(); - List hat_elements = new List(); CFArray element_array = new CFArray(element_array_ref); for (int i = 0; i < element_array.Count; i++) { IOHIDElementRef element_ref = element_array[i]; + IOHIDElementCookie cookie = NativeMethods.IOHIDElementGetCookie(element_ref); HIDPage page = NativeMethods.IOHIDElementGetUsagePage(element_ref); int usage = NativeMethods.IOHIDElementGetUsage(element_ref); @@ -613,12 +663,27 @@ namespace OpenTK.Platform.MacOS case HIDUsageGD.Slider: case HIDUsageGD.Dial: case HIDUsageGD.Wheel: - axes++; + if (axes < JoystickState.MaxAxes) + { + joy.AddElement(element_ref, cookie, axes++, page, usage, 0, 0); + } + else + { + Debug.Print("[{0}] Failed to add axis (limit of {1} has been reached).", + GetType().Name, JoystickState.MaxAxes); + } break; case HIDUsageGD.Hatswitch: - hats++; - hat_elements.Add(element_ref); + if (hats < JoystickState.MaxHats) + { + joy.AddElement(element_ref, cookie, hats++, page, usage, 0, 0); + } + else + { + Debug.Print("[{0}] Failed to add hat (limit of {1} has been reached).", + GetType().Name, JoystickState.MaxHats); + } break; } break; @@ -628,13 +693,33 @@ namespace OpenTK.Platform.MacOS { case HIDUsageSim.Rudder: case HIDUsageSim.Throttle: - axes++; + if (axes < JoystickState.MaxAxes) + { + joy.AddElement(element_ref, cookie, axes++, page, usage, 0, 0); + } + else + { + Debug.Print("[{0}] Failed to add axis (limit of {1} has been reached).", + GetType().Name, JoystickState.MaxAxes); + } break; } break; case HIDPage.Button: - button_elements.Add(usage); + if (buttons < JoystickState.MaxButtons) + { + joy.AddElement(element_ref, cookie, buttons++, page, usage, 0, 0); + } + else + { + Debug.Print("[{0}] Failed to add button (limit of {1} has been reached).", + GetType().Name, JoystickState.MaxButtons); + } + break; + + case HIDPage.VendorDefinedStart: + joy.AddElement(element_ref, cookie, vendor++, page, usage, 0, 0); break; } } @@ -662,17 +747,6 @@ namespace OpenTK.Platform.MacOS joy.Guid = guid; joy.State.SetIsConnected(true); joy.Capabilities = new JoystickCapabilities(axes, buttons, hats, true); - - // Map button elements to JoystickButtons - for (int button = 0; button < button_elements.Count; button++) - { - joy.ElementUsageToButton.Add(button_elements[button], JoystickButton.Button0 + button); - } - - for (int hat = 0; hat < hat_elements.Count; hat++) - { - joy.ElementToHat.Add(hat_elements[hat], JoystickHat.Hat0 + hat); - } } CF.CFRelease(element_array_ref); @@ -749,9 +823,17 @@ namespace OpenTK.Platform.MacOS static void UpdateJoystick(JoystickData joy, IOHIDValueRef val) { IOHIDElementRef elem = NativeMethods.IOHIDValueGetElement(val); + IOHIDElementCookie cookie = NativeMethods.IOHIDElementGetCookie(elem); HIDPage page = NativeMethods.IOHIDElementGetUsagePage(elem); int usage = NativeMethods.IOHIDElementGetUsage(elem); + if (!joy.Elements.ContainsKey(cookie)) + { + Debug.Print("[{0}] Reported joystick element {1:x} ({2}/{3}) is unknown", + typeof(HIDInput).Name, cookie, page, usage); + return; + } + switch (page) { case HIDPage.GenericDesktop: @@ -767,7 +849,7 @@ namespace OpenTK.Platform.MacOS case HIDUsageGD.Dial: case HIDUsageGD.Wheel: short offset = GetJoystickAxis(val, elem); - JoystickAxis axis = HidHelper.TranslateJoystickAxis(page, usage); + JoystickAxis axis = JoystickAxis.Axis0 + joy.Elements[cookie].Order; if (axis >= JoystickAxis.Axis0 && axis <= JoystickAxis.Last) { joy.State.SetAxis(axis, offset); @@ -776,7 +858,7 @@ namespace OpenTK.Platform.MacOS case HIDUsageGD.Hatswitch: HatPosition position = GetJoystickHat(val, elem); - JoystickHat hat = TranslateJoystickHat(joy, elem); + JoystickHat hat = JoystickHat.Hat0 + joy.Elements[cookie].Order; if (hat >= JoystickHat.Hat0 && hat <= JoystickHat.Last) { joy.State.SetHat(hat, new JoystickHatState(position)); @@ -791,7 +873,7 @@ namespace OpenTK.Platform.MacOS case HIDUsageSim.Rudder: case HIDUsageSim.Throttle: short offset = GetJoystickAxis(val, elem); - JoystickAxis axis = HidHelper.TranslateJoystickAxis(page, usage); + JoystickAxis axis = JoystickAxis.Axis0 + joy.Elements[cookie].Order; if (axis >= JoystickAxis.Axis0 && axis <= JoystickAxis.Last) { joy.State.SetAxis(axis, offset); @@ -803,7 +885,7 @@ namespace OpenTK.Platform.MacOS case HIDPage.Button: { bool pressed = GetJoystickButton(val, elem); - JoystickButton button = TranslateJoystickButton(joy, usage); + JoystickButton button = JoystickButton.Button0 + joy.Elements[cookie].Order; if (button >= JoystickButton.Button0 && button <= JoystickButton.Last) { joy.State.SetButton(button, pressed); @@ -828,16 +910,6 @@ namespace OpenTK.Platform.MacOS return value >= 1; } - static JoystickButton TranslateJoystickButton(JoystickData joy, int usage) - { - JoystickButton button; - if (joy.ElementUsageToButton.TryGetValue(usage, out button)) - { - return button; - } - return JoystickButton.Last + 1; - } - static HatPosition GetJoystickHat(IOHIDValueRef val, IOHIDElementRef element) { HatPosition position = HatPosition.Centered; @@ -872,16 +944,6 @@ namespace OpenTK.Platform.MacOS return position; } - static JoystickHat TranslateJoystickHat(JoystickData joy, IOHIDElementRef elem) - { - JoystickHat hat; - if (joy.ElementToHat.TryGetValue(elem, out hat)) - { - return hat; - } - return JoystickHat.Last + 1; - } - #endregion #endregion @@ -1132,6 +1194,9 @@ namespace OpenTK.Platform.MacOS [DllImport(hid)] public static extern IOHIDElementRef IOHIDValueGetElement(IOHIDValueRef @value); + [DllImport(hid)] + public static extern IOHIDElementCookie IOHIDElementGetCookie(IOHIDElementRef element); + [DllImport(hid)] public static extern CFIndex IOHIDValueGetIntegerValue(IOHIDValueRef @value); From 9c67265832ae70c9f4d0cefe813820569c5aea49 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 12 Sep 2014 08:10:21 +0200 Subject: [PATCH 3/8] [Mac] Added CFGetTypeID method --- Source/OpenTK/Platform/MacOS/Quartz/CoreFoundation.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/OpenTK/Platform/MacOS/Quartz/CoreFoundation.cs b/Source/OpenTK/Platform/MacOS/Quartz/CoreFoundation.cs index a11b9b9b..419f7a13 100644 --- a/Source/OpenTK/Platform/MacOS/Quartz/CoreFoundation.cs +++ b/Source/OpenTK/Platform/MacOS/Quartz/CoreFoundation.cs @@ -112,6 +112,9 @@ namespace OpenTK.Platform.MacOS.Carbon [DllImport(appServices)] internal static extern IntPtr CFDictionaryGetValue(IntPtr theDictionary, IntPtr theKey); + [DllImport(appServices)] + internal static extern IntPtr CFGetTypeID(IntPtr v); + [DllImport(appServices)] internal static extern IntPtr CFRetain(CFTypeRef cf); From b9f7f2c2422756abf278efd47acf2364525b3266 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 12 Sep 2014 08:11:30 +0200 Subject: [PATCH 4/8] [Mac] Sort joystick elements like SDL2 GamePad configuration database is now working correctly on Mac. --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 283 ++++++++++++++++------- 1 file changed, 197 insertions(+), 86 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index 80cfa1d9..76b53300 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -77,26 +77,23 @@ namespace OpenTK.Platform.MacOS readonly public Dictionary Elements = new Dictionary(); - public void AddElement( - IntPtr element, IntPtr cookie, int order, - HIDPage page, int usage, - int min, int max) + public void AddElement(JoystickElement e) { - if (!Elements.ContainsKey(cookie)) + if (!Elements.ContainsKey(e.Cookie)) { - Elements.Add(cookie, new JoystickElement(element, cookie, order, page, usage, min, max)); + 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, cookie, page, usage); + typeof(HIDInput).Name, e.Cookie, e.Page, e.Usage); } else { Debug.Print("[{0}] Attempted to add joystick element {1:x} ({2}/{3}) twice, ignoring.", - typeof(HIDInput).Name, cookie, page, usage); + typeof(HIDInput).Name, e.Cookie, e.Page, e.Usage); } } } - class JoystickElement + class JoystickElement : IComparable, IEquatable { public IntPtr Element; public IntPtr Cookie; @@ -126,6 +123,24 @@ namespace OpenTK.Platform.MacOS MinReported = min; MaxReported = max; } + + #region IComparable implementation + + public int CompareTo(JoystickElement other) + { + return Usage.CompareTo(other.Usage); + } + + #endregion + + #region IEquatable implementation + + public bool Equals(JoystickElement other) + { + return Cookie.Equals(other.Cookie); + } + + #endregion } IOHIDManagerRef hidmanager; @@ -151,6 +166,12 @@ namespace OpenTK.Platform.MacOS readonly MappedGamePadDriver mapped_gamepad = new MappedGamePadDriver(); + // Used for device discovery + readonly List axis_elements = new List(); + readonly List button_elements = new List(); + readonly List hat_elements = new List(); + readonly List vendor_elements = new List(); + IntPtr MouseEventTap; IntPtr MouseEventTapSource; MouseState CursorState; @@ -641,87 +662,44 @@ namespace OpenTK.Platform.MacOS Guid guid = CreateJoystickGuid(device, name); - CFArray element_array = new CFArray(element_array_ref); - for (int i = 0; i < element_array.Count; i++) + axis_elements.Clear(); + button_elements.Clear(); + hat_elements.Clear(); + vendor_elements.Clear(); + AddElements(joy, element_array_ref, ref axes, ref buttons, ref hats, ref vendor); + + // 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++) { - IOHIDElementRef element_ref = element_array[i]; - IOHIDElementCookie cookie = NativeMethods.IOHIDElementGetCookie(element_ref); - HIDPage page = NativeMethods.IOHIDElementGetUsagePage(element_ref); - int usage = NativeMethods.IOHIDElementGetUsage(element_ref); + JoystickElement e = axis_elements[i]; + e.Order = i; + joy.AddElement(e); + } - switch (page) - { - case HIDPage.GenericDesktop: - switch ((HIDUsageGD)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: - if (axes < JoystickState.MaxAxes) - { - joy.AddElement(element_ref, cookie, axes++, page, usage, 0, 0); - } - else - { - Debug.Print("[{0}] Failed to add axis (limit of {1} has been reached).", - GetType().Name, JoystickState.MaxAxes); - } - break; + button_elements.Sort(); + for (int i = 0; i < button_elements.Count; i++) + { + JoystickElement e = button_elements[i]; + e.Order = i; + joy.AddElement(e); + } - case HIDUsageGD.Hatswitch: - if (hats < JoystickState.MaxHats) - { - joy.AddElement(element_ref, cookie, hats++, page, usage, 0, 0); - } - else - { - Debug.Print("[{0}] Failed to add hat (limit of {1} has been reached).", - GetType().Name, JoystickState.MaxHats); - } - break; - } - break; + hat_elements.Sort(); + for (int i = 0; i < hat_elements.Count; i++) + { + JoystickElement e = hat_elements[i]; + e.Order = i; + joy.AddElement(e); + } - case HIDPage.Simulation: - switch ((HIDUsageSim)usage) - { - case HIDUsageSim.Rudder: - case HIDUsageSim.Throttle: - if (axes < JoystickState.MaxAxes) - { - joy.AddElement(element_ref, cookie, axes++, page, usage, 0, 0); - } - else - { - Debug.Print("[{0}] Failed to add axis (limit of {1} has been reached).", - GetType().Name, JoystickState.MaxAxes); - } - break; - } - break; - - case HIDPage.Button: - if (buttons < JoystickState.MaxButtons) - { - joy.AddElement(element_ref, cookie, buttons++, page, usage, 0, 0); - } - else - { - Debug.Print("[{0}] Failed to add button (limit of {1} has been reached).", - GetType().Name, JoystickState.MaxButtons); - } - break; - - case HIDPage.VendorDefinedStart: - joy.AddElement(element_ref, cookie, vendor++, page, usage, 0, 0); - break; - } + vendor_elements.Sort(); + for (int i = 0; i < vendor_elements.Count; i++) + { + JoystickElement e = vendor_elements[i]; + e.Order = i; + joy.AddElement(e); } if (axes > JoystickState.MaxAxes) @@ -753,6 +731,133 @@ namespace OpenTK.Platform.MacOS return joy; } + void AddElements(JoystickData joy, CFArrayRef element_array_ref, ref int axes, ref int buttons, ref int hats, ref int vendor) + { + CFArray element_array = new CFArray(element_array_ref); + for (int i = 0; i < element_array.Count; i++) + { + IOHIDElementRef element_ref = element_array[i]; + + if (element_ref != IntPtr.Zero && CF.CFGetTypeID(element_ref) == NativeMethods.IOHIDElementGetTypeID()) + { + IOHIDElementCookie cookie = NativeMethods.IOHIDElementGetCookie(element_ref); + HIDPage page = NativeMethods.IOHIDElementGetUsagePage(element_ref); + int usage = NativeMethods.IOHIDElementGetUsage(element_ref); + + switch (NativeMethods.IOHIDElementGetType(element_ref)) + { + case IOHIDElementType.Input_Axis: + case IOHIDElementType.Input_Button: + case IOHIDElementType.Input_Misc: + switch (page) + { + case HIDPage.GenericDesktop: + switch ((HIDUsageGD)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: + if (axes < JoystickState.MaxAxes) + { + 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); + } + break; + + case HIDUsageGD.Hatswitch: + if (hats < JoystickState.MaxHats) + { + 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); + } + break; + } + break; + + case HIDPage.Simulation: + switch ((HIDUsageSim)usage) + { + case HIDUsageSim.Rudder: + case HIDUsageSim.Throttle: + if (axes < JoystickState.MaxAxes) + { + 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); + } + break; + } + break; + + case HIDPage.Button: + if (buttons < JoystickState.MaxButtons) + { + 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); + } + break; + + case HIDPage.VendorDefinedStart: + { + JoystickElement e = new JoystickElement(element_ref, cookie, vendor++, page, usage, 0, 0); + if (!vendor_elements.Contains(e)) + { + vendor_elements.Add(e); + } + } + break; + } + break; + + case IOHIDElementType.Collection: + 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); + } + break; + } + } + } + } + JoystickData GetJoystick(int index) { IntPtr device; @@ -1194,6 +1299,9 @@ namespace OpenTK.Platform.MacOS [DllImport(hid)] public static extern IOHIDElementRef IOHIDValueGetElement(IOHIDValueRef @value); + [DllImport(hid)] + public static extern CFArrayRef IOHIDElementGetChildren(IOHIDElementRef element_ref); + [DllImport(hid)] public static extern IOHIDElementCookie IOHIDElementGetCookie(IOHIDElementRef element); @@ -1209,6 +1317,9 @@ namespace OpenTK.Platform.MacOS public static extern IOHIDElementType IOHIDElementGetType( IOHIDElementRef element); + [DllImport(hid)] + public static extern IOHIDElementCookie IOHIDElementGetTypeID(); + [DllImport(hid)] public static extern int IOHIDElementGetUsage(IOHIDElementRef elem); From fbedac9a16a35db282579eda9bbf816c65dc91b5 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 12 Sep 2014 10:33:24 +0200 Subject: [PATCH 5/8] [Mac] Fixed Joystick Hat calculations --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 29 ++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index 76b53300..e40da70a 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -1037,8 +1037,33 @@ namespace OpenTK.Platform.MacOS { // 0 = up; 1 = up-right; 2 = right; 3 = right-down; // 4 = down; 5 = down-left; 6 = left; 7 = up-left - // Our HatPosition enum - position = (HatPosition)value; + switch (value) + { + case 0: + position = HatPosition.Up; + break; + case 1: + position = HatPosition.UpRight; + break; + case 2: + position = HatPosition.Right; + break; + case 3: + position = HatPosition.DownRight; + break; + case 4: + position = HatPosition.Down; + break; + case 5: + position = HatPosition.DownLeft; + break; + case 6: + position = HatPosition.Left; + break; + case 7: + position = HatPosition.UpLeft; + break; + } } else { From 2a6579032eba329be141fed8e224e31e17b43b94 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 15 Sep 2014 14:48:01 +0200 Subject: [PATCH 6/8] [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); From 2c26df8d934de800f52fa9554092adcfa0cafa7a Mon Sep 17 00:00:00 2001 From: thefiddler Date: Wed, 17 Sep 2014 18:15:05 +0200 Subject: [PATCH 7/8] [Input] Added From* overloads with out parameters --- Source/OpenTK/Platform/DeviceCollection.cs | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Source/OpenTK/Platform/DeviceCollection.cs b/Source/OpenTK/Platform/DeviceCollection.cs index 04ac1015..804dac9d 100644 --- a/Source/OpenTK/Platform/DeviceCollection.cs +++ b/Source/OpenTK/Platform/DeviceCollection.cs @@ -115,6 +115,20 @@ namespace OpenTK.Platform } } + public bool FromIndex(int index, out T device) + { + if (index >= 0 && index < Devices.Count) + { + device = Devices[index]; + return true; + } + else + { + device = default(T); + return false; + } + } + public T FromHardwareId(long id) { if (Map.ContainsKey(id)) @@ -127,6 +141,20 @@ namespace OpenTK.Platform } } + public bool FromHardwareId(long id, out T device) + { + if (Map.ContainsKey(id)) + { + device = FromIndex(Map[id]); + return true; + } + else + { + device = default(T); + return false; + } + } + public int Count { get { return Map.Count; } From 8642177c30cd61eda8de56373b1806ea37d1b63f Mon Sep 17 00:00:00 2001 From: thefiddler Date: Wed, 17 Sep 2014 18:15:56 +0200 Subject: [PATCH 8/8] [Mac] Use DeviceCollection This reduces code duplication significantly. --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 204 +++++++++-------------- 1 file changed, 79 insertions(+), 125 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index b423ab97..a743954d 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -59,16 +59,29 @@ namespace OpenTK.Platform.MacOS class MouseData { + public IntPtr Id; public MouseState State; + + public MouseData(IntPtr id) + { + Id = id; + } } class KeyboardData { + public IntPtr Id; public KeyboardState State; + + public KeyboardData(IntPtr id) + { + Id = id; + } } class JoystickData { + public IntPtr Id; public string Name; public Guid Guid; public JoystickState State; @@ -77,6 +90,11 @@ namespace OpenTK.Platform.MacOS readonly public Dictionary Elements = new Dictionary(); + public JoystickData(IntPtr id) + { + Id = id; + } + public void AddElement(JoystickElement e) { if (!Elements.ContainsKey(e.Cookie)) @@ -145,20 +163,12 @@ namespace OpenTK.Platform.MacOS IOHIDManagerRef hidmanager; - readonly Dictionary MouseDevices = - new Dictionary(new IntPtrEqualityComparer()); - readonly Dictionary MouseIndexToDevice = - new Dictionary(); - - readonly Dictionary KeyboardDevices = - new Dictionary(new IntPtrEqualityComparer()); - readonly Dictionary KeyboardIndexToDevice = - new Dictionary(); - - readonly Dictionary JoystickDevices = - new Dictionary(new IntPtrEqualityComparer()); - readonly Dictionary JoystickIndexToDevice = - new Dictionary(); + readonly DeviceCollection MouseDevices = + new DeviceCollection(); + readonly DeviceCollection KeyboardDevices = + new DeviceCollection(); + readonly DeviceCollection JoystickDevices = + new DeviceCollection(); readonly CFRunLoop RunLoop; readonly CFString InputLoopMode = CF.RunLoopModeDefault; @@ -393,22 +403,27 @@ namespace OpenTK.Platform.MacOS try { bool recognized = false; + long id = device.ToInt64(); - if (MouseDevices.ContainsKey(device)) + MouseData mouse; + KeyboardData keyboard; + JoystickData joystick; + + if (MouseDevices.FromHardwareId(id, out mouse)) { - RemoveMouse(sender, device); + RemoveMouse(sender, id); recognized = true; } - if (KeyboardDevices.ContainsKey(device)) + if (KeyboardDevices.FromHardwareId(id, out keyboard)) { - RemoveKeyboard(sender, device); + RemoveKeyboard(sender, id); recognized = true; } - if (JoystickDevices.ContainsKey(device)) + if (JoystickDevices.FromHardwareId(id, out joystick)) { - RemoveJoystick(sender, device); + RemoveJoystick(sender, id); recognized = true; } @@ -439,15 +454,16 @@ namespace OpenTK.Platform.MacOS MouseData mouse; KeyboardData keyboard; JoystickData joystick; - if (MouseDevices.TryGetValue(context, out mouse)) + long id = context.ToInt64(); + if (MouseDevices.FromHardwareId(id, out mouse)) { UpdateMouse(mouse, val); } - else if (KeyboardDevices.TryGetValue(context, out keyboard)) + else if (KeyboardDevices.FromHardwareId(id, out keyboard)) { UpdateKeyboard(keyboard, val); } - else if (JoystickDevices.TryGetValue(context, out joystick)) + else if (JoystickDevices.FromHardwareId(id, out joystick)) { UpdateJoystick(joystick, val); } @@ -466,24 +482,16 @@ namespace OpenTK.Platform.MacOS void AddMouse(CFAllocatorRef sender, CFAllocatorRef device) { - if (!MouseDevices.ContainsKey(device)) - { - Debug.Print("Mouse device {0:x} discovered, sender is {1:x}", device, sender); - MouseIndexToDevice.Add(MouseDevices.Count, device); - MouseDevices.Add(device, new MouseData()); - } - else - { - Debug.Print("Mouse device {0:x} reconnected, sender is {1:x}", device, sender); - } - MouseDevices[device].State.SetIsConnected(true); + Debug.Print("Mouse device {0:x} discovered, sender is {1:x}", device, sender); + MouseData mouse = new MouseData(device); + mouse.State.SetIsConnected(true); + MouseDevices.Add(device.ToInt64(), mouse); } - void RemoveMouse(CFAllocatorRef sender, CFAllocatorRef device) + void RemoveMouse(CFAllocatorRef sender, long id) { - Debug.Print("Mouse device {0:x} disconnected, sender is {1:x}", device, sender); - // Keep the device in case it comes back later on - MouseDevices[device].State.SetIsConnected(false); + Debug.Print("Mouse device {0:x} disconnected, sender is {1:x}", id, sender); + MouseDevices.Remove(id); } static void UpdateMouse(MouseData mouse, IOHIDValueRef val) @@ -540,24 +548,16 @@ namespace OpenTK.Platform.MacOS void AddKeyboard(CFAllocatorRef sender, CFAllocatorRef device) { - if (!KeyboardDevices.ContainsKey(device)) - { - Debug.Print("Keyboard device {0:x} discovered, sender is {1:x}", device, sender); - KeyboardIndexToDevice.Add(KeyboardDevices.Count, device); - KeyboardDevices.Add(device, new KeyboardData()); - } - else - { - Debug.Print("Keyboard device {0:x} reconnected, sender is {1:x}", device, sender); - } - KeyboardDevices[device].State.SetIsConnected(true); + Debug.Print("Keyboard device {0:x} discovered, sender is {1:x}", device, sender); + KeyboardData keyboard = new KeyboardData(device); + keyboard.State.SetIsConnected(true); + KeyboardDevices.Add(device.ToInt64(), keyboard); } - void RemoveKeyboard(CFAllocatorRef sender, CFAllocatorRef device) + void RemoveKeyboard(CFAllocatorRef sender, long id) { - Debug.Print("Keyboard device {0:x} disconnected, sender is {1:x}", device, sender); - // Keep the device in case it comes back later on - KeyboardDevices[device].State.SetIsConnected(false); + Debug.Print("Keyboard device {0:x} disconnected, sender is {1:x}", id, sender); + KeyboardDevices.Remove(id); } static void UpdateKeyboard(KeyboardData keyboard, IOHIDValueRef val) @@ -651,7 +651,7 @@ namespace OpenTK.Platform.MacOS CFArrayRef element_array_ref = NativeMethods.IOHIDDeviceCopyMatchingElements(device, IntPtr.Zero, IntPtr.Zero); if (element_array_ref != IntPtr.Zero) { - joy = new JoystickData(); + joy = new JoystickData(device); CFStringRef name_ref = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDProductKey); string name = CF.CFStringGetCString(name_ref); @@ -823,16 +823,7 @@ namespace OpenTK.Platform.MacOS JoystickData GetJoystick(int index) { - IntPtr device; - if (JoystickIndexToDevice.TryGetValue(index, out device)) - { - JoystickData joystick; - if (JoystickDevices.TryGetValue(device, out joystick)) - { - return joystick; - } - } - return null; + return JoystickDevices.FromIndex(index); } void AddJoystick(CFAllocatorRef sender, CFAllocatorRef device) @@ -845,42 +836,7 @@ namespace OpenTK.Platform.MacOS 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; - } - - // 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; - } + JoystickDevices.Add(device.ToInt64(), joy); } } finally @@ -889,12 +845,10 @@ namespace OpenTK.Platform.MacOS } } - void RemoveJoystick(CFAllocatorRef sender, CFAllocatorRef device) + void RemoveJoystick(CFAllocatorRef sender, long id) { - Debug.Print("Joystick device {0:x} disconnected, sender is {1:x}", device, sender); - // Keep the device in case it comes back later on - JoystickDevices[device].State = new JoystickState(); - JoystickDevices[device].Capabilities = new JoystickCapabilities(); + Debug.Print("Joystick device {0:x} disconnected, sender is {1:x}", id, sender); + JoystickDevices.Remove(id); } static void UpdateJoystick(JoystickData joy, IOHIDValueRef val) @@ -1064,9 +1018,9 @@ namespace OpenTK.Platform.MacOS MouseState IMouseDriver2.GetState() { MouseState master = new MouseState(); - foreach (KeyValuePair item in MouseDevices) + foreach (MouseData item in MouseDevices) { - master.MergeBits(item.Value.State); + master.MergeBits(item.State); } return master; @@ -1074,10 +1028,10 @@ namespace OpenTK.Platform.MacOS MouseState IMouseDriver2.GetState(int index) { - IntPtr device; - if (MouseIndexToDevice.TryGetValue(index, out device)) + MouseData mouse; + if (MouseDevices.FromIndex(index, out mouse)) { - return MouseDevices[device].State; + return mouse.State; } return new MouseState(); @@ -1101,9 +1055,9 @@ namespace OpenTK.Platform.MacOS KeyboardState IKeyboardDriver2.GetState() { KeyboardState master = new KeyboardState(); - foreach (KeyValuePair item in KeyboardDevices) + foreach (KeyboardData item in KeyboardDevices) { - master.MergeBits(item.Value.State); + master.MergeBits(item.State); } return master; @@ -1111,10 +1065,10 @@ namespace OpenTK.Platform.MacOS KeyboardState IKeyboardDriver2.GetState(int index) { - IntPtr device; - if (KeyboardIndexToDevice.TryGetValue(index, out device)) + KeyboardData keyboard; + if (KeyboardDevices.FromIndex(index, out keyboard)) { - return KeyboardDevices[device].State; + return keyboard.State; } return new KeyboardState(); @@ -1122,11 +1076,11 @@ namespace OpenTK.Platform.MacOS string IKeyboardDriver2.GetDeviceName(int index) { - IntPtr device; - if (KeyboardIndexToDevice.TryGetValue(index, out device)) + KeyboardData keyboard; + if (KeyboardDevices.FromIndex(index, out keyboard)) { - IntPtr vendor_id = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDVendorIDKey); - IntPtr product_id = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDProductIDKey); + IntPtr vendor_id = NativeMethods.IOHIDDeviceGetProperty(keyboard.Id, NativeMethods.IOHIDVendorIDKey); + IntPtr product_id = NativeMethods.IOHIDDeviceGetProperty(keyboard.Id, NativeMethods.IOHIDProductIDKey); // Todo: find out the real vendor/product name from the relevant ids. return String.Format("{0}:{1}", vendor_id, product_id); } @@ -1750,19 +1704,19 @@ namespace OpenTK.Platform.MacOS NativeMethods.IOHIDManagerUnscheduleFromRunLoop( hidmanager, RunLoop, InputLoopMode); - foreach (var device in MouseDevices.Keys) + foreach (var device in MouseDevices) { - DeviceRemoved(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, device); + DeviceRemoved(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, device.Id); } - foreach (var device in KeyboardDevices.Keys) + foreach (var device in KeyboardDevices) { - DeviceRemoved(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, device); + DeviceRemoved(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, device.Id); } - foreach (var device in JoystickDevices.Keys) + foreach (var device in JoystickDevices) { - DeviceRemoved(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, device); + DeviceRemoved(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, device.Id); } if (hidmanager != IntPtr.Zero)