| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | // Copyright 2013 Dolphin Emulator Project | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+ | 
					
						
							| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | // Refer to the license.txt file included. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include <sstream> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | #include <Foundation/Foundation.h> | 
					
						
							|  |  |  | #include <IOKit/hid/IOHIDLib.h> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 15:05:24 +12:00
										 |  |  | #include "Common/StringUtil.h" | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "InputCommon/ControllerInterface/OSX/OSXJoystick.h" | 
					
						
							| 
									
										
										
										
											2013-06-16 20:07:10 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | namespace ciface | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | namespace OSX | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-14 10:25:52 +02:00
										 |  |  | Joystick::Joystick(IOHIDDeviceRef device, std::string name) | 
					
						
							|  |  |  |     : m_device(device), m_device_name(name), m_ff_device(nullptr) | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Buttons | 
					
						
							|  |  |  |   NSDictionary* buttonDict = @{ | 
					
						
							|  |  |  |     @kIOHIDElementTypeKey : @(kIOHIDElementTypeInput_Button), | 
					
						
							|  |  |  |     @kIOHIDElementUsagePageKey : @(kHIDPage_Button) | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CFArrayRef buttons = | 
					
						
							|  |  |  |       IOHIDDeviceCopyMatchingElements(m_device, (CFDictionaryRef)buttonDict, kIOHIDOptionsTypeNone); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (buttons) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     for (int i = 0; i < CFArrayGetCount(buttons); i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       IOHIDElementRef e = (IOHIDElementRef)CFArrayGetValueAtIndex(buttons, i); | 
					
						
							|  |  |  |       // DeviceElementDebugPrint(e, nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       AddInput(new Button(e, m_device)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     CFRelease(buttons); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Axes | 
					
						
							|  |  |  |   NSDictionary* axisDict = @{ @kIOHIDElementTypeKey : @(kIOHIDElementTypeInput_Misc) }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CFArrayRef axes = | 
					
						
							|  |  |  |       IOHIDDeviceCopyMatchingElements(m_device, (CFDictionaryRef)axisDict, kIOHIDOptionsTypeNone); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (axes) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     for (int i = 0; i < CFArrayGetCount(axes); i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       IOHIDElementRef e = (IOHIDElementRef)CFArrayGetValueAtIndex(axes, i); | 
					
						
							|  |  |  |       // DeviceElementDebugPrint(e, nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (IOHIDElementGetUsage(e) == kHIDUsage_GD_Hatswitch) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         AddInput(new Hat(e, m_device, Hat::up)); | 
					
						
							|  |  |  |         AddInput(new Hat(e, m_device, Hat::right)); | 
					
						
							|  |  |  |         AddInput(new Hat(e, m_device, Hat::down)); | 
					
						
							|  |  |  |         AddInput(new Hat(e, m_device, Hat::left)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         AddAnalogInputs(new Axis(e, m_device, Axis::negative), | 
					
						
							|  |  |  |                         new Axis(e, m_device, Axis::positive)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     CFRelease(axes); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Force Feedback | 
					
						
							|  |  |  |   FFCAPABILITIES ff_caps; | 
					
						
							|  |  |  |   if (SUCCEEDED( | 
					
						
							|  |  |  |           ForceFeedback::FFDeviceAdapter::Create(IOHIDDeviceGetService(m_device), &m_ff_device)) && | 
					
						
							|  |  |  |       SUCCEEDED(FFDeviceGetForceFeedbackCapabilities(m_ff_device->m_device, &ff_caps))) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     InitForceFeedback(m_ff_device, ff_caps.numFfAxes); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-29 08:11:51 +09:00
										 |  |  | Joystick::~Joystick() | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_ff_device) | 
					
						
							|  |  |  |     m_ff_device->Release(); | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-14 05:06:08 +00:00
										 |  |  | std::string Joystick::GetName() const | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return m_device_name; | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-14 05:06:08 +00:00
										 |  |  | std::string Joystick::GetSource() const | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return "Input"; | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | ControlState Joystick::Button::GetState() const | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   IOHIDValueRef value; | 
					
						
							|  |  |  |   if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) | 
					
						
							|  |  |  |     return IOHIDValueGetIntegerValue(value); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-14 05:06:08 +00:00
										 |  |  | std::string Joystick::Button::GetName() const | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::ostringstream s; | 
					
						
							|  |  |  |   s << IOHIDElementGetUsage(m_element); | 
					
						
							| 
									
										
										
										
											2016-07-01 15:05:24 +12:00
										 |  |  |   return std::string("Button ") + StripSpaces(s.str()); | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | Joystick::Axis::Axis(IOHIDElementRef element, IOHIDDeviceRef device, direction dir) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     : m_element(element), m_device(device), m_direction(dir) | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Need to parse the element a bit first | 
					
						
							|  |  |  |   std::string description("unk"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int const usage = IOHIDElementGetUsage(m_element); | 
					
						
							|  |  |  |   switch (usage) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case kHIDUsage_GD_X: | 
					
						
							|  |  |  |     description = "X"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case kHIDUsage_GD_Y: | 
					
						
							|  |  |  |     description = "Y"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case kHIDUsage_GD_Z: | 
					
						
							|  |  |  |     description = "Z"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case kHIDUsage_GD_Rx: | 
					
						
							|  |  |  |     description = "Rx"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case kHIDUsage_GD_Ry: | 
					
						
							|  |  |  |     description = "Ry"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case kHIDUsage_GD_Rz: | 
					
						
							|  |  |  |     description = "Rz"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case kHIDUsage_GD_Wheel: | 
					
						
							|  |  |  |     description = "Wheel"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case kHIDUsage_Csmr_ACPan: | 
					
						
							|  |  |  |     description = "Pan"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-30 10:36:53 +00:00
										 |  |  |     IOHIDElementCookie elementCookie = IOHIDElementGetCookie(m_element); | 
					
						
							|  |  |  |     // This axis isn't a 'well-known' one so cook a descriptive and uniquely | 
					
						
							|  |  |  |     // identifiable name. macOS provides a 'cookie' for each element that | 
					
						
							|  |  |  |     // will persist between sessions and identify the same physical controller | 
					
						
							|  |  |  |     // element so we can use that as a component of the axis name | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     std::ostringstream s; | 
					
						
							| 
									
										
										
										
											2016-10-30 10:36:53 +00:00
										 |  |  |     s << "CK-"; | 
					
						
							|  |  |  |     s << elementCookie; | 
					
						
							| 
									
										
										
										
											2016-07-01 15:05:24 +12:00
										 |  |  |     description = StripSpaces(s.str()); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   m_name = std::string("Axis ") + description; | 
					
						
							|  |  |  |   m_name.append((m_direction == positive) ? "+" : "-"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   m_neutral = (IOHIDElementGetLogicalMax(m_element) + IOHIDElementGetLogicalMin(m_element)) / 2.; | 
					
						
							|  |  |  |   m_scale = 1 / fabs(IOHIDElementGetLogicalMax(m_element) - m_neutral); | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | ControlState Joystick::Axis::GetState() const | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   IOHIDValueRef value; | 
					
						
							| 
									
										
										
										
											2011-01-14 05:06:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // IOHIDValueGetIntegerValue() crashes when trying | 
					
						
							|  |  |  |     // to convert unusually large element values. | 
					
						
							|  |  |  |     if (IOHIDValueGetLength(value) > 2) | 
					
						
							|  |  |  |       return 0; | 
					
						
							| 
									
										
										
										
											2011-02-27 00:15:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     float position = IOHIDValueGetIntegerValue(value); | 
					
						
							| 
									
										
										
										
											2010-06-26 13:03:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     if (m_direction == positive && position > m_neutral) | 
					
						
							|  |  |  |       return (position - m_neutral) * m_scale; | 
					
						
							|  |  |  |     if (m_direction == negative && position < m_neutral) | 
					
						
							|  |  |  |       return (m_neutral - position) * m_scale; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2011-01-16 17:00:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return 0; | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-14 05:06:08 +00:00
										 |  |  | std::string Joystick::Axis::GetName() const | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return m_name; | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | Joystick::Hat::Hat(IOHIDElementRef element, IOHIDDeviceRef device, direction dir) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     : m_element(element), m_device(device), m_direction(dir) | 
					
						
							| 
									
										
										
										
											2011-01-16 17:00:17 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   switch (dir) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case up: | 
					
						
							|  |  |  |     m_name = "Up"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case right: | 
					
						
							|  |  |  |     m_name = "Right"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case down: | 
					
						
							|  |  |  |     m_name = "Down"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case left: | 
					
						
							|  |  |  |     m_name = "Left"; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     m_name = "unk"; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2011-01-16 17:00:17 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | ControlState Joystick::Hat::GetState() const | 
					
						
							| 
									
										
										
										
											2011-01-16 17:00:17 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   IOHIDValueRef value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int position = IOHIDValueGetIntegerValue(value); | 
					
						
							|  |  |  |     int min = IOHIDElementGetLogicalMin(m_element); | 
					
						
							|  |  |  |     int max = IOHIDElementGetLogicalMax(m_element); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // if the position is outside the min or max, don't register it as a valid button press | 
					
						
							|  |  |  |     if (position < min || position > max) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // normalize the position so that its lowest value is 0 | 
					
						
							|  |  |  |     position -= min; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (position) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |       if (m_direction == up) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							|  |  |  |       if (m_direction == up || m_direction == right) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 2: | 
					
						
							|  |  |  |       if (m_direction == right) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 3: | 
					
						
							|  |  |  |       if (m_direction == right || m_direction == down) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 4: | 
					
						
							|  |  |  |       if (m_direction == down) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 5: | 
					
						
							|  |  |  |       if (m_direction == down || m_direction == left) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 6: | 
					
						
							|  |  |  |       if (m_direction == left) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 7: | 
					
						
							|  |  |  |       if (m_direction == left || m_direction == up) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0; | 
					
						
							| 
									
										
										
										
											2011-01-16 17:00:17 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string Joystick::Hat::GetName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return m_name; | 
					
						
							| 
									
										
										
										
											2011-01-16 17:00:17 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-10-17 23:00:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | bool Joystick::IsSameDevice(const IOHIDDeviceRef other_device) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return m_device == other_device; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-04-27 07:33:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | } |