Sfoglia il codice sorgente

Add support for the Xbox 360 "Big Button" wireless receiver

Ethan Lee 2 settimane fa
parent
commit
6083940ef4

+ 1 - 0
VisualC-GDK/SDL/SDL.vcxproj

@@ -745,6 +745,7 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch2.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch2.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360bb.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />

+ 1 - 0
VisualC-GDK/SDL/SDL.vcxproj.filters

@@ -92,6 +92,7 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch2.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch2.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360bb.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />

+ 1 - 0
VisualC/SDL/SDL.vcxproj

@@ -849,6 +849,7 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch2.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch2.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360bb.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />

+ 3 - 0
VisualC/SDL/SDL.vcxproj.filters

@@ -1651,6 +1651,9 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c">
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c">
       <Filter>joystick\hidapi</Filter>
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360bb.c">
+      <Filter>joystick\hidapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c">
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c">
       <Filter>joystick\hidapi</Filter>
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
     </ClCompile>

+ 4 - 0
Xcode/SDL/SDL.xcodeproj/project.pbxproj

@@ -572,6 +572,7 @@
 		F3FD042E2C9B755700824C4C /* SDL_hidapi_nintendo.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FD042C2C9B755700824C4C /* SDL_hidapi_nintendo.h */; };
 		F3FD042E2C9B755700824C4C /* SDL_hidapi_nintendo.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FD042C2C9B755700824C4C /* SDL_hidapi_nintendo.h */; };
 		F3FD042F2C9B755700824C4C /* SDL_hidapi_steam_hori.c in Sources */ = {isa = PBXBuildFile; fileRef = F3FD042D2C9B755700824C4C /* SDL_hidapi_steam_hori.c */; };
 		F3FD042F2C9B755700824C4C /* SDL_hidapi_steam_hori.c in Sources */ = {isa = PBXBuildFile; fileRef = F3FD042D2C9B755700824C4C /* SDL_hidapi_steam_hori.c */; };
 		FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; platformFilters = (ios, maccatalyst, macos, tvos, ); settings = {ATTRIBUTES = (Required, ); }; };
 		FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; platformFilters = (ios, maccatalyst, macos, tvos, ); settings = {ATTRIBUTES = (Required, ); }; };
+		000076D3980E0431F8620000 /* SDL_hidapi_xbox360bb.c in Sources */ = {isa = PBXBuildFile; fileRef = 0000E85E176D78EFBFDC0000 /* SDL_hidapi_xbox360bb.c */; };
 /* End PBXBuildFile section */
 /* End PBXBuildFile section */
 
 
 /* Begin PBXContainerItemProxy section */
 /* Begin PBXContainerItemProxy section */
@@ -1182,6 +1183,7 @@
 		F59C710600D5CB5801000001 /* SDL.info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = SDL.info; sourceTree = "<group>"; };
 		F59C710600D5CB5801000001 /* SDL.info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = SDL.info; sourceTree = "<group>"; };
 		F5A2EF3900C6A39A01000001 /* BUGS.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = BUGS.txt; path = ../../BUGS.txt; sourceTree = SOURCE_ROOT; };
 		F5A2EF3900C6A39A01000001 /* BUGS.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = BUGS.txt; path = ../../BUGS.txt; sourceTree = SOURCE_ROOT; };
 		FA73671C19A540EF004122E4 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
 		FA73671C19A540EF004122E4 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
+		0000E85E176D78EFBFDC0000 /* SDL_hidapi_xbox360bb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_hidapi_xbox360bb.c; path = SDL_hidapi_xbox360bb.c; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 /* End PBXFileReference section */
 
 
 /* Begin PBXFrameworksBuildPhase section */
 /* Begin PBXFrameworksBuildPhase section */
@@ -2058,6 +2060,7 @@
 				A7D8A7C723E2513E00DCD162 /* SDL_hidapijoystick_c.h */,
 				A7D8A7C723E2513E00DCD162 /* SDL_hidapijoystick_c.h */,
 				F3E6C3912EE9F20000A6B39E /* SDL_report_descriptor.h */,
 				F3E6C3912EE9F20000A6B39E /* SDL_report_descriptor.h */,
 				F3E6C3922EE9F20000A6B39E /* SDL_report_descriptor.c */,
 				F3E6C3922EE9F20000A6B39E /* SDL_report_descriptor.c */,
+				0000E85E176D78EFBFDC0000 /* SDL_hidapi_xbox360bb.c */,
 			);
 			);
 			path = hidapi;
 			path = hidapi;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -3243,6 +3246,7 @@
 				00009183ED11C92F23FC0000 /* SDL_notification.c in Sources */,
 				00009183ED11C92F23FC0000 /* SDL_notification.c in Sources */,
 				0000FB5C9B8CE5929A250000 /* SDL_cocoanotification.m in Sources */,
 				0000FB5C9B8CE5929A250000 /* SDL_cocoanotification.m in Sources */,
 				0000AF1D2CED20010C2D0000 /* SDL_notificationevents.c in Sources */,
 				0000AF1D2CED20010C2D0000 /* SDL_notificationevents.c in Sources */,
+				000076D3980E0431F8620000 /* SDL_hidapi_xbox360bb.c in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};

+ 1 - 0
src/hidapi/SDL_hidapi.c

@@ -861,6 +861,7 @@ static const struct {
     { USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT },
     { USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT },
     { USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT },
     { USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT },
     { USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_PRO },
     { USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_PRO },
+    { USB_VENDOR_MICROSOFT, USB_PRODUCT_XBOX360_BIGBUTTON_RECEIVER },
 };
 };
 
 
 static bool RequiresLibUSB(Uint16 vendor, Uint16 product, bool libusb_xbox)
 static bool RequiresLibUSB(Uint16 vendor, Uint16 product, bool libusb_xbox)

+ 3 - 1
src/hidapi/libusb/hid.c

@@ -943,6 +943,7 @@ static int is_xbox360(unsigned short vendor_id, const struct libusb_interface_de
 	static const int xb360_iface_subclass = 93;
 	static const int xb360_iface_subclass = 93;
 	static const int xb360_iface_protocol = 1; /* Wired */
 	static const int xb360_iface_protocol = 1; /* Wired */
 	static const int xb360w_iface_protocol = 129; /* Wireless */
 	static const int xb360w_iface_protocol = 129; /* Wireless */
+	static const int xb360bb_iface_protocol = 4; /* Wireless */
 	static const int supported_vendors[] = {
 	static const int supported_vendors[] = {
 		0x0079, /* GPD Win 2 */
 		0x0079, /* GPD Win 2 */
 		0x0351, /* CRKD */
 		0x0351, /* CRKD */
@@ -982,7 +983,8 @@ static int is_xbox360(unsigned short vendor_id, const struct libusb_interface_de
 	if (intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
 	if (intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
 	    intf_desc->bInterfaceSubClass == xb360_iface_subclass &&
 	    intf_desc->bInterfaceSubClass == xb360_iface_subclass &&
 	    (intf_desc->bInterfaceProtocol == xb360_iface_protocol ||
 	    (intf_desc->bInterfaceProtocol == xb360_iface_protocol ||
-	     intf_desc->bInterfaceProtocol == xb360w_iface_protocol)) {
+	     intf_desc->bInterfaceProtocol == xb360w_iface_protocol ||
+	     intf_desc->bInterfaceProtocol == xb360bb_iface_protocol)) {
 		size_t i;
 		size_t i;
 		for (i = 0; i < sizeof(supported_vendors)/sizeof(supported_vendors[0]); ++i) {
 		for (i = 0; i < sizeof(supported_vendors)/sizeof(supported_vendors[0]); ++i) {
 			if (vendor_id == supported_vendors[i]) {
 			if (vendor_id == supported_vendors[i]) {

+ 2 - 0
src/joystick/SDL_gamepad.c

@@ -1244,6 +1244,8 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
         Uint8 sub_product  = guid.data[15] & 0x1F;
         Uint8 sub_product  = guid.data[15] & 0x1F;
 
 
         SDL_CreateMappingStringForSInputGamepad(vendor, product, sub_product, version, face_style, mapping_string, sizeof(mapping_string));
         SDL_CreateMappingStringForSInputGamepad(vendor, product, sub_product, version, face_style, mapping_string, sizeof(mapping_string));
+    } else if ((vendor == USB_VENDOR_MICROSOFT) && (product == USB_PRODUCT_XBOX360_BIGBUTTON_RECEIVER)) {
+        SDL_strlcat(mapping_string, "dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,misc1:b7", sizeof(mapping_string));
     } else {
     } else {
         // All other gamepads have the standard set of 19 buttons and 6 axes
         // All other gamepads have the standard set of 19 buttons and 6 axes
         if (SDL_IsJoystickGameCube(vendor, product)) {
         if (SDL_IsJoystickGameCube(vendor, product)) {

+ 4 - 0
src/joystick/hidapi/SDL_hidapi_xbox360.c

@@ -200,6 +200,10 @@ static bool HIDAPI_DriverXbox360_IsSupportedDevice(SDL_HIDAPI_Device *device, co
         // This is the wireless dongle, which talks a different protocol
         // This is the wireless dongle, which talks a different protocol
         return false;
         return false;
     }
     }
+    if ((vendor_id == USB_VENDOR_MICROSOFT) && (product_id == USB_PRODUCT_XBOX360_BIGBUTTON_RECEIVER)) {
+        // This is the BigButton wireless receiver, which talks a different protocol
+        return false;
+    }
     if (interface_number > 0) {
     if (interface_number > 0) {
         // This is the chatpad or other input interface, not the Xbox 360 interface
         // This is the chatpad or other input interface, not the Xbox 360 interface
         return false;
         return false;

+ 280 - 0
src/joystick/hidapi/SDL_hidapi_xbox360bb.c

@@ -0,0 +1,280 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#ifdef SDL_JOYSTICK_HIDAPI
+
+#include "../../SDL_hints_c.h"
+#include "../SDL_sysjoystick.h"
+#include "SDL_hidapijoystick_c.h"
+#include "SDL_hidapi_rumble.h"
+#include "SDL_hidapi_xbox360.h"
+
+#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
+
+// Define this if you want to log all packets from the controller
+// #define DEBUG_XBOX_PROTOCOL
+
+#define MAX_CONTROLLERS 4
+
+enum
+{
+    SDL_GAMEPAD_BUTTON_XBOX360_BIG_BUTTON = SDL_GAMEPAD_BUTTON_START + 1,
+    SDL_GAMEPAD_NUM_XBOX360BB_BUTTONS,
+};
+
+typedef struct
+{
+    SDL_HIDAPI_Device *device;
+    SDL_JoystickID joysticks[MAX_CONTROLLERS];
+    Uint8 last_state[MAX_CONTROLLERS][USB_PACKET_LENGTH];
+    Uint64 last_packet[MAX_CONTROLLERS];
+} SDL_DriverXbox360BB_Context;
+
+static void HIDAPI_DriverXBOX360BB_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
+}
+
+static void HIDAPI_DriverXBOX360BB_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
+    SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
+}
+
+static bool HIDAPI_DriverXBOX360BB_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT)));
+}
+
+static bool HIDAPI_DriverXBOX360BB_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
+{
+    return (vendor_id == USB_VENDOR_MICROSOFT) && (product_id == USB_PRODUCT_XBOX360_BIGBUTTON_RECEIVER);
+}
+
+static bool HIDAPI_DriverXBOX360BB_InitDevice(SDL_HIDAPI_Device *device)
+{
+    SDL_DriverXbox360BB_Context *ctx;
+    Uint8 i;
+
+    HIDAPI_SetDeviceName(device, "Xbox 360 Big Button Controller");
+
+    ctx = (SDL_DriverXbox360BB_Context *)SDL_calloc(1, sizeof(*ctx));
+    if (!ctx) {
+        return false;
+    }
+    ctx->device = device;
+
+    device->context = ctx;
+
+    for (i = 0; i < MAX_CONTROLLERS; ++i) {
+        HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
+    }
+
+    return true;
+}
+
+static int HIDAPI_DriverXBOX360BB_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
+{
+    return -1;
+}
+
+static void HIDAPI_DriverXBOX360BB_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
+{
+}
+
+static bool HIDAPI_DriverXBOX360BB_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
+{
+    SDL_DriverXbox360BB_Context *ctx = (SDL_DriverXbox360BB_Context *)device->context;
+    Uint8 i;
+
+    SDL_AssertJoysticksLocked();
+
+    for (i = 0; i < MAX_CONTROLLERS; ++i) {
+        if (joystick->instance_id == ctx->joysticks[i]) {
+            joystick->nbuttons = SDL_GAMEPAD_NUM_XBOX360BB_BUTTONS;
+            joystick->nhats = 1;
+            joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS;
+            return true;
+        }
+    }
+    return false; // Should never get here!
+}
+
+static bool HIDAPI_DriverXBOX360BB_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
+{
+    return SDL_Unsupported();
+}
+
+static bool HIDAPI_DriverXBOX360BB_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+    return SDL_Unsupported();
+}
+
+static Uint32 HIDAPI_DriverXBOX360BB_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
+{
+    return 0;
+}
+
+static bool HIDAPI_DriverXBOX360BB_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
+{
+    return SDL_Unsupported();
+}
+
+static bool HIDAPI_DriverXBOX360BB_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
+{
+    return SDL_Unsupported();
+}
+
+static bool HIDAPI_DriverXBOX360BB_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
+{
+    return SDL_Unsupported();
+}
+
+static void HIDAPI_DriverXBOX360BB_HandleStatePacket(SDL_DriverXbox360BB_Context *ctx, Uint8 *data, int size)
+{
+    Uint64 timestamp = SDL_GetTicksNS();
+    SDL_Joystick *joystick;
+    Uint8 i;
+
+    i = data[2];
+    SDL_assert(i < MAX_CONTROLLERS);
+    joystick = SDL_GetJoystickFromID(ctx->joysticks[i]);
+    ctx->last_packet[i] = timestamp;
+
+    if (ctx->last_state[i][3] != data[3]) {
+        Uint8 hat = 0;
+
+        if (data[3] & 0x01) {
+            hat |= SDL_HAT_UP;
+        }
+        if (data[3] & 0x02) {
+            hat |= SDL_HAT_DOWN;
+        }
+        if (data[3] & 0x04) {
+            hat |= SDL_HAT_LEFT;
+        }
+        if (data[3] & 0x08) {
+            hat |= SDL_HAT_RIGHT;
+        }
+        SDL_SendJoystickHat(timestamp, joystick, 0, hat);
+
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[3] & 0x10) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK,  ((data[3] & 0x20) != 0));
+    }
+
+    if (ctx->last_state[i][4] != data[4]) {
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE,              ((data[4] & 0x04) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX360_BIG_BUTTON, ((data[4] & 0x08) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH,              ((data[4] & 0x10) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST,               ((data[4] & 0x20) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST,               ((data[4] & 0x40) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH,              ((data[4] & 0x80) != 0));
+    }
+
+    SDL_memcpy(ctx->last_state[i], data, SDL_min(size, sizeof(ctx->last_state[i])));
+}
+
+static void HIDAPI_DriverXBOX360BB_HandleReleaseEvents(SDL_DriverXbox360BB_Context *ctx)
+{
+    Uint64 timestamp = SDL_GetTicksNS();
+    Uint8 i;
+
+    // The receiver only sends packets when a button is down, handle our own release logic
+    for (i = 0; i < MAX_CONTROLLERS; ++i) {
+        // FIXME: Even when a button is continuously pressed, we get _huge_
+        // delays between packets. This is the smallest number I could get
+        // without erroneous button releases. Yeesh.
+        // -flibit
+        const int XBOXBB_BUTTON_RELEASE_TIMEOUT_MS = 120;
+        if (SDL_NS_TO_MS(timestamp - ctx->last_packet[i]) >= XBOXBB_BUTTON_RELEASE_TIMEOUT_MS) {
+            SDL_Joystick *joystick = SDL_GetJoystickFromID(ctx->joysticks[i]);
+            if (joystick) {
+                SDL_SendJoystickHat(timestamp, joystick, 0, 0);
+                SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, 0);
+                SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, 0);
+                SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, 0);
+                SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, 0);
+                SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, 0);
+                SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, 0);
+                SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, 0);
+                SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX360_BIG_BUTTON, 0);
+            }
+            SDL_zero(ctx->last_state[i]);
+            ctx->last_packet[i] = timestamp;
+        }
+    }
+}
+
+static bool HIDAPI_DriverXBOX360BB_UpdateDevice(SDL_HIDAPI_Device *device)
+{
+    SDL_DriverXbox360BB_Context *ctx = (SDL_DriverXbox360BB_Context *)device->context;
+    Uint8 data[USB_PACKET_LENGTH];
+    int size;
+
+    while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
+#ifdef DEBUG_XBOX_PROTOCOL
+        HIDAPI_DumpPacket("Xbox 360 BigButton packet: size = %d", data, size);
+#endif
+        if (size == 5) {
+            HIDAPI_DriverXBOX360BB_HandleStatePacket(ctx, data, size);
+        }
+    }
+
+    HIDAPI_DriverXBOX360BB_HandleReleaseEvents(ctx);
+
+    return (size >= 0);
+}
+
+static void HIDAPI_DriverXBOX360BB_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
+{
+}
+
+static void HIDAPI_DriverXBOX360BB_FreeDevice(SDL_HIDAPI_Device *device)
+{
+}
+
+SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360BB = {
+    "SDL_JOYSTICK_HIDAPI_XBOX_360_BIGBUTTON",
+    true,
+    HIDAPI_DriverXBOX360BB_RegisterHints,
+    HIDAPI_DriverXBOX360BB_UnregisterHints,
+    HIDAPI_DriverXBOX360BB_IsEnabled,
+    HIDAPI_DriverXBOX360BB_IsSupportedDevice,
+    HIDAPI_DriverXBOX360BB_InitDevice,
+    HIDAPI_DriverXBOX360BB_GetDevicePlayerIndex,
+    HIDAPI_DriverXBOX360BB_SetDevicePlayerIndex,
+    HIDAPI_DriverXBOX360BB_UpdateDevice,
+    HIDAPI_DriverXBOX360BB_OpenJoystick,
+    HIDAPI_DriverXBOX360BB_RumbleJoystick,
+    HIDAPI_DriverXBOX360BB_RumbleJoystickTriggers,
+    HIDAPI_DriverXBOX360BB_GetJoystickCapabilities,
+    HIDAPI_DriverXBOX360BB_SetJoystickLED,
+    HIDAPI_DriverXBOX360BB_SendJoystickEffect,
+    HIDAPI_DriverXBOX360BB_SetJoystickSensorsEnabled,
+    HIDAPI_DriverXBOX360BB_CloseJoystick,
+    HIDAPI_DriverXBOX360BB_FreeDevice,
+};
+
+#endif // SDL_JOYSTICK_HIDAPI_XBOX360
+
+#endif // SDL_JOYSTICK_HIDAPI

+ 4 - 0
src/joystick/hidapi/SDL_hidapi_xbox360w.c

@@ -67,6 +67,10 @@ static bool HIDAPI_DriverXbox360W_IsSupportedDevice(SDL_HIDAPI_Device *device, c
 {
 {
     const int XB360W_IFACE_PROTOCOL = 129; // Wireless
     const int XB360W_IFACE_PROTOCOL = 129; // Wireless
 
 
+    if ((vendor_id == USB_VENDOR_MICROSOFT) && (product_id == USB_PRODUCT_XBOX360_BIGBUTTON_RECEIVER)) {
+        // This is the BigButton wireless receiver, which talks a different protocol
+        return false;
+    }
     if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY2 || product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY1 || product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER) && interface_protocol == 0) ||
     if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY2 || product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY1 || product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER) && interface_protocol == 0) ||
         (type == SDL_GAMEPAD_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
         (type == SDL_GAMEPAD_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
         return true;
         return true;

+ 1 - 0
src/joystick/hidapi/SDL_hidapijoystick.c

@@ -87,6 +87,7 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
     &SDL_HIDAPI_DriverXbox360,
     &SDL_HIDAPI_DriverXbox360,
     &SDL_HIDAPI_DriverXbox360W,
     &SDL_HIDAPI_DriverXbox360W,
+    &SDL_HIDAPI_DriverXbox360BB,
 #endif
 #endif
 #ifdef SDL_JOYSTICK_HIDAPI_GIP
 #ifdef SDL_JOYSTICK_HIDAPI_GIP
     &SDL_HIDAPI_DriverGIP,
     &SDL_HIDAPI_DriverGIP,

+ 1 - 0
src/joystick/hidapi/SDL_hidapijoystick_c.h

@@ -164,6 +164,7 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch2;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverWii;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverWii;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W;
+extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360BB;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamHori;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamHori;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamTriton;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamTriton;

+ 1 - 0
src/joystick/usb_ids.h

@@ -191,6 +191,7 @@
 #define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER             0x0719
 #define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER             0x0719
 #define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY1 0x02a9
 #define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY1 0x02a9
 #define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY2 0x0291
 #define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY2 0x0291
+#define USB_PRODUCT_XBOX360_BIGBUTTON_RECEIVER            0x02a0
 #define USB_PRODUCT_XBOX_ONE_ADAPTIVE                     0x0b0a
 #define USB_PRODUCT_XBOX_ONE_ADAPTIVE                     0x0b0a
 #define USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLUETOOTH           0x0b0c
 #define USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLUETOOTH           0x0b0c
 #define USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLE                 0x0b21
 #define USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLE                 0x0b21