From 2c9fda17985ae7032da49b12af782815fd7fc775 Mon Sep 17 00:00:00 2001
From: greso <greso@macbook.lan>
Date: Tue, 7 Aug 2018 19:45:49 +0200
Subject: [PATCH] (macOS) Fix input issues

For my Xbox One Controller the min input for the hat is 1 and not 0. 0
points to the default state that is called after each button press.

On top of that the two axis for the trigger buttons were ignored. I
added some additional axis that are not present on my controller but
will probably help for other input devices.
---
 input/drivers_hid/iohidmanager_hid.c | 113 ++++++++++++++++++++++++---
 1 file changed, 102 insertions(+), 11 deletions(-)

diff --git a/input/drivers_hid/iohidmanager_hid.c b/input/drivers_hid/iohidmanager_hid.c
index c43ddf1358..77e9c6defd 100644
--- a/input/drivers_hid/iohidmanager_hid.c
+++ b/input/drivers_hid/iohidmanager_hid.c
@@ -43,7 +43,7 @@ typedef struct apple_hid
    IOHIDManagerRef ptr;
    joypad_connection_t *slots;
    uint32_t buttons[MAX_USERS];
-   int16_t axes[MAX_USERS][6];
+   int16_t axes[MAX_USERS][11];
    int8_t hats[MAX_USERS][2]; /* MacOS only supports 1 hat AFAICT */
 } iohidmanager_hid_t;
 
@@ -201,7 +201,7 @@ static int16_t iohidmanager_hid_joypad_axis(void *data,
    if (joyaxis == AXIS_NONE)
       return 0;
 
-   if (AXIS_NEG_GET(joyaxis) < 6)
+   if (AXIS_NEG_GET(joyaxis) < 11)
    {
       val += hid->axes[port][AXIS_NEG_GET(joyaxis)];
       val += pad_connection_get_axis(&hid->slots[port],
@@ -210,7 +210,7 @@ static int16_t iohidmanager_hid_joypad_axis(void *data,
       if (val >= 0)
          val = 0;
    }
-   else if (AXIS_POS_GET(joyaxis) < 6)
+   else if (AXIS_POS_GET(joyaxis) < 11)
    {
       val += hid->axes[port][AXIS_POS_GET(joyaxis)];
       val += pad_connection_get_axis(&hid->slots[port],
@@ -290,12 +290,16 @@ static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
 
                         if (tmp->cookie == (IOHIDElementCookie)cookie)
                         {
-                           CFIndex range = IOHIDElementGetLogicalMax(element) - IOHIDElementGetLogicalMin(element);
+                           CFIndex min = IOHIDElementGetLogicalMin(element);
+                           CFIndex range = IOHIDElementGetLogicalMax(element) - min;
                            CFIndex val   = IOHIDValueGetIntegerValue(value);
 
                            if (range == 3)
                               val *= 2;
 
+                           if(min == 1)
+                              val--;
+
                            switch(val)
                            {
                               case 0:
@@ -383,6 +387,39 @@ static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
                break;
          }
          break;
+      case kHIDPage_Simulation:
+          switch (type)
+          {
+             case kIOHIDElementTypeInput_Misc:
+                 switch (use)
+                 {
+                 default:
+                     tmp = adapter->axes;
+
+                     while (tmp && tmp->cookie != (IOHIDElementCookie)cookie)
+                     {
+                        tmp = tmp->next;
+                     }
+                     if (tmp)
+                     {
+                        if (tmp->cookie == (IOHIDElementCookie)cookie)
+                        {
+                           CFIndex min   = IOHIDElementGetPhysicalMin(element);
+                           CFIndex state = IOHIDValueGetIntegerValue(value) - min;
+                           CFIndex max   = IOHIDElementGetPhysicalMax(element) - min;
+                           float val     = (float)state / (float)max;
+
+                           hid->axes[adapter->slot][tmp->id] =
+                              ((val * 2.0f) - 1.0f) * 32767.0f;
+                        }
+                     }
+                     else
+                        pushed_button = 1;
+                     break;
+                 }
+                 break;
+          }
+          break;
    }
 
    if (pushed_button)
@@ -530,6 +567,21 @@ static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanag
 
 	/* get device unique id */
 	uint32_t deviceUniqueId = iohidmanager_hid_device_get_unique_id(device);
+
+    static const uint32_t axis_use_ids[11] =
+    {
+        kHIDUsage_GD_X,
+        kHIDUsage_GD_Y,
+        kHIDUsage_GD_Rx,
+        kHIDUsage_GD_Ry,
+        kHIDUsage_GD_Z,
+        kHIDUsage_GD_Rz,
+        kHIDUsage_Sim_Rudder,
+        kHIDUsage_Sim_Throttle,
+        kHIDUsage_Sim_Steering,
+        kHIDUsage_Sim_Accelerator,
+        kHIDUsage_Sim_Brake
+    };
 	
 	/* check if pad was already registered previously (by deterministic method)
 	 * if so do not re-add the pad */
@@ -548,8 +600,8 @@ static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanag
    int count;
    CFMutableArrayRef elements;
    CFRange range;
-   bool found_axis[6] =
-   { false, false, false, false, false, false };
+   bool found_axis[11] =
+   { false, false, false, false, false, false, false, false, false, false, false };
    apple_input_rec_t *tmp                   = NULL;
    apple_input_rec_t *tmpButtons            = NULL;
    apple_input_rec_t *tmpAxes               = NULL;
@@ -655,13 +707,11 @@ static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanag
                      default:
                         {
                            uint32_t i = 0;
-                           static const uint32_t axis_use_ids[6] =
-                           { 48, 49, 51, 52, 50, 53 };
 
-                           while (i < 6 && axis_use_ids[i] != use)
+                           while (i < 11 && axis_use_ids[i] != use)
                               i++;
 
-                           if (i < 6)
+                           if (i < 11)
                            {
 
                               apple_input_rec_t *axis = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t));
@@ -711,6 +761,47 @@ static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanag
                   break;
             }
             break;
+
+         case kHIDPage_Simulation:
+             switch (use)
+             {
+                 default:
+                 {
+                     uint32_t i = 0;
+
+                     while (i < 11 && axis_use_ids[i] != use)
+                        i++;
+
+                     if (i < 11)
+                     {
+                        apple_input_rec_t *axis = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t));
+                        axis->id                = i;
+                        axis->cookie            = (IOHIDElementCookie)cookie;
+                        axis->next              = NULL;
+
+                        if (iohidmanager_check_for_id(adapter->axes,i))
+                        {
+                           /* axis ID already exists, save to tmp for appending later */
+                           if (tmpAxes)
+                              iohidmanager_append_record(tmpAxes, axis);
+                           else
+                              tmpAxes           = axis;
+                        }
+                        else
+                        {
+                           found_axis[axis->id] = true;
+                           if (adapter->axes)
+                              iohidmanager_append_record(adapter->axes, axis);
+                           else
+                              adapter->axes     = axis;
+                        }
+                     }
+                     else
+                        detected_button = 1;
+                     }
+                     break;
+                }
+                break;
       }
 
       if (detected_button)
@@ -738,7 +829,7 @@ static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanag
    }
 
    /* take care of buttons/axes with duplicate 'use' values */
-   for (i = 0; i < 6; i++)
+   for (i = 0; i < 11; i++)
    {
       if (found_axis[i] == false && tmpAxes)
       {