Commit b90b59279ed82576045f1383648370ab0f5715fd

Sam Lantinga 2020-04-17T21:30:58

Added support for the Razer Atrox Arcade Stick

diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c
index faf79a6..8401ddb 100644
--- a/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -40,6 +40,9 @@
 /* The amount of time to wait after hotplug to send controller init sequence */
 #define CONTROLLER_INIT_DELAY_MS    1500 /* 475 for Xbox One S, 1275 for the PDP Battlefield 1 */
 
+/* The amount of time to wait after init for valid input */
+#define CONTROLLER_INPUT_DELAY_MS   50  /* 42 for Razer Wolverine Ultimate */
+
 /* Connect controller */
 static const Uint8 xboxone_init0[] = {
     0x04, 0x20, 0x00, 0x00
@@ -116,7 +119,9 @@ typedef struct {
     SDL_bool bluetooth;
     SDL_XboxOneWirelessProtocol wireless_protocol;
     SDL_bool initialized;
+    SDL_bool input_ready;
     Uint32 start_time;
+    Uint32 initialized_time;
     Uint8 sequence;
     Uint8 last_state[USB_PACKET_LENGTH];
     SDL_bool has_paddles;
@@ -319,6 +324,7 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
     ctx->bluetooth = IsBluetoothXboxOneController(device->vendor_id, device->product_id);
     ctx->initialized = ctx->bluetooth ? SDL_TRUE : SDL_FALSE;
     ctx->start_time = SDL_GetTicks();
+    ctx->input_ready = SDL_TRUE;
     ctx->sequence = 1;
     ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id);
 
@@ -377,8 +383,14 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, 
         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
+        if (ctx->vendor_id == USB_VENDOR_RAZER && ctx->product_id == USB_PRODUCT_RAZER_ATROX) {
+            /* The Razer Atrox has the right and left shoulder bits reversed */
+            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
+            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
+        } else {
+            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
+            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
+        }
         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
     }
@@ -448,12 +460,20 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, 
     if (axis == 32704) {
         axis = 32767;
     }
+    if (axis == -32768 && size == 30 && (data[22] & 0x80) != 0) {
+        axis = 32767;
+    }
     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
+
     axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
+    if (axis == -32768 && size == 30 && (data[22] & 0x40) != 0) {
+        axis = 32767;
+    }
     if (axis == 32704) {
         axis = 32767;
     }
     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
+
     axis = *(Sint16*)(&data[10]);
     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
     axis = *(Sint16*)(&data[12]);
@@ -700,6 +720,8 @@ HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
                 return SDL_FALSE;
             }
             ctx->initialized = SDL_TRUE;
+            ctx->initialized_time = SDL_GetTicks();
+            ctx->input_ready = SDL_FALSE;
         }
     }
 
@@ -743,12 +765,23 @@ HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
                         return SDL_FALSE;
                     }
                     ctx->initialized = SDL_TRUE;
+                    ctx->initialized_time = SDL_GetTicks();
+                    ctx->input_ready = SDL_FALSE;
                 }
                 break;
             case 0x03:
                 /* Controller heartbeat */
                 break;
             case 0x20:
+                if (!ctx->input_ready) {
+                    if (!SDL_TICKS_PASSED(SDL_GetTicks(), ctx->initialized_time + CONTROLLER_INPUT_DELAY_MS)) {
+#ifdef DEBUG_XBOX_PROTOCOL
+                        SDL_Log("Spurious input at %ums\n", SDL_GetTicks() - ctx->initialized_time);
+#endif
+                        break;
+                    }
+                    ctx->input_ready = SDL_TRUE;
+                }
                 HIDAPI_DriverXboxOne_HandleStatePacket(joystick, device->dev, ctx, data, size);
                 break;
             case 0x07:
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index 519742d..624c35e 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -38,6 +38,7 @@
 #define USB_PRODUCT_NINTENDO_SWITCH_PRO                 0x2009
 #define USB_PRODUCT_RAZER_PANTHERA                      0x0401
 #define USB_PRODUCT_RAZER_PANTHERA_EVO                  0x1008
+#define USB_PRODUCT_RAZER_ATROX                         0x0a00
 #define USB_PRODUCT_SONY_DS4                            0x05c4
 #define USB_PRODUCT_SONY_DS4_DONGLE                     0x0ba0
 #define USB_PRODUCT_SONY_DS4_SLIM                       0x09cc