Updated the HIDAPI Xbox One driver with support for Bluetooth Xbox One controllers
authorSam Lantinga <slouken@libsdl.org>
Mon, 02 Mar 2020 09:26:12 -0800
changeset 135682c4ec356333e
parent 13567 e5e55d467f7e
child 13569 af2f0ddf861a
Updated the HIDAPI Xbox One driver with support for Bluetooth Xbox One controllers
src/joystick/hidapi/SDL_hidapi_xbox360.c
src/joystick/hidapi/SDL_hidapi_xboxone.c
     1.1 --- a/src/joystick/hidapi/SDL_hidapi_xbox360.c	Mon Mar 02 09:03:55 2020 -0800
     1.2 +++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c	Mon Mar 02 09:26:12 2020 -0800
     1.3 @@ -285,6 +285,17 @@
     1.4          /* This is the old Bluetooth Xbox One S firmware, which isn't supported by this driver */
     1.5          return SDL_FALSE;
     1.6      }
     1.7 +#if defined(__MACOSX__)
     1.8 +    /* Wired Xbox One controllers are handled by this driver, interfacing with
     1.9 +       the 360Controller driver available from:
    1.10 +       https://github.com/360Controller/360Controller/releases
    1.11 +
    1.12 +       Bluetooth Xbox One controllers are handled by the SDL Xbox One driver
    1.13 +    */
    1.14 +    if (IsBluetoothXboxOneController(vendor_id, product_id)) {
    1.15 +        return SDL_FALSE;
    1.16 +    }
    1.17 +#endif
    1.18      return (type == SDL_CONTROLLER_TYPE_XBOX360 || type == SDL_CONTROLLER_TYPE_XBOXONE);
    1.19  #else
    1.20      return (type == SDL_CONTROLLER_TYPE_XBOX360);
    1.21 @@ -680,106 +691,6 @@
    1.22  }
    1.23  #endif /* __WIN32__ */
    1.24  
    1.25 -#ifdef __MACOSX__
    1.26 -static void
    1.27 -HIDAPI_DriverXboxOneS_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
    1.28 -{
    1.29 -    Sint16 axis;
    1.30 -
    1.31 -    if (ctx->last_state[14] != data[14]) {
    1.32 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
    1.33 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
    1.34 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
    1.35 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
    1.36 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
    1.37 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
    1.38 -    }
    1.39 -
    1.40 -    if (ctx->last_state[15] != data[15]) {
    1.41 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
    1.42 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
    1.43 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
    1.44 -    }
    1.45 -
    1.46 -    if (ctx->last_state[16] != data[16]) {
    1.47 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
    1.48 -    }
    1.49 -
    1.50 -    if (ctx->last_state[13] != data[13]) {
    1.51 -        SDL_bool dpad_up = SDL_FALSE;
    1.52 -        SDL_bool dpad_down = SDL_FALSE;
    1.53 -        SDL_bool dpad_left = SDL_FALSE;
    1.54 -        SDL_bool dpad_right = SDL_FALSE;
    1.55 -
    1.56 -        switch (data[13]) {
    1.57 -        case 1:
    1.58 -            dpad_up = SDL_TRUE;
    1.59 -            break;
    1.60 -        case 2:
    1.61 -            dpad_up = SDL_TRUE;
    1.62 -            dpad_right = SDL_TRUE;
    1.63 -            break;
    1.64 -        case 3:
    1.65 -            dpad_right = SDL_TRUE;
    1.66 -            break;
    1.67 -        case 4:
    1.68 -            dpad_right = SDL_TRUE;
    1.69 -            dpad_down = SDL_TRUE;
    1.70 -            break;
    1.71 -        case 5:
    1.72 -            dpad_down = SDL_TRUE;
    1.73 -            break;
    1.74 -        case 6:
    1.75 -            dpad_left = SDL_TRUE;
    1.76 -            dpad_down = SDL_TRUE;
    1.77 -            break;
    1.78 -        case 7:
    1.79 -            dpad_left = SDL_TRUE;
    1.80 -            break;
    1.81 -        case 8:
    1.82 -            dpad_up = SDL_TRUE;
    1.83 -            dpad_left = SDL_TRUE;
    1.84 -            break;
    1.85 -        default:
    1.86 -            break;
    1.87 -        }
    1.88 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
    1.89 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
    1.90 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
    1.91 -        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
    1.92 -    }
    1.93 -
    1.94 -    axis = (int)*(Uint16*)(&data[1]) - 0x8000;
    1.95 -    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
    1.96 -    axis = (int)*(Uint16*)(&data[3]) - 0x8000;
    1.97 -    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
    1.98 -    axis = (int)*(Uint16*)(&data[5]) - 0x8000;
    1.99 -    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   1.100 -    axis = (int)*(Uint16*)(&data[7]) - 0x8000;
   1.101 -    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   1.102 -
   1.103 -    axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
   1.104 -    if (axis == 32704) {
   1.105 -        axis = 32767;
   1.106 -    }
   1.107 -    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   1.108 -
   1.109 -    axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
   1.110 -    if (axis == 32704) {
   1.111 -        axis = 32767;
   1.112 -    }
   1.113 -    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   1.114 -
   1.115 -    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   1.116 -}
   1.117 -
   1.118 -static void
   1.119 -HIDAPI_DriverXboxOneS_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   1.120 -{
   1.121 -    SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   1.122 -}
   1.123 -#endif /* __MACOSX__ */
   1.124 -
   1.125  static SDL_bool
   1.126  HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
   1.127  {
   1.128 @@ -796,31 +707,7 @@
   1.129      }
   1.130  
   1.131      while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
   1.132 -#ifdef __WIN32__
   1.133          HIDAPI_DriverXbox360_HandleStatePacket(joystick, device->dev, ctx, data, size);
   1.134 -#else
   1.135 -        switch (data[0]) {
   1.136 -        case 0x00:
   1.137 -            HIDAPI_DriverXbox360_HandleStatePacket(joystick, device->dev, ctx, data, size);
   1.138 -            break;
   1.139 -#ifdef __MACOSX__
   1.140 -        case 0x01:
   1.141 -            HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, device->dev, ctx, data, size);
   1.142 -            break;
   1.143 -        case 0x02:
   1.144 -            HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, device->dev, ctx, data, size);
   1.145 -            break;
   1.146 -#endif
   1.147 -        default:
   1.148 -#ifdef DEBUG_JOYSTICK
   1.149 -            SDL_Log("Unknown Xbox 360 packet, size = %d\n", size);
   1.150 -            SDL_Log("%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
   1.151 -                data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
   1.152 -                data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16]);
   1.153 -#endif
   1.154 -            break;
   1.155 -        }
   1.156 -#endif /* __WIN32__ */
   1.157      }
   1.158  
   1.159      if (size < 0) {
     2.1 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c	Mon Mar 02 09:03:55 2020 -0800
     2.2 +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c	Mon Mar 02 09:26:12 2020 -0800
     2.3 @@ -108,14 +108,16 @@
     2.4  typedef struct {
     2.5      Uint16 vendor_id;
     2.6      Uint16 product_id;
     2.7 +    SDL_bool bluetooth;
     2.8 +    SDL_bool initialized;
     2.9      Uint32 start_time;
    2.10 -    SDL_bool initialized;
    2.11      Uint8 sequence;
    2.12      Uint8 last_state[USB_PACKET_LENGTH];
    2.13      SDL_bool has_paddles;
    2.14  } SDL_DriverXboxOne_Context;
    2.15  
    2.16  
    2.17 +#define DEBUG_XBOX_PROTOCOL
    2.18  #ifdef DEBUG_XBOX_PROTOCOL
    2.19  static void
    2.20  DumpPacket(const char *prefix, Uint8 *data, int size)
    2.21 @@ -187,64 +189,60 @@
    2.22  {
    2.23      Uint16 vendor_id = ctx->vendor_id;
    2.24      Uint16 product_id = ctx->product_id;
    2.25 -
    2.26 -    if (!IsBluetoothXboxOneController(vendor_id, product_id)) {
    2.27 -        int i;
    2.28 -        Uint8 init_packet[USB_PACKET_LENGTH];
    2.29 +    int i;
    2.30 +    Uint8 init_packet[USB_PACKET_LENGTH];
    2.31  
    2.32 -        for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
    2.33 -            const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
    2.34 +    for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
    2.35 +        const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
    2.36  
    2.37 -            if (packet->vendor_id && (vendor_id != packet->vendor_id)) {
    2.38 -                continue;
    2.39 -            }
    2.40 +        if (packet->vendor_id && (vendor_id != packet->vendor_id)) {
    2.41 +            continue;
    2.42 +        }
    2.43  
    2.44 -            if (packet->product_id && (product_id != packet->product_id)) {
    2.45 -                continue;
    2.46 -            }
    2.47 +        if (packet->product_id && (product_id != packet->product_id)) {
    2.48 +            continue;
    2.49 +        }
    2.50  
    2.51 -            if (packet->exclude_vendor_id && (vendor_id == packet->exclude_vendor_id)) {
    2.52 -                continue;
    2.53 -            }
    2.54 +        if (packet->exclude_vendor_id && (vendor_id == packet->exclude_vendor_id)) {
    2.55 +            continue;
    2.56 +        }
    2.57  
    2.58 -            if (packet->exclude_product_id && (product_id == packet->exclude_product_id)) {
    2.59 -                continue;
    2.60 -            }
    2.61 +        if (packet->exclude_product_id && (product_id == packet->exclude_product_id)) {
    2.62 +            continue;
    2.63 +        }
    2.64  
    2.65 -            SDL_memcpy(init_packet, packet->data, packet->size);
    2.66 -            if (init_packet[0] != 0x01) {
    2.67 -                init_packet[2] = ctx->sequence++;
    2.68 -            }
    2.69 -            if (hid_write(device->dev, init_packet, packet->size) != packet->size) {
    2.70 -                SDL_SetError("Couldn't write Xbox One initialization packet");
    2.71 -                return SDL_FALSE;
    2.72 -            }
    2.73 +        SDL_memcpy(init_packet, packet->data, packet->size);
    2.74 +        if (init_packet[0] != 0x01) {
    2.75 +            init_packet[2] = ctx->sequence++;
    2.76 +        }
    2.77 +        if (hid_write(device->dev, init_packet, packet->size) != packet->size) {
    2.78 +            SDL_SetError("Couldn't write Xbox One initialization packet");
    2.79 +            return SDL_FALSE;
    2.80 +        }
    2.81  
    2.82 -            if (packet->response[0]) {
    2.83 -                const Uint32 RESPONSE_TIMEOUT_MS = 50;
    2.84 -                Uint32 start = SDL_GetTicks();
    2.85 -                SDL_bool got_response = SDL_FALSE;
    2.86 +        if (packet->response[0]) {
    2.87 +            const Uint32 RESPONSE_TIMEOUT_MS = 50;
    2.88 +            Uint32 start = SDL_GetTicks();
    2.89 +            SDL_bool got_response = SDL_FALSE;
    2.90  
    2.91 -                while (!got_response && !SDL_TICKS_PASSED(SDL_GetTicks(), start + RESPONSE_TIMEOUT_MS)) {
    2.92 -                    Uint8 data[USB_PACKET_LENGTH];
    2.93 -                    int size;
    2.94 +            while (!got_response && !SDL_TICKS_PASSED(SDL_GetTicks(), start + RESPONSE_TIMEOUT_MS)) {
    2.95 +                Uint8 data[USB_PACKET_LENGTH];
    2.96 +                int size;
    2.97  
    2.98 -                    while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
    2.99 +                while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
   2.100  #ifdef DEBUG_XBOX_PROTOCOL
   2.101 -                        DumpPacket("Xbox One INIT packet: size = %d", data, size);
   2.102 +                    DumpPacket("Xbox One INIT packet: size = %d", data, size);
   2.103  #endif
   2.104 -                        if (size >= 2 && data[0] == packet->response[0] && data[1] == packet->response[1]) {
   2.105 -                            got_response = SDL_TRUE;
   2.106 -                        }
   2.107 +                    if (size >= 2 && data[0] == packet->response[0] && data[1] == packet->response[1]) {
   2.108 +                        got_response = SDL_TRUE;
   2.109                      }
   2.110                  }
   2.111 +            }
   2.112  #ifdef DEBUG_XBOX_PROTOCOL
   2.113 -                SDL_Log("Init sequence %d got response: %s\n", i, got_response ? "TRUE" : "FALSE");
   2.114 +            SDL_Log("Init sequence %d got response: %s\n", i, got_response ? "TRUE" : "FALSE");
   2.115  #endif
   2.116 -            }
   2.117          }
   2.118      }
   2.119 -
   2.120      return SDL_TRUE;
   2.121  }
   2.122  
   2.123 @@ -252,12 +250,14 @@
   2.124  HIDAPI_DriverXboxOne_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
   2.125  {
   2.126  #ifdef __LINUX__
   2.127 -    if (IsBluetoothXboxOneController(vendor_id, product_id)) {
   2.128 -        /* We can't do rumble on this device, hid_write() fails, so don't try to open it here */
   2.129 +    if (vendor_id == USB_VENDOR_POWERA && product_id == 0x541a) {
   2.130 +        /* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
   2.131          return SDL_FALSE;
   2.132      }
   2.133 -    if (vendor_id == USB_VENDOR_POWERA && product_id == 0x541a) {
   2.134 -        /* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
   2.135 +#endif
   2.136 +#ifdef __MACOSX__
   2.137 +    /* Wired Xbox One controllers are handled by the 360Controller driver */
   2.138 +    if (!IsBluetoothXboxOneController(vendor_id, product_id)) {
   2.139          return SDL_FALSE;
   2.140      }
   2.141  #endif
   2.142 @@ -308,6 +308,8 @@
   2.143  
   2.144      ctx->vendor_id = device->vendor_id;
   2.145      ctx->product_id = device->product_id;
   2.146 +    ctx->bluetooth = IsBluetoothXboxOneController(device->vendor_id, device->product_id);
   2.147 +    ctx->initialized = ctx->bluetooth ? SDL_TRUE : SDL_FALSE;
   2.148      ctx->start_time = SDL_GetTicks();
   2.149      ctx->sequence = 1;
   2.150      ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id);
   2.151 @@ -323,14 +325,27 @@
   2.152  static int
   2.153  HIDAPI_DriverXboxOne_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
   2.154  {
   2.155 -    Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
   2.156 +    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
   2.157 +
   2.158 +    if (ctx->bluetooth) {
   2.159 +        Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
   2.160 +
   2.161 +        rumble_packet[4] = (low_frequency_rumble >> 8);
   2.162 +        rumble_packet[5] = (high_frequency_rumble >> 8);
   2.163  
   2.164 -    /* Magnitude is 1..100 so scale the 16-bit input here */
   2.165 -    rumble_packet[8] = low_frequency_rumble / 655;
   2.166 -    rumble_packet[9] = high_frequency_rumble / 655;
   2.167 +        if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   2.168 +            return SDL_SetError("Couldn't send rumble packet");
   2.169 +        }
   2.170 +    } else {
   2.171 +        Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
   2.172  
   2.173 -    if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   2.174 -        return SDL_SetError("Couldn't send rumble packet");
   2.175 +        /* Magnitude is 1..100 so scale the 16-bit input here */
   2.176 +        rumble_packet[8] = low_frequency_rumble / 655;
   2.177 +        rumble_packet[9] = high_frequency_rumble / 655;
   2.178 +
   2.179 +        if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   2.180 +            return SDL_SetError("Couldn't send rumble packet");
   2.181 +        }
   2.182      }
   2.183      return 0;
   2.184  }
   2.185 @@ -456,6 +471,104 @@
   2.186      SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   2.187  }
   2.188  
   2.189 +static void
   2.190 +HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
   2.191 +{
   2.192 +    Sint16 axis;
   2.193 +
   2.194 +    if (ctx->last_state[14] != data[14]) {
   2.195 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   2.196 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   2.197 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   2.198 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   2.199 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   2.200 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   2.201 +    }
   2.202 +
   2.203 +    if (ctx->last_state[15] != data[15]) {
   2.204 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   2.205 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   2.206 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   2.207 +    }
   2.208 +
   2.209 +    if (ctx->last_state[16] != data[16]) {
   2.210 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   2.211 +    }
   2.212 +
   2.213 +    if (ctx->last_state[13] != data[13]) {
   2.214 +        SDL_bool dpad_up = SDL_FALSE;
   2.215 +        SDL_bool dpad_down = SDL_FALSE;
   2.216 +        SDL_bool dpad_left = SDL_FALSE;
   2.217 +        SDL_bool dpad_right = SDL_FALSE;
   2.218 +
   2.219 +        switch (data[13]) {
   2.220 +        case 1:
   2.221 +            dpad_up = SDL_TRUE;
   2.222 +            break;
   2.223 +        case 2:
   2.224 +            dpad_up = SDL_TRUE;
   2.225 +            dpad_right = SDL_TRUE;
   2.226 +            break;
   2.227 +        case 3:
   2.228 +            dpad_right = SDL_TRUE;
   2.229 +            break;
   2.230 +        case 4:
   2.231 +            dpad_right = SDL_TRUE;
   2.232 +            dpad_down = SDL_TRUE;
   2.233 +            break;
   2.234 +        case 5:
   2.235 +            dpad_down = SDL_TRUE;
   2.236 +            break;
   2.237 +        case 6:
   2.238 +            dpad_left = SDL_TRUE;
   2.239 +            dpad_down = SDL_TRUE;
   2.240 +            break;
   2.241 +        case 7:
   2.242 +            dpad_left = SDL_TRUE;
   2.243 +            break;
   2.244 +        case 8:
   2.245 +            dpad_up = SDL_TRUE;
   2.246 +            dpad_left = SDL_TRUE;
   2.247 +            break;
   2.248 +        default:
   2.249 +            break;
   2.250 +        }
   2.251 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   2.252 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   2.253 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   2.254 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   2.255 +    }
   2.256 +
   2.257 +    axis = (int)*(Uint16*)(&data[1]) - 0x8000;
   2.258 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   2.259 +    axis = (int)*(Uint16*)(&data[3]) - 0x8000;
   2.260 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   2.261 +    axis = (int)*(Uint16*)(&data[5]) - 0x8000;
   2.262 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   2.263 +    axis = (int)*(Uint16*)(&data[7]) - 0x8000;
   2.264 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   2.265 +
   2.266 +    axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
   2.267 +    if (axis == 32704) {
   2.268 +        axis = 32767;
   2.269 +    }
   2.270 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   2.271 +
   2.272 +    axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
   2.273 +    if (axis == 32704) {
   2.274 +        axis = 32767;
   2.275 +    }
   2.276 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   2.277 +
   2.278 +    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   2.279 +}
   2.280 +
   2.281 +static void
   2.282 +HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
   2.283 +{
   2.284 +    SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   2.285 +}
   2.286 +
   2.287  static SDL_bool
   2.288  HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
   2.289  {
   2.290 @@ -486,34 +599,50 @@
   2.291  #ifdef DEBUG_XBOX_PROTOCOL
   2.292          DumpPacket("Xbox One packet: size = %d", data, size);
   2.293  #endif
   2.294 -        switch (data[0]) {
   2.295 -        case 0x02:
   2.296 -            /* Controller is connected and waiting for initialization */
   2.297 -            if (!ctx->initialized) {
   2.298 -#ifdef DEBUG_XBOX_PROTOCOL
   2.299 -                SDL_Log("Delay after init: %ums\n", SDL_GetTicks() - ctx->start_time);
   2.300 +        if (ctx->bluetooth) {
   2.301 +            switch (data[0]) {
   2.302 +            case 0x01:
   2.303 +                HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, device->dev, ctx, data, size);
   2.304 +                break;
   2.305 +            case 0x02:
   2.306 +                HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, device->dev, ctx, data, size);
   2.307 +                break;
   2.308 +            default:
   2.309 +#ifdef DEBUG_JOYSTICK
   2.310 +                SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
   2.311  #endif
   2.312 -                if (!SendControllerInit(device, ctx)) {
   2.313 -                    HIDAPI_JoystickDisconnected(device, joystick->instance_id);
   2.314 -                    return SDL_FALSE;
   2.315 -                }
   2.316 -                ctx->initialized = SDL_TRUE;
   2.317 +                break;
   2.318              }
   2.319 -            break;
   2.320 -        case 0x03:
   2.321 -            /* Controller heartbeat */
   2.322 -            break;
   2.323 -        case 0x20:
   2.324 -            HIDAPI_DriverXboxOne_HandleStatePacket(joystick, device->dev, ctx, data, size);
   2.325 -            break;
   2.326 -        case 0x07:
   2.327 -            HIDAPI_DriverXboxOne_HandleModePacket(joystick, device->dev, ctx, data, size);
   2.328 -            break;
   2.329 -        default:
   2.330 +        } else {
   2.331 +            switch (data[0]) {
   2.332 +            case 0x02:
   2.333 +                /* Controller is connected and waiting for initialization */
   2.334 +                if (!ctx->initialized) {
   2.335 +#ifdef DEBUG_XBOX_PROTOCOL
   2.336 +                    SDL_Log("Delay after init: %ums\n", SDL_GetTicks() - ctx->start_time);
   2.337 +#endif
   2.338 +                    if (!SendControllerInit(device, ctx)) {
   2.339 +                        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
   2.340 +                        return SDL_FALSE;
   2.341 +                    }
   2.342 +                    ctx->initialized = SDL_TRUE;
   2.343 +                }
   2.344 +                break;
   2.345 +            case 0x03:
   2.346 +                /* Controller heartbeat */
   2.347 +                break;
   2.348 +            case 0x20:
   2.349 +                HIDAPI_DriverXboxOne_HandleStatePacket(joystick, device->dev, ctx, data, size);
   2.350 +                break;
   2.351 +            case 0x07:
   2.352 +                HIDAPI_DriverXboxOne_HandleModePacket(joystick, device->dev, ctx, data, size);
   2.353 +                break;
   2.354 +            default:
   2.355  #ifdef DEBUG_JOYSTICK
   2.356 -            SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
   2.357 +                SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
   2.358  #endif
   2.359 -            break;
   2.360 +                break;
   2.361 +            }
   2.362          }
   2.363      }
   2.364