Don't rely on the device VID/PID to get the Nintendo controller type

The Nintendo Online Sega Genesis controller reports the SNES VID/PID over Bluetooth. This is a more robust way of handling future controllers as well, so let's go with this instead.

Also use full reports over Bluetooth, and don't report gyro for Nintendo Online classic controllers.
This commit is contained in:
Sam Lantinga 2022-08-03 21:31:12 -07:00
parent b6aadb16b9
commit 57c3b2c950
2 changed files with 62 additions and 38 deletions

View File

@ -587,21 +587,25 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI
(vendor == USB_VENDOR_SHENZHEN && product == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER)) {
/* GameCube driver has 12 buttons and 6 axes */
SDL_strlcat(mapping_string, "a:b0,b:b1,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3,start:b8,x:b2,y:b3,", sizeof(mapping_string));
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_N64_CONTROLLER) {
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,misc1:b15,", sizeof(mapping_string));
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER) {
SDL_strlcat(mapping_string, "a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,rightshoulder:b10,righttrigger:a5,start:b6,misc1:b15,", sizeof(mapping_string));
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SNES_CONTROLLER) {
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,", sizeof(mapping_string));
} else if (SDL_IsJoystickNintendoSwitchJoyConLeft(vendor, product) ||
SDL_IsJoystickNintendoSwitchJoyConRight(vendor, product) ||
SDL_IsJoystickNintendoSwitchJoyConGrip(vendor, product)) {
} else if (vendor == USB_VENDOR_NINTENDO && guid.data[15] != 0 && guid.data[15] != 3) {
switch (guid.data[15]) {
case 9:
case 10:
/* NES Controller */
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,", sizeof(mapping_string));
break;
case 11:
/* SNES Controller */
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,", sizeof(mapping_string));
break;
case 12:
/* N64 Controller */
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,misc1:b15,", sizeof(mapping_string));
break;
case 13:
/* SEGA Genesis Controller */
SDL_strlcat(mapping_string, "a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,rightshoulder:b10,righttrigger:a5,start:b6,misc1:b15,", sizeof(mapping_string));
break;
default:
/* Mini gamepad mode */
SDL_strlcat(mapping_string, "a:b0,b:b1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,", sizeof(mapping_string));

View File

@ -1095,36 +1095,55 @@ ReadJoyConControllerType(SDL_HIDAPI_Device *device)
return eControllerType;
}
static void
UpdateDeviceName(SDL_HIDAPI_Device *device, ESwitchDeviceInfoControllerType eControllerType)
{
const char *name = NULL;
switch (eControllerType) {
case k_eSwitchDeviceInfoControllerType_JoyConLeft:
name = "Nintendo Switch Joy-Con (L)";
break;
case k_eSwitchDeviceInfoControllerType_JoyConRight:
name = "Nintendo Switch Joy-Con (R)";
break;
case k_eSwitchDeviceInfoControllerType_ProController:
name = "Nintendo Switch Pro Controller";
break;
case k_eSwitchDeviceInfoControllerType_NESLeft:
name = "Nintendo NES Controller (L)";
break;
case k_eSwitchDeviceInfoControllerType_NESRight:
name = "Nintendo NES Controller (R)";
break;
case k_eSwitchDeviceInfoControllerType_SNES:
name = "Nintendo SNES Controller";
break;
case k_eSwitchDeviceInfoControllerType_N64:
name = "Nintendo N64 Controller";
break;
case k_eSwitchDeviceInfoControllerType_SEGA_Genesis:
name = "Nintendo SEGA Genesis Controller";
break;
default:
break;
}
if (name && (!name || SDL_strcmp(name, device->name) != 0)) {
SDL_free(device->name);
device->name = SDL_strdup(name);
}
}
static SDL_bool
HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
{
/* The NES controllers need additional fix up, since we can't detect them without opening the device */
if (device->vendor_id == USB_VENDOR_NINTENDO &&
(device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT ||
device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP)) {
if (device->vendor_id == USB_VENDOR_NINTENDO) {
ESwitchDeviceInfoControllerType eControllerType = ReadJoyConControllerType(device);
switch (eControllerType) {
case k_eSwitchDeviceInfoControllerType_JoyConLeft:
SDL_free(device->name);
device->name = SDL_strdup("Nintendo Switch Joy-Con (L)");
device->guid.data[15] = eControllerType;
break;
case k_eSwitchDeviceInfoControllerType_JoyConRight:
SDL_free(device->name);
device->name = SDL_strdup("Nintendo Switch Joy-Con (R)");
device->guid.data[15] = eControllerType;
break;
case k_eSwitchDeviceInfoControllerType_NESLeft:
SDL_free(device->name);
device->name = SDL_strdup("NES Controller (L)");
device->guid.data[15] = eControllerType;
break;
case k_eSwitchDeviceInfoControllerType_NESRight:
SDL_free(device->name);
device->name = SDL_strdup("NES Controller (R)");
device->guid.data[15] = eControllerType;
break;
case k_eSwitchDeviceInfoControllerType_Unknown:
/* This might be a Joy-Con that's missing from a charging grip slot */
if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) {
if (device->interface_number == 1) {
SDL_free(device->name);
@ -1138,6 +1157,8 @@ HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
}
break;
default:
UpdateDeviceName(device, eControllerType);
device->guid.data[15] = eControllerType;
break;
}
}
@ -1208,17 +1229,16 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
* 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 ||
device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP ||
device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT ||
device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT)) {
if (device->vendor_id == USB_VENDOR_NINTENDO) {
input_mode = k_eSwitchInputReportIDs_FullControllerState;
}
if (input_mode == k_eSwitchInputReportIDs_FullControllerState &&
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESLeft &&
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESRight) {
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESRight &&
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_SNES &&
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_N64 &&
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_SEGA_Genesis) {
/* Use the right sensor in the combined Joy-Con pair */
if (!device->parent ||
ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {