mirror of
https://github.com/Ryujinx/SDL.git
synced 2024-12-23 19:15:29 +00:00
Added support for the Nintendo Online NES Controllers to the HIDAPI driver
This commit is contained in:
parent
45c1cc8177
commit
875b737c64
|
@ -595,8 +595,17 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI
|
||||||
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));
|
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) ||
|
} else if (SDL_IsJoystickNintendoSwitchJoyConLeft(vendor, product) ||
|
||||||
SDL_IsJoystickNintendoSwitchJoyConRight(vendor, product)) {
|
SDL_IsJoystickNintendoSwitchJoyConRight(vendor, product)) {
|
||||||
|
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;
|
||||||
|
default:
|
||||||
/* Mini gamepad mode */
|
/* 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));
|
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));
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* All other controllers have the standard set of 19 buttons and 6 axes */
|
/* All other controllers have the standard set of 19 buttons and 6 axes */
|
||||||
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,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", sizeof(mapping_string));
|
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,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", sizeof(mapping_string));
|
||||||
|
|
|
@ -104,10 +104,12 @@ typedef enum {
|
||||||
} ESwitchProprietaryCommandIDs;
|
} ESwitchProprietaryCommandIDs;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
k_eSwitchDeviceInfoControllerType_Unknown = 0x0,
|
k_eSwitchDeviceInfoControllerType_Unknown = 0,
|
||||||
k_eSwitchDeviceInfoControllerType_JoyConLeft = 0x1,
|
k_eSwitchDeviceInfoControllerType_JoyConLeft = 1,
|
||||||
k_eSwitchDeviceInfoControllerType_JoyConRight = 0x2,
|
k_eSwitchDeviceInfoControllerType_JoyConRight = 2,
|
||||||
k_eSwitchDeviceInfoControllerType_ProController = 0x3,
|
k_eSwitchDeviceInfoControllerType_ProController = 3,
|
||||||
|
k_eSwitchDeviceInfoControllerType_NESLeft = 9,
|
||||||
|
k_eSwitchDeviceInfoControllerType_NESRight = 10,
|
||||||
} ESwitchDeviceInfoControllerType;
|
} ESwitchDeviceInfoControllerType;
|
||||||
|
|
||||||
#define k_unSwitchOutputPacketDataLength 49
|
#define k_unSwitchOutputPacketDataLength 49
|
||||||
|
@ -318,7 +320,7 @@ HasHomeLED(int vendor_id, int product_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
AlwaysUsesLabels(int vendor_id, int product_id)
|
AlwaysUsesLabels(int vendor_id, int product_id, ESwitchDeviceInfoControllerType eControllerType)
|
||||||
{
|
{
|
||||||
/* These controllers don't have a diamond button configuration, so always use labels */
|
/* These controllers don't have a diamond button configuration, so always use labels */
|
||||||
if (vendor_id == USB_VENDOR_NINTENDO &&
|
if (vendor_id == USB_VENDOR_NINTENDO &&
|
||||||
|
@ -326,6 +328,10 @@ AlwaysUsesLabels(int vendor_id, int product_id)
|
||||||
product_id == USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER)) {
|
product_id == USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER)) {
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
if (eControllerType == k_eSwitchDeviceInfoControllerType_NESLeft ||
|
||||||
|
eControllerType == k_eSwitchDeviceInfoControllerType_NESRight) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,6 +516,25 @@ static SDL_bool WritePacket(SDL_DriverSwitch_Context *ctx, void *pBuf, Uint8 ucL
|
||||||
return (WriteOutput(ctx, (Uint8 *)pBuf, ucLen) >= 0);
|
return (WriteOutput(ctx, (Uint8 *)pBuf, ucLen) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_bool
|
||||||
|
WritePacketSync(SDL_DriverSwitch_Context *ctx, void *pBuf, Uint8 ucLen)
|
||||||
|
{
|
||||||
|
Uint8 rgucBuf[k_unSwitchMaxOutputPacketLength];
|
||||||
|
const size_t unWriteSize = ctx->m_bUsingBluetooth ? k_unSwitchBluetoothPacketLength : k_unSwitchUSBPacketLength;
|
||||||
|
|
||||||
|
if (ucLen > k_unSwitchOutputPacketDataLength) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ucLen < unWriteSize) {
|
||||||
|
SDL_memcpy(rgucBuf, pBuf, ucLen);
|
||||||
|
SDL_memset(rgucBuf + ucLen, 0, unWriteSize - ucLen);
|
||||||
|
pBuf = rgucBuf;
|
||||||
|
ucLen = (Uint8) unWriteSize;
|
||||||
|
}
|
||||||
|
return (SDL_hid_write(ctx->device->dev, (Uint8 *)pBuf, ucLen) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
|
static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
|
||||||
{
|
{
|
||||||
int nRetries = 5;
|
int nRetries = 5;
|
||||||
|
@ -532,6 +557,29 @@ static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommand
|
||||||
return reply != NULL;
|
return reply != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_bool
|
||||||
|
WriteSubcommandSync(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
|
||||||
|
{
|
||||||
|
int nRetries = 5;
|
||||||
|
SwitchSubcommandInputPacket_t *reply = NULL;
|
||||||
|
|
||||||
|
while (!reply && nRetries--) {
|
||||||
|
SwitchSubcommandOutputPacket_t commandPacket;
|
||||||
|
ConstructSubcommand(ctx, ucCommandID, pBuf, ucLen, &commandPacket);
|
||||||
|
|
||||||
|
if (!WritePacketSync(ctx, &commandPacket, sizeof(commandPacket))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply = ReadSubcommandReply(ctx, ucCommandID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ppReply) {
|
||||||
|
*ppReply = reply;
|
||||||
|
}
|
||||||
|
return reply != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs ucCommand, Uint8 *pBuf, Uint8 ucLen, SDL_bool waitForReply)
|
static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs ucCommand, Uint8 *pBuf, Uint8 ucLen, SDL_bool waitForReply)
|
||||||
{
|
{
|
||||||
int nRetries = 5;
|
int nRetries = 5;
|
||||||
|
@ -975,9 +1023,55 @@ static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ESwitchDeviceInfoControllerType
|
||||||
|
ReadJoyConControllerType(SDL_HIDAPI_Device *device)
|
||||||
|
{
|
||||||
|
ESwitchDeviceInfoControllerType eControllerType = k_eSwitchDeviceInfoControllerType_Unknown;
|
||||||
|
|
||||||
|
/* Create enough of a context to read the controller type from the device */
|
||||||
|
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||||
|
if (ctx) {
|
||||||
|
SwitchSubcommandInputPacket_t *reply = NULL;
|
||||||
|
|
||||||
|
ctx->device = device;
|
||||||
|
ctx->m_bUsingBluetooth = SDL_TRUE;
|
||||||
|
|
||||||
|
device->dev = SDL_hid_open_path(device->path, 0);
|
||||||
|
if (device->dev) {
|
||||||
|
if (WriteSubcommandSync(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) {
|
||||||
|
// Byte 2: Controller ID (1=LJC, 2=RJC, 3=Pro)
|
||||||
|
eControllerType = (ESwitchDeviceInfoControllerType) reply->deviceInfo.ucDeviceType;
|
||||||
|
}
|
||||||
|
SDL_hid_close(device->dev);
|
||||||
|
device->dev = NULL;
|
||||||
|
}
|
||||||
|
SDL_free(ctx);
|
||||||
|
}
|
||||||
|
return eControllerType;
|
||||||
|
}
|
||||||
|
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
|
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) {
|
||||||
|
ESwitchDeviceInfoControllerType eControllerType = ReadJoyConControllerType(device);
|
||||||
|
switch (eControllerType) {
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return HIDAPI_JoystickConnected(device, NULL);
|
return HIDAPI_JoystickConnected(device, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,7 +1147,9 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
|
||||||
input_mode = k_eSwitchInputReportIDs_FullControllerState;
|
input_mode = k_eSwitchInputReportIDs_FullControllerState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input_mode == k_eSwitchInputReportIDs_FullControllerState) {
|
if (input_mode == k_eSwitchInputReportIDs_FullControllerState &&
|
||||||
|
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESLeft &&
|
||||||
|
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESRight) {
|
||||||
/* Use the right sensor in the combined Joy-Con pair */
|
/* Use the right sensor in the combined Joy-Con pair */
|
||||||
if (!device->parent ||
|
if (!device->parent ||
|
||||||
ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
|
ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
|
||||||
|
@ -1123,7 +1219,7 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
|
||||||
ctx->m_bIsGameCube = SDL_TRUE;
|
ctx->m_bIsGameCube = SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AlwaysUsesLabels(device->vendor_id, device->product_id)) {
|
if (AlwaysUsesLabels(device->vendor_id, device->product_id, ctx->m_eControllerType)) {
|
||||||
ctx->m_bUseButtonLabels = SDL_TRUE;
|
ctx->m_bUseButtonLabels = SDL_TRUE;
|
||||||
} else {
|
} else {
|
||||||
SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
|
SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
|
||||||
|
|
Loading…
Reference in a new issue