فهرست منبع

Fixed bug 4996 - Mac: XBoxOne Bluetooth rumble isn't working

rofferom

I have an annoying issue on MacOS about XBoxOne Bluetooth rumble (Vendor: 0x045e, Product: 0x02fd).

When 360controller is installed, rumble is working correctly. However, Bluetooth rumble isn't working at all, with or without 360controller installed (although it is working with Chrome + https://html5gamepad.com).

I looked at the code, and it seems that XBox controllers are managed in MacOS in this file: SDL_hidapi_xbox360.c. The XBoxOne file is disabled for MacOS in SDL_hidjoystick_c.h.

The function HIDAPI_DriverXbox360_Rumble() is called correctly, and hid_write() returns no error.

I have tried a stupid test. I took the rumble packet from 360controller: https://github.com/360Controller/360Controller/blob/ec4e88eb2d2535e9b32561c702f42fb22b0a7f99/XBOBTFF/FFDriver.cpp#L620. With the patch I have attached, I manage to have rumble working on Bluetooth (with some stupid vibration level, but it proves it can if the packet is changed).

But it breaks the USB rumble with 360controller. A comment in the function makes an explicit reference to 360controller, I think that's why I have broken this specific usecase.

I don't know what is the correct way to fix this, but it seems that the current implementation has a missing case for Bluetooth support.


Note that I also tested master this morning, and I have another issue:
    if (!device->ffservice) {
        return SDL_Unsupported();
    }

test fails in DARWIN_JoystickRumble(). This test has been done quickly, I'm not totaly confident about its accuracy.
Sam Lantinga 5 سال پیش
والد
کامیت
6590d078d7
1فایلهای تغییر یافته به همراه36 افزوده شده و 7 حذف شده
  1. 36 7
      src/joystick/hidapi/SDL_hidapi_xbox360.c

+ 36 - 7
src/joystick/hidapi/SDL_hidapi_xbox360.c

@@ -244,6 +244,20 @@ HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
 
 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
 
+static SDL_bool
+IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
+{
+    /* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
+    if (vendor_id == USB_VENDOR_MICROSOFT) {
+        if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
+            product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
+            product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
 static SDL_bool
 HIDAPI_DriverXbox360_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)
 {
@@ -403,23 +417,38 @@ HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
 #else /* !__WIN32__ */
 
 #ifdef __MACOSX__
-    /* On Mac OS X the 360Controller driver uses this short report,
-       and we need to prefix it with a magic token so hidapi passes it through untouched
-     */
-    Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
+    if (IsBluetoothXboxOneController(device->vendor_id, device->product_id)) {
+        Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
+
+        rumble_packet[4] = (low_frequency_rumble >> 8);
+        rumble_packet[5] = (high_frequency_rumble >> 8);
 
-    rumble_packet[6+2] = (low_frequency_rumble >> 8);
-    rumble_packet[6+3] = (high_frequency_rumble >> 8);
+        if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
+            return SDL_SetError("Couldn't send rumble packet");
+        }
+    } else {
+        /* On Mac OS X the 360Controller driver uses this short report,
+           and we need to prefix it with a magic token so hidapi passes it through untouched
+         */
+        Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
+
+        rumble_packet[6+2] = (low_frequency_rumble >> 8);
+        rumble_packet[6+3] = (high_frequency_rumble >> 8);
+
+        if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
+            return SDL_SetError("Couldn't send rumble packet");
+        }
+    }
 #else
     Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
     rumble_packet[3] = (low_frequency_rumble >> 8);
     rumble_packet[4] = (high_frequency_rumble >> 8);
-#endif
 
     if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
         return SDL_SetError("Couldn't send rumble packet");
     }
+#endif
 #endif /* __WIN32__ */
 
     return 0;