Merge pull request #180 from thefiddler/mac_joystick
[Mac] Improve joystick driver
This commit is contained in:
commit
a1c3950b8a
3 changed files with 392 additions and 223 deletions
|
@ -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)
|
public T FromHardwareId(long id)
|
||||||
{
|
{
|
||||||
if (Map.ContainsKey(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
|
public int Count
|
||||||
{
|
{
|
||||||
get { return Map.Count; }
|
get { return Map.Count; }
|
||||||
|
|
|
@ -45,6 +45,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
using CFTypeRef = System.IntPtr;
|
using CFTypeRef = System.IntPtr;
|
||||||
using IOHIDDeviceRef = System.IntPtr;
|
using IOHIDDeviceRef = System.IntPtr;
|
||||||
using IOHIDElementRef = System.IntPtr;
|
using IOHIDElementRef = System.IntPtr;
|
||||||
|
using IOHIDElementCookie = System.IntPtr;
|
||||||
using IOHIDManagerRef = System.IntPtr;
|
using IOHIDManagerRef = System.IntPtr;
|
||||||
using IOHIDValueRef = System.IntPtr;
|
using IOHIDValueRef = System.IntPtr;
|
||||||
using IOOptionBits = System.IntPtr;
|
using IOOptionBits = System.IntPtr;
|
||||||
|
@ -58,42 +59,116 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
class MouseData
|
class MouseData
|
||||||
{
|
{
|
||||||
|
public IntPtr Id;
|
||||||
public MouseState State;
|
public MouseState State;
|
||||||
|
|
||||||
|
public MouseData(IntPtr id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KeyboardData
|
class KeyboardData
|
||||||
{
|
{
|
||||||
|
public IntPtr Id;
|
||||||
public KeyboardState State;
|
public KeyboardState State;
|
||||||
|
|
||||||
|
public KeyboardData(IntPtr id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class JoystickData
|
class JoystickData
|
||||||
{
|
{
|
||||||
|
public IntPtr Id;
|
||||||
public string Name;
|
public string Name;
|
||||||
public Guid Guid;
|
public Guid Guid;
|
||||||
public JoystickState State;
|
public JoystickState State;
|
||||||
public JoystickCapabilities Capabilities;
|
public JoystickCapabilities Capabilities;
|
||||||
readonly public Dictionary<int, JoystickButton> ElementUsageToButton =
|
|
||||||
new Dictionary<int, JoystickButton>();
|
readonly public Dictionary<IOHIDElementCookie, JoystickElement> Elements =
|
||||||
readonly public Dictionary<IOHIDElementRef, JoystickHat> ElementToHat =
|
new Dictionary<IOHIDElementCookie, JoystickElement>();
|
||||||
new Dictionary<IOHIDElementRef, JoystickHat>(new IntPtrEqualityComparer());
|
|
||||||
|
public JoystickData(IntPtr id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddElement(JoystickElement e)
|
||||||
|
{
|
||||||
|
if (!Elements.ContainsKey(e.Cookie))
|
||||||
|
{
|
||||||
|
Elements.Add(e.Cookie, e);
|
||||||
|
Debug.Print("Discovered joystick element {0:x} ({1}/{2})",
|
||||||
|
e.Cookie, e.Page, e.Usage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("Duplicate joystick element {0:x} ({1}/{2}) ignored.",
|
||||||
|
e.Cookie, e.Page, e.Usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JoystickElement : IComparable<JoystickElement>, IEquatable<JoystickElement>
|
||||||
|
{
|
||||||
|
public IntPtr Element;
|
||||||
|
public IntPtr Cookie;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Order in which this element was reported
|
||||||
|
public int Index;
|
||||||
|
|
||||||
|
public JoystickElement(
|
||||||
|
IntPtr element, IntPtr cookie,
|
||||||
|
HIDPage page, int usage,
|
||||||
|
int min, int max)
|
||||||
|
{
|
||||||
|
Element = element;
|
||||||
|
Cookie = cookie;
|
||||||
|
Page = page;
|
||||||
|
Usage = usage;
|
||||||
|
Min = min;
|
||||||
|
Max = max;
|
||||||
|
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;
|
IOHIDManagerRef hidmanager;
|
||||||
|
|
||||||
readonly Dictionary<IntPtr, MouseData> MouseDevices =
|
readonly DeviceCollection<MouseData> MouseDevices =
|
||||||
new Dictionary<IntPtr, MouseData>(new IntPtrEqualityComparer());
|
new DeviceCollection<MouseData>();
|
||||||
readonly Dictionary<int, IntPtr> MouseIndexToDevice =
|
readonly DeviceCollection<KeyboardData> KeyboardDevices =
|
||||||
new Dictionary<int, IntPtr>();
|
new DeviceCollection<KeyboardData>();
|
||||||
|
readonly DeviceCollection<JoystickData> JoystickDevices =
|
||||||
readonly Dictionary<IntPtr, KeyboardData> KeyboardDevices =
|
new DeviceCollection<JoystickData>();
|
||||||
new Dictionary<IntPtr, KeyboardData>(new IntPtrEqualityComparer());
|
|
||||||
readonly Dictionary<int, IntPtr> KeyboardIndexToDevice =
|
|
||||||
new Dictionary<int, IntPtr>();
|
|
||||||
|
|
||||||
readonly Dictionary<IntPtr, JoystickData> JoystickDevices =
|
|
||||||
new Dictionary<IntPtr, JoystickData>(new IntPtrEqualityComparer());
|
|
||||||
readonly Dictionary<int, IntPtr> JoystickIndexToDevice =
|
|
||||||
new Dictionary<int, IntPtr>();
|
|
||||||
|
|
||||||
readonly CFRunLoop RunLoop;
|
readonly CFRunLoop RunLoop;
|
||||||
readonly CFString InputLoopMode = CF.RunLoopModeDefault;
|
readonly CFString InputLoopMode = CF.RunLoopModeDefault;
|
||||||
|
@ -101,6 +176,12 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
readonly MappedGamePadDriver mapped_gamepad = new MappedGamePadDriver();
|
readonly MappedGamePadDriver mapped_gamepad = new MappedGamePadDriver();
|
||||||
|
|
||||||
|
// Used for device discovery
|
||||||
|
readonly List<JoystickElement> axis_elements = new List<JoystickElement>();
|
||||||
|
readonly List<JoystickElement> button_elements = new List<JoystickElement>();
|
||||||
|
readonly List<JoystickElement> hat_elements = new List<JoystickElement>();
|
||||||
|
readonly List<JoystickElement> vendor_elements = new List<JoystickElement>();
|
||||||
|
|
||||||
IntPtr MouseEventTap;
|
IntPtr MouseEventTap;
|
||||||
IntPtr MouseEventTapSource;
|
IntPtr MouseEventTapSource;
|
||||||
MouseState CursorState;
|
MouseState CursorState;
|
||||||
|
@ -322,22 +403,27 @@ namespace OpenTK.Platform.MacOS
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool recognized = false;
|
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;
|
recognized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (KeyboardDevices.ContainsKey(device))
|
if (KeyboardDevices.FromHardwareId(id, out keyboard))
|
||||||
{
|
{
|
||||||
RemoveKeyboard(sender, device);
|
RemoveKeyboard(sender, id);
|
||||||
recognized = true;
|
recognized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JoystickDevices.ContainsKey(device))
|
if (JoystickDevices.FromHardwareId(id, out joystick))
|
||||||
{
|
{
|
||||||
RemoveJoystick(sender, device);
|
RemoveJoystick(sender, id);
|
||||||
recognized = true;
|
recognized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,15 +454,16 @@ namespace OpenTK.Platform.MacOS
|
||||||
MouseData mouse;
|
MouseData mouse;
|
||||||
KeyboardData keyboard;
|
KeyboardData keyboard;
|
||||||
JoystickData joystick;
|
JoystickData joystick;
|
||||||
if (MouseDevices.TryGetValue(context, out mouse))
|
long id = context.ToInt64();
|
||||||
|
if (MouseDevices.FromHardwareId(id, out mouse))
|
||||||
{
|
{
|
||||||
UpdateMouse(mouse, val);
|
UpdateMouse(mouse, val);
|
||||||
}
|
}
|
||||||
else if (KeyboardDevices.TryGetValue(context, out keyboard))
|
else if (KeyboardDevices.FromHardwareId(id, out keyboard))
|
||||||
{
|
{
|
||||||
UpdateKeyboard(keyboard, val);
|
UpdateKeyboard(keyboard, val);
|
||||||
}
|
}
|
||||||
else if (JoystickDevices.TryGetValue(context, out joystick))
|
else if (JoystickDevices.FromHardwareId(id, out joystick))
|
||||||
{
|
{
|
||||||
UpdateJoystick(joystick, val);
|
UpdateJoystick(joystick, val);
|
||||||
}
|
}
|
||||||
|
@ -395,24 +482,16 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
void AddMouse(CFAllocatorRef sender, CFAllocatorRef device)
|
void AddMouse(CFAllocatorRef sender, CFAllocatorRef device)
|
||||||
{
|
{
|
||||||
if (!MouseDevices.ContainsKey(device))
|
Debug.Print("Mouse device {0:x} discovered, sender is {1:x}", device, sender);
|
||||||
{
|
MouseData mouse = new MouseData(device);
|
||||||
Debug.Print("Mouse device {0:x} discovered, sender is {1:x}", device, sender);
|
mouse.State.SetIsConnected(true);
|
||||||
MouseIndexToDevice.Add(MouseDevices.Count, device);
|
MouseDevices.Add(device.ToInt64(), mouse);
|
||||||
MouseDevices.Add(device, new MouseData());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Print("Mouse device {0:x} reconnected, sender is {1:x}", device, sender);
|
|
||||||
}
|
|
||||||
MouseDevices[device].State.SetIsConnected(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
Debug.Print("Mouse device {0:x} disconnected, sender is {1:x}", id, sender);
|
||||||
// Keep the device in case it comes back later on
|
MouseDevices.Remove(id);
|
||||||
MouseDevices[device].State.SetIsConnected(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateMouse(MouseData mouse, IOHIDValueRef val)
|
static void UpdateMouse(MouseData mouse, IOHIDValueRef val)
|
||||||
|
@ -469,24 +548,16 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
void AddKeyboard(CFAllocatorRef sender, CFAllocatorRef device)
|
void AddKeyboard(CFAllocatorRef sender, CFAllocatorRef device)
|
||||||
{
|
{
|
||||||
if (!KeyboardDevices.ContainsKey(device))
|
Debug.Print("Keyboard device {0:x} discovered, sender is {1:x}", device, sender);
|
||||||
{
|
KeyboardData keyboard = new KeyboardData(device);
|
||||||
Debug.Print("Keyboard device {0:x} discovered, sender is {1:x}", device, sender);
|
keyboard.State.SetIsConnected(true);
|
||||||
KeyboardIndexToDevice.Add(KeyboardDevices.Count, device);
|
KeyboardDevices.Add(device.ToInt64(), keyboard);
|
||||||
KeyboardDevices.Add(device, new KeyboardData());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Print("Keyboard device {0:x} reconnected, sender is {1:x}", device, sender);
|
|
||||||
}
|
|
||||||
KeyboardDevices[device].State.SetIsConnected(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
Debug.Print("Keyboard device {0:x} disconnected, sender is {1:x}", id, sender);
|
||||||
// Keep the device in case it comes back later on
|
KeyboardDevices.Remove(id);
|
||||||
KeyboardDevices[device].State.SetIsConnected(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateKeyboard(KeyboardData keyboard, IOHIDValueRef val)
|
static void UpdateKeyboard(KeyboardData keyboard, IOHIDValueRef val)
|
||||||
|
@ -558,7 +629,18 @@ namespace OpenTK.Platform.MacOS
|
||||||
guid_bytes.AddRange(name_bytes);
|
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)
|
JoystickData CreateJoystick(IntPtr sender, IntPtr device)
|
||||||
|
@ -569,178 +651,220 @@ namespace OpenTK.Platform.MacOS
|
||||||
CFArrayRef element_array_ref = NativeMethods.IOHIDDeviceCopyMatchingElements(device, IntPtr.Zero, IntPtr.Zero);
|
CFArrayRef element_array_ref = NativeMethods.IOHIDDeviceCopyMatchingElements(device, IntPtr.Zero, IntPtr.Zero);
|
||||||
if (element_array_ref != IntPtr.Zero)
|
if (element_array_ref != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
joy = new JoystickData();
|
joy = new JoystickData(device);
|
||||||
int axes = 0;
|
|
||||||
int buttons = 0;
|
|
||||||
int hats = 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);
|
||||||
|
|
||||||
Guid guid = CreateJoystickGuid(device, name);
|
Guid guid = CreateJoystickGuid(device, name);
|
||||||
|
|
||||||
List<int> button_elements = new List<int>();
|
axis_elements.Clear();
|
||||||
List<IOHIDElementRef> hat_elements = new List<CFAllocatorRef>();
|
button_elements.Clear();
|
||||||
CFArray element_array = new CFArray(element_array_ref);
|
hat_elements.Clear();
|
||||||
for (int i = 0; i < element_array.Count; i++)
|
vendor_elements.Clear();
|
||||||
|
AddElements(joy, element_array_ref);
|
||||||
|
|
||||||
|
// Ensure a stable sorting order that matches SDL2.
|
||||||
|
// (This is necessary for the gamepad database).
|
||||||
|
axis_elements.Sort();
|
||||||
|
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++)
|
||||||
{
|
{
|
||||||
IOHIDElementRef element_ref = element_array[i];
|
JoystickElement e = axis_elements[i];
|
||||||
HIDPage page = NativeMethods.IOHIDElementGetUsagePage(element_ref);
|
e.Index = i;
|
||||||
int usage = NativeMethods.IOHIDElementGetUsage(element_ref);
|
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:
|
|
||||||
axes++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HIDUsageGD.Hatswitch:
|
|
||||||
hats++;
|
|
||||||
hat_elements.Add(element_ref);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HIDPage.Simulation:
|
|
||||||
switch ((HIDUsageSim)usage)
|
|
||||||
{
|
|
||||||
case HIDUsageSim.Rudder:
|
|
||||||
case HIDUsageSim.Throttle:
|
|
||||||
axes++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HIDPage.Button:
|
|
||||||
button_elements.Add(usage);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (axes > JoystickState.MaxAxes)
|
for (int i = 0; i < Math.Min(button_elements.Count, JoystickState.MaxButtons); i++)
|
||||||
|
{
|
||||||
|
JoystickElement e = button_elements[i];
|
||||||
|
e.Index = i;
|
||||||
|
joy.AddElement(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Math.Min(hat_elements.Count, JoystickState.MaxHats); i++)
|
||||||
|
{
|
||||||
|
JoystickElement e = hat_elements[i];
|
||||||
|
e.Index = i;
|
||||||
|
joy.AddElement(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < vendor_elements.Count; i++)
|
||||||
|
{
|
||||||
|
JoystickElement e = vendor_elements[i];
|
||||||
|
e.Index = i;
|
||||||
|
joy.AddElement(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
// 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);
|
CF.CFRelease(element_array_ref);
|
||||||
|
|
||||||
return joy;
|
return joy;
|
||||||
}
|
}
|
||||||
|
|
||||||
JoystickData GetJoystick(int index)
|
void AddElements(JoystickData joy, CFArrayRef element_array_ref)
|
||||||
{
|
{
|
||||||
IntPtr device;
|
CFArray element_array = new CFArray(element_array_ref);
|
||||||
if (JoystickIndexToDevice.TryGetValue(index, out device))
|
for (int i = 0; i < element_array.Count; i++)
|
||||||
{
|
{
|
||||||
JoystickData joystick;
|
IOHIDElementRef element_ref = element_array[i];
|
||||||
if (JoystickDevices.TryGetValue(device, out joystick))
|
|
||||||
|
if (element_ref != IntPtr.Zero && CF.CFGetTypeID(element_ref) == NativeMethods.IOHIDElementGetTypeID())
|
||||||
{
|
{
|
||||||
return joystick;
|
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))
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
|
||||||
|
if (!axis_elements.Contains(e))
|
||||||
|
{
|
||||||
|
axis_elements.Add(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HIDUsageGD.Hatswitch:
|
||||||
|
e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
|
||||||
|
if (!hat_elements.Contains(e))
|
||||||
|
{
|
||||||
|
hat_elements.Add(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HIDPage.Simulation:
|
||||||
|
switch ((HIDUsageSim)usage)
|
||||||
|
{
|
||||||
|
case HIDUsageSim.Rudder:
|
||||||
|
case HIDUsageSim.Throttle:
|
||||||
|
e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
|
||||||
|
if (!axis_elements.Contains(e))
|
||||||
|
{
|
||||||
|
axis_elements.Add(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HIDPage.Button:
|
||||||
|
e = new JoystickElement(element_ref, cookie, page, usage, 0, 0);
|
||||||
|
if (!button_elements.Contains(e))
|
||||||
|
{
|
||||||
|
button_elements.Add(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HIDPage.VendorDefinedStart:
|
||||||
|
e = new JoystickElement(element_ref, cookie, 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);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
}
|
||||||
|
|
||||||
|
JoystickData GetJoystick(int index)
|
||||||
|
{
|
||||||
|
return JoystickDevices.FromIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
JoystickData joy = CreateJoystick(sender, device);
|
Debug.Indent();
|
||||||
if (joy != null)
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// Add a device->joy lookup entry for this device.
|
JoystickData joy = CreateJoystick(sender, device);
|
||||||
if (!JoystickDevices.ContainsKey(device))
|
if (joy != null)
|
||||||
{
|
{
|
||||||
// First time we've seen this device.
|
JoystickDevices.Add(device.ToInt64(), joy);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Debug.Unindent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
Debug.Print("Joystick device {0:x} disconnected, sender is {1:x}", id, sender);
|
||||||
// Keep the device in case it comes back later on
|
JoystickDevices.Remove(id);
|
||||||
JoystickDevices[device].State = new JoystickState();
|
|
||||||
JoystickDevices[device].Capabilities = new JoystickCapabilities();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateJoystick(JoystickData joy, IOHIDValueRef val)
|
static void UpdateJoystick(JoystickData joy, IOHIDValueRef val)
|
||||||
{
|
{
|
||||||
IOHIDElementRef elem = NativeMethods.IOHIDValueGetElement(val);
|
IOHIDElementRef elem = NativeMethods.IOHIDValueGetElement(val);
|
||||||
|
IOHIDElementCookie cookie = NativeMethods.IOHIDElementGetCookie(elem);
|
||||||
HIDPage page = NativeMethods.IOHIDElementGetUsagePage(elem);
|
HIDPage page = NativeMethods.IOHIDElementGetUsagePage(elem);
|
||||||
int usage = NativeMethods.IOHIDElementGetUsage(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)
|
switch (page)
|
||||||
{
|
{
|
||||||
case HIDPage.GenericDesktop:
|
case HIDPage.GenericDesktop:
|
||||||
|
@ -756,7 +880,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 = HidHelper.TranslateJoystickAxis(page, usage);
|
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);
|
||||||
|
@ -765,7 +889,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
case HIDUsageGD.Hatswitch:
|
case HIDUsageGD.Hatswitch:
|
||||||
HatPosition position = GetJoystickHat(val, elem);
|
HatPosition position = GetJoystickHat(val, elem);
|
||||||
JoystickHat hat = TranslateJoystickHat(joy, elem);
|
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));
|
||||||
|
@ -780,7 +904,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 = HidHelper.TranslateJoystickAxis(page, usage);
|
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);
|
||||||
|
@ -792,7 +916,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
case HIDPage.Button:
|
case HIDPage.Button:
|
||||||
{
|
{
|
||||||
bool pressed = GetJoystickButton(val, elem);
|
bool pressed = GetJoystickButton(val, elem);
|
||||||
JoystickButton button = TranslateJoystickButton(joy, usage);
|
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);
|
||||||
|
@ -817,16 +941,6 @@ namespace OpenTK.Platform.MacOS
|
||||||
return value >= 1;
|
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)
|
static HatPosition GetJoystickHat(IOHIDValueRef val, IOHIDElementRef element)
|
||||||
{
|
{
|
||||||
HatPosition position = HatPosition.Centered;
|
HatPosition position = HatPosition.Centered;
|
||||||
|
@ -849,8 +963,33 @@ namespace OpenTK.Platform.MacOS
|
||||||
{
|
{
|
||||||
// 0 = up; 1 = up-right; 2 = right; 3 = right-down;
|
// 0 = up; 1 = up-right; 2 = right; 3 = right-down;
|
||||||
// 4 = down; 5 = down-left; 6 = left; 7 = up-left
|
// 4 = down; 5 = down-left; 6 = left; 7 = up-left
|
||||||
// Our HatPosition enum
|
switch (value)
|
||||||
position = (HatPosition)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
|
else
|
||||||
{
|
{
|
||||||
|
@ -861,16 +1000,6 @@ namespace OpenTK.Platform.MacOS
|
||||||
return position;
|
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
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -889,9 +1018,9 @@ namespace OpenTK.Platform.MacOS
|
||||||
MouseState IMouseDriver2.GetState()
|
MouseState IMouseDriver2.GetState()
|
||||||
{
|
{
|
||||||
MouseState master = new MouseState();
|
MouseState master = new MouseState();
|
||||||
foreach (KeyValuePair<IntPtr, MouseData> item in MouseDevices)
|
foreach (MouseData item in MouseDevices)
|
||||||
{
|
{
|
||||||
master.MergeBits(item.Value.State);
|
master.MergeBits(item.State);
|
||||||
}
|
}
|
||||||
|
|
||||||
return master;
|
return master;
|
||||||
|
@ -899,10 +1028,10 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
MouseState IMouseDriver2.GetState(int index)
|
MouseState IMouseDriver2.GetState(int index)
|
||||||
{
|
{
|
||||||
IntPtr device;
|
MouseData mouse;
|
||||||
if (MouseIndexToDevice.TryGetValue(index, out device))
|
if (MouseDevices.FromIndex(index, out mouse))
|
||||||
{
|
{
|
||||||
return MouseDevices[device].State;
|
return mouse.State;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MouseState();
|
return new MouseState();
|
||||||
|
@ -926,9 +1055,9 @@ namespace OpenTK.Platform.MacOS
|
||||||
KeyboardState IKeyboardDriver2.GetState()
|
KeyboardState IKeyboardDriver2.GetState()
|
||||||
{
|
{
|
||||||
KeyboardState master = new KeyboardState();
|
KeyboardState master = new KeyboardState();
|
||||||
foreach (KeyValuePair<IntPtr, KeyboardData> item in KeyboardDevices)
|
foreach (KeyboardData item in KeyboardDevices)
|
||||||
{
|
{
|
||||||
master.MergeBits(item.Value.State);
|
master.MergeBits(item.State);
|
||||||
}
|
}
|
||||||
|
|
||||||
return master;
|
return master;
|
||||||
|
@ -936,10 +1065,10 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
KeyboardState IKeyboardDriver2.GetState(int index)
|
KeyboardState IKeyboardDriver2.GetState(int index)
|
||||||
{
|
{
|
||||||
IntPtr device;
|
KeyboardData keyboard;
|
||||||
if (KeyboardIndexToDevice.TryGetValue(index, out device))
|
if (KeyboardDevices.FromIndex(index, out keyboard))
|
||||||
{
|
{
|
||||||
return KeyboardDevices[device].State;
|
return keyboard.State;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new KeyboardState();
|
return new KeyboardState();
|
||||||
|
@ -947,11 +1076,11 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
string IKeyboardDriver2.GetDeviceName(int index)
|
string IKeyboardDriver2.GetDeviceName(int index)
|
||||||
{
|
{
|
||||||
IntPtr device;
|
KeyboardData keyboard;
|
||||||
if (KeyboardIndexToDevice.TryGetValue(index, out device))
|
if (KeyboardDevices.FromIndex(index, out keyboard))
|
||||||
{
|
{
|
||||||
IntPtr vendor_id = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDVendorIDKey);
|
IntPtr vendor_id = NativeMethods.IOHIDDeviceGetProperty(keyboard.Id, NativeMethods.IOHIDVendorIDKey);
|
||||||
IntPtr product_id = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDProductIDKey);
|
IntPtr product_id = NativeMethods.IOHIDDeviceGetProperty(keyboard.Id, NativeMethods.IOHIDProductIDKey);
|
||||||
// Todo: find out the real vendor/product name from the relevant ids.
|
// Todo: find out the real vendor/product name from the relevant ids.
|
||||||
return String.Format("{0}:{1}", vendor_id, product_id);
|
return String.Format("{0}:{1}", vendor_id, product_id);
|
||||||
}
|
}
|
||||||
|
@ -1121,6 +1250,12 @@ namespace OpenTK.Platform.MacOS
|
||||||
[DllImport(hid)]
|
[DllImport(hid)]
|
||||||
public static extern IOHIDElementRef IOHIDValueGetElement(IOHIDValueRef @value);
|
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);
|
||||||
|
|
||||||
[DllImport(hid)]
|
[DllImport(hid)]
|
||||||
public static extern CFIndex IOHIDValueGetIntegerValue(IOHIDValueRef @value);
|
public static extern CFIndex IOHIDValueGetIntegerValue(IOHIDValueRef @value);
|
||||||
|
|
||||||
|
@ -1133,6 +1268,9 @@ namespace OpenTK.Platform.MacOS
|
||||||
public static extern IOHIDElementType IOHIDElementGetType(
|
public static extern IOHIDElementType IOHIDElementGetType(
|
||||||
IOHIDElementRef element);
|
IOHIDElementRef element);
|
||||||
|
|
||||||
|
[DllImport(hid)]
|
||||||
|
public static extern IOHIDElementCookie IOHIDElementGetTypeID();
|
||||||
|
|
||||||
[DllImport(hid)]
|
[DllImport(hid)]
|
||||||
public static extern int IOHIDElementGetUsage(IOHIDElementRef elem);
|
public static extern int IOHIDElementGetUsage(IOHIDElementRef elem);
|
||||||
|
|
||||||
|
@ -1566,19 +1704,19 @@ namespace OpenTK.Platform.MacOS
|
||||||
NativeMethods.IOHIDManagerUnscheduleFromRunLoop(
|
NativeMethods.IOHIDManagerUnscheduleFromRunLoop(
|
||||||
hidmanager, RunLoop, InputLoopMode);
|
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)
|
if (hidmanager != IntPtr.Zero)
|
||||||
|
|
|
@ -112,6 +112,9 @@ namespace OpenTK.Platform.MacOS.Carbon
|
||||||
[DllImport(appServices)]
|
[DllImport(appServices)]
|
||||||
internal static extern IntPtr CFDictionaryGetValue(IntPtr theDictionary, IntPtr theKey);
|
internal static extern IntPtr CFDictionaryGetValue(IntPtr theDictionary, IntPtr theKey);
|
||||||
|
|
||||||
|
[DllImport(appServices)]
|
||||||
|
internal static extern IntPtr CFGetTypeID(IntPtr v);
|
||||||
|
|
||||||
[DllImport(appServices)]
|
[DllImport(appServices)]
|
||||||
internal static extern IntPtr CFRetain(CFTypeRef cf);
|
internal static extern IntPtr CFRetain(CFTypeRef cf);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue