Fixed bug 5051 - Switch Pro Controller hidapi driver does not report battery levels when connected via Bluetooth bluenaxela+sdl I've noticed that the Switch Pro Controller hidapi driver does not report battery levels when connected via Bluetooth, despite having code for setting joystick->epowerlevel. This is caused by the driver always using k_eSwitchInputReportIDs_SimpleControllerState via Bluetooth. Using that mode means that the state reports you get back from the controller do not include battery state. Not using the full controller state over Bluetooth effectively makes this driver's support for setting joystick->epowerlevel entirely pointless, only ever reporting SDL_JOYSTICK_POWER_WIRED. Is there a reason this was set to only use SimpleControllerState via Bluetooth? I've attached a patch I'm using to allow getting battery level for the Switch Pro Controller. A couple notes about this patch: 1) It changes LoadStickCalibration to accept the input_mode that is selected, because that's really what should determine what is used for stick extents, since stick extents differ between the modes. 2) In my patch I only use FullControllerState when the vid/pid matches the official Switch Pro Controller, as a cautionary measure in case some third-party controllers have problems with FullControllerState mode via Bluetooth (I noticed a HORI Wireless Switch Pad I had seemed to not read controller calibration correctly for stick extents. Maybe it's calibration data was uninitialized on account of having never been used with a Switch? I'm unsure, though if that guess is right maybe SDL2 should be detecting an uninitiated calibration state and using some sensible defaults)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index ee4baf0..473df1d 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -229,17 +229,17 @@ typedef struct {
static SDL_bool
HasHomeLED(int vendor_id, int product_id)
{
- /* The Power A Nintendo Switch Pro controllers don't have a Home LED */
- if (vendor_id == 0 && product_id == 0) {
- return SDL_FALSE;
- }
+ /* The Power A Nintendo Switch Pro controllers don't have a Home LED */
+ if (vendor_id == 0 && product_id == 0) {
+ return SDL_FALSE;
+ }
- /* HORI Wireless Switch Pad */
- if (vendor_id == 0x0f0d && product_id == 0x00f6) {
- return SDL_FALSE;
- }
+ /* HORI Wireless Switch Pad */
+ if (vendor_id == 0x0f0d && product_id == 0x00f6) {
+ return SDL_FALSE;
+ }
- return SDL_TRUE;
+ return SDL_TRUE;
}
static SDL_bool
@@ -541,7 +541,7 @@ static SDL_bool SetSlotLED(SDL_DriverSwitch_Context *ctx, Uint8 slot)
return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data, sizeof(led_data), NULL);
}
-static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
+static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx, Uint8 input_mode)
{
Uint8 *pStickCal;
size_t stick, axis;
@@ -594,7 +594,7 @@ static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
}
}
- if (ctx->m_bUsingBluetooth) {
+ if (input_mode == k_eSwitchInputReportIDs_SimpleControllerState) {
for (stick = 0; stick < 2; ++stick) {
for(axis = 0; axis < 2; ++axis) {
ctx->m_StickExtents[stick].axis[axis].sMin = (Sint16)(SDL_MIN_SINT16 * 0.5f);
@@ -736,7 +736,24 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
ctx->m_bUsingBluetooth = SDL_TRUE;
}
- if (!LoadStickCalibration(ctx)) {
+ /* Determine the desired input mode (needed before loading stick calibration) */
+ if (ctx->m_bUsingBluetooth) {
+ input_mode = k_eSwitchInputReportIDs_SimpleControllerState;
+ } else {
+ input_mode = k_eSwitchInputReportIDs_FullControllerState;
+ }
+
+ /* The official Nintendo Switch Pro Controller supports FullControllerState over bluetooth
+ * just fine. We really should use that, or else the epowerlevel code in
+ * HandleFullControllerState is completely pointless. We need full state if we want battery
+ * level and we only care about battery level over bluetooth anyway.
+ */
+ if (device->vendor_id == USB_VENDOR_NINTENDO &&
+ device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO) {
+ input_mode = k_eSwitchInputReportIDs_FullControllerState;
+ }
+
+ if (!LoadStickCalibration(ctx, input_mode)) {
SDL_SetError("Couldn't load stick calibration");
goto error;
}
@@ -746,12 +763,7 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
goto error;
}
- /* Set the desired input mode */
- if (ctx->m_bUsingBluetooth) {
- input_mode = k_eSwitchInputReportIDs_SimpleControllerState;
- } else {
- input_mode = k_eSwitchInputReportIDs_FullControllerState;
- }
+ /* Set desired input mode */
if (!SetInputMode(ctx, input_mode)) {
SDL_SetError("Couldn't set input mode");
goto error;
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index 2603962..cf806bd 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -35,6 +35,7 @@
#define USB_VENDOR_VALVE 0x28de
#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER 0x0337
+#define USB_PRODUCT_NINTENDO_SWITCH_PRO 0x2009
#define USB_PRODUCT_RAZER_PANTHERA 0x0401
#define USB_PRODUCT_RAZER_PANTHERA_EVO 0x1008
#define USB_PRODUCT_SONY_DS4 0x05c4