diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c index faf79a687..8401ddb7c 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 519742da4..624c35e0a 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