Added support for the Switch 2 Joy-Cons with charging grip
This commit is contained in:
@@ -844,8 +844,10 @@ static const struct {
|
|||||||
Uint16 product;
|
Uint16 product;
|
||||||
} SDL_libusb_whitelist[] = {
|
} SDL_libusb_whitelist[] = {
|
||||||
{ USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER },
|
{ USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER },
|
||||||
{ USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_PRO },
|
|
||||||
{ USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER },
|
{ USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER },
|
||||||
|
{ 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_PRO },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool IsInWhitelist(Uint16 vendor, Uint16 product)
|
static bool IsInWhitelist(Uint16 vendor, Uint16 product)
|
||||||
|
|||||||
@@ -716,12 +716,32 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
|||||||
// GameCube driver has 12 buttons and 6 axes
|
// GameCube driver has 12 buttons and 6 axes
|
||||||
SDL_strlcat(mapping_string, "a:b0,b:b2,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:b1,y:b3,misc3:b11,misc4:b10,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
|
SDL_strlcat(mapping_string, "a:b0,b:b2,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:b1,y:b3,misc3:b11,misc4:b10,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
|
||||||
} else if (vendor == USB_VENDOR_NINTENDO &&
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
(product == USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER)) {
|
product == USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER) {
|
||||||
// Switch 2 GameCube has additional buttons for ZL and C
|
SDL_strlcat(mapping_string, "a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,leftshoulder:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a5,rightx:a2,righty:a3,start:b5,x:b2,y:b3,misc1:b8,misc2:b9,misc3:b10,misc4:b11,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
|
||||||
SDL_strlcat(mapping_string, "a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:a4,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,misc3:b4,misc4:b12,rightshoulder:b5,righttrigger:a5,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
|
|
||||||
} else if (vendor == USB_VENDOR_NINTENDO &&
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
(product == USB_PRODUCT_NINTENDO_SWITCH2_PRO)) {
|
product == USB_PRODUCT_NINTENDO_SWITCH2_PRO) {
|
||||||
SDL_strlcat(mapping_string, "a:b0,b:b1,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,rightshoulder:b4,righttrigger:b5,rightx:a2,righty:a3~,start:b6,back:b14,x:b2,y:b3,leftstick:b15,rightstick:b7,paddle1:b18,paddle2:b19,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,misc1:b11,misc2:b12,paddle1:b13,paddle2:b14,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
||||||
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
|
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT) {
|
||||||
|
if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, false)) {
|
||||||
|
// Vertical mode
|
||||||
|
SDL_strlcat(mapping_string, "back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b11,paddle2:b14,paddle4:b16,", sizeof(mapping_string));
|
||||||
|
} else {
|
||||||
|
// 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,paddle2:b14,paddle4:b16,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
|
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT) {
|
||||||
|
if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, false)) {
|
||||||
|
// Vertical mode
|
||||||
|
SDL_strlcat(mapping_string, "a:b0,b:b1,guide:b5,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,misc2:b12,paddle1:b13,paddle3:b15,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
||||||
|
} else {
|
||||||
|
// 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,misc2:b12,paddle1:b13,paddle3:b15,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
|
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR) {
|
||||||
|
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,misc1:b11,misc2:b12,paddle1:b13,paddle2:b14,paddle3:b15,paddle4:b16,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
||||||
} else if (vendor == USB_VENDOR_NINTENDO &&
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
(guid.data[15] == k_eSwitchDeviceInfoControllerType_HVCLeft ||
|
(guid.data[15] == k_eSwitchDeviceInfoControllerType_HVCLeft ||
|
||||||
guid.data[15] == k_eSwitchDeviceInfoControllerType_HVCRight ||
|
guid.data[15] == k_eSwitchDeviceInfoControllerType_HVCRight ||
|
||||||
@@ -840,7 +860,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
|||||||
// GC Ultimate Primary Map
|
// GC Ultimate Primary Map
|
||||||
SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b7,rightstick:b5,righttrigger:a5,rightx:a2,righty:a3,start:b10,misc3:b8,misc4:b9,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
|
SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b7,rightstick:b5,righttrigger:a5,rightx:a2,righty:a3,start:b10,misc3:b8,misc4:b9,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC:
|
case USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC:
|
||||||
switch (sub_type) {
|
switch (sub_type) {
|
||||||
@@ -850,7 +870,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_PRODUCT_BONZIRICHANNEL_FIREBIRD:
|
case USB_PRODUCT_BONZIRICHANNEL_FIREBIRD:
|
||||||
default:
|
default:
|
||||||
// Unmapped device
|
// Unmapped device
|
||||||
|
|||||||
@@ -2953,10 +2953,14 @@ SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, cons
|
|||||||
} else if (vendor == 0x0001 && product == 0x0001) {
|
} else if (vendor == 0x0001 && product == 0x0001) {
|
||||||
type = SDL_GAMEPAD_TYPE_STANDARD;
|
type = SDL_GAMEPAD_TYPE_STANDARD;
|
||||||
|
|
||||||
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT) {
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
|
(product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT ||
|
||||||
|
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT)) {
|
||||||
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT;
|
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT;
|
||||||
|
|
||||||
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT) {
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
|
(product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT ||
|
||||||
|
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT)) {
|
||||||
if (name && SDL_strstr(name, "NES Controller") != NULL) {
|
if (name && SDL_strstr(name, "NES Controller") != NULL) {
|
||||||
// We don't have a type for the Nintendo Online NES Controller
|
// We don't have a type for the Nintendo Online NES Controller
|
||||||
type = SDL_GAMEPAD_TYPE_STANDARD;
|
type = SDL_GAMEPAD_TYPE_STANDARD;
|
||||||
@@ -2971,7 +2975,9 @@ SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, cons
|
|||||||
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT;
|
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR) {
|
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||||
|
(product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR ||
|
||||||
|
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR)) {
|
||||||
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR;
|
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR;
|
||||||
|
|
||||||
} else if (forUI && SDL_IsJoystickGameCube(vendor, product)) {
|
} else if (forUI && SDL_IsJoystickGameCube(vendor, product)) {
|
||||||
@@ -3161,7 +3167,9 @@ bool SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id)
|
|||||||
|
|
||||||
bool SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id)
|
bool SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id)
|
||||||
{
|
{
|
||||||
return vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR;
|
return vendor_id == USB_VENDOR_NINTENDO &&
|
||||||
|
(product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR ||
|
||||||
|
product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDL_IsJoystickGameCube(Uint16 vendor_id, Uint16 product_id)
|
bool SDL_IsJoystickGameCube(Uint16 vendor_id, Uint16 product_id)
|
||||||
|
|||||||
@@ -540,8 +540,11 @@ static const ControllerDescription_t arrControllers[] = {
|
|||||||
{ MAKE_CONTROLLER_ID( 0x05ac, 0x0002 ), k_eControllerType_AppleController, NULL }, // MFI Standard Gamepad (generic entry for iOS/tvOS)
|
{ MAKE_CONTROLLER_ID( 0x05ac, 0x0002 ), k_eControllerType_AppleController, NULL }, // MFI Standard Gamepad (generic entry for iOS/tvOS)
|
||||||
|
|
||||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2006 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch Joy-Con (Left)
|
{ MAKE_CONTROLLER_ID( 0x057e, 0x2006 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch Joy-Con (Left)
|
||||||
|
{ MAKE_CONTROLLER_ID( 0x057e, 0x2067 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch 2 Joy-Con (Left)
|
||||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2007 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch Joy-Con (Right)
|
{ MAKE_CONTROLLER_ID( 0x057e, 0x2007 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch Joy-Con (Right)
|
||||||
|
{ MAKE_CONTROLLER_ID( 0x057e, 0x2066 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch 2 Joy-Con (Right)
|
||||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2008 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch Joy-Con (Left+Right Combined)
|
{ MAKE_CONTROLLER_ID( 0x057e, 0x2008 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch Joy-Con (Left+Right Combined)
|
||||||
|
{ MAKE_CONTROLLER_ID( 0x057e, 0x2068 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch 2 Joy-Con (Left+Right Combined)
|
||||||
|
|
||||||
// This same controller ID is spoofed by many 3rd-party Switch controllers.
|
// This same controller ID is spoofed by many 3rd-party Switch controllers.
|
||||||
// The ones we currently know of are:
|
// The ones we currently know of are:
|
||||||
@@ -550,6 +553,7 @@ static const ControllerDescription_t arrControllers[] = {
|
|||||||
// * ZhiXu Gamepad Wireless
|
// * ZhiXu Gamepad Wireless
|
||||||
// * Sunwaytek Wireless Motion Controller for Nintendo Switch
|
// * Sunwaytek Wireless Motion Controller for Nintendo Switch
|
||||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2009 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Switch Pro Controller
|
{ MAKE_CONTROLLER_ID( 0x057e, 0x2009 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Switch Pro Controller
|
||||||
|
{ MAKE_CONTROLLER_ID( 0x057e, 0x2069 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Switch 2 Pro Controller
|
||||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2017 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SNES Controller
|
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2017 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SNES Controller
|
||||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2019 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online N64 Controller
|
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2019 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online N64 Controller
|
||||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x201e ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SEGA Genesis Controller
|
//{ MAKE_CONTROLLER_ID( 0x057e, 0x201e ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SEGA Genesis Controller
|
||||||
|
|||||||
@@ -1388,7 +1388,15 @@ static bool HIDAPI_DriverSwitch_IsSupportedDevice(SDL_HIDAPI_Device *device, con
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO);
|
if (type != SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Nintendo Switch 2 Pro uses another driver
|
||||||
|
if (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH2_PRO) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
||||||
|
|||||||
@@ -32,6 +32,44 @@
|
|||||||
|
|
||||||
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH2
|
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH2
|
||||||
|
|
||||||
|
// Define this if you want to log all packets from the controller
|
||||||
|
#if 0
|
||||||
|
#define DEBUG_SWITCH2_PROTOCOL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_PRO_SHARE = 11,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_PRO_C,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_PRO_RIGHT_PADDLE,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_PRO_LEFT_PADDLE,
|
||||||
|
SDL_GAMEPAD_NUM_SWITCH2_PRO_BUTTONS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_SHARE = 11,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_C,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE1,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE1,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE2,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE2,
|
||||||
|
SDL_GAMEPAD_NUM_SWITCH2_JOYCON_BUTTONS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_GUIDE = 4,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_START,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_LEFT_SHOULDER,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_RIGHT_SHOULDER,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_SHARE,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_C,
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_LEFT_TRIGGER, // Full trigger pull click
|
||||||
|
SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_RIGHT_TRIGGER, // Full trigger pull click
|
||||||
|
SDL_GAMEPAD_NUM_SWITCH2_GAMECUBE_BUTTONS
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Uint16 neutral;
|
Uint16 neutral;
|
||||||
@@ -58,6 +96,9 @@ typedef struct
|
|||||||
Switch2_StickCalibration right_stick;
|
Switch2_StickCalibration right_stick;
|
||||||
Uint8 left_trigger_max;
|
Uint8 left_trigger_max;
|
||||||
Uint8 right_trigger_max;
|
Uint8 right_trigger_max;
|
||||||
|
|
||||||
|
bool vertical_mode;
|
||||||
|
Uint8 last_state[USB_PACKET_LENGTH];
|
||||||
} SDL_DriverSwitch2_Context;
|
} SDL_DriverSwitch2_Context;
|
||||||
|
|
||||||
static void ParseStickCalibration(Switch2_StickCalibration *stick_data, const Uint8 *data)
|
static void ParseStickCalibration(Switch2_StickCalibration *stick_data, const Uint8 *data)
|
||||||
@@ -127,7 +168,7 @@ static int RecvBulkData(SDL_DriverSwitch2_Context *ctx, Uint8 *data, unsigned si
|
|||||||
return total_transferred;
|
return total_transferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MapJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick, int axis, const Switch2_AxisCalibration *calib, float value)
|
static void MapJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick, Uint8 axis, const Switch2_AxisCalibration *calib, float value, bool invert)
|
||||||
{
|
{
|
||||||
Sint16 mapped_value;
|
Sint16 mapped_value;
|
||||||
if (calib && calib->neutral && calib->min && calib->max) {
|
if (calib && calib->neutral && calib->min && calib->max) {
|
||||||
@@ -141,10 +182,13 @@ static void MapJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick, int axis,
|
|||||||
} else {
|
} else {
|
||||||
mapped_value = (Sint16) HIDAPI_RemapVal(value, 0, 4096, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
mapped_value = (Sint16) HIDAPI_RemapVal(value, 0, 4096, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||||
}
|
}
|
||||||
|
if (invert) {
|
||||||
|
mapped_value = ~mapped_value;
|
||||||
|
}
|
||||||
SDL_SendJoystickAxis(timestamp, joystick, axis, mapped_value);
|
SDL_SendJoystickAxis(timestamp, joystick, axis, mapped_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MapTriggerAxis(Uint64 timestamp, SDL_Joystick *joystick, int axis, Uint8 max, float value)
|
static void MapTriggerAxis(Uint64 timestamp, SDL_Joystick *joystick, Uint8 axis, Uint8 max, float value)
|
||||||
{
|
{
|
||||||
Sint16 mapped_value = (Sint16) HIDAPI_RemapVal(
|
Sint16 mapped_value = (Sint16) HIDAPI_RemapVal(
|
||||||
SDL_clamp((value - max) / (232.f - max), 0, 1),
|
SDL_clamp((value - max) / (232.f - max), 0, 1),
|
||||||
@@ -174,6 +218,8 @@ static bool HIDAPI_DriverSwitch2_IsSupportedDevice(SDL_HIDAPI_Device *device, co
|
|||||||
if (vendor_id == USB_VENDOR_NINTENDO) {
|
if (vendor_id == USB_VENDOR_NINTENDO) {
|
||||||
switch (product_id) {
|
switch (product_id) {
|
||||||
case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER:
|
case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER:
|
||||||
|
case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT:
|
||||||
|
case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT:
|
||||||
case USB_PRODUCT_NINTENDO_SWITCH2_PRO:
|
case USB_PRODUCT_NINTENDO_SWITCH2_PRO:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -366,122 +412,31 @@ static void HIDAPI_DriverSwitch2_SetDevicePlayerIndex(SDL_HIDAPI_Device *device,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HIDAPI_DriverSwitch2_UpdateDevice(SDL_HIDAPI_Device *device)
|
static bool HIDAPI_DriverSwitch2_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||||
{
|
{
|
||||||
SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context;
|
SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context;
|
||||||
|
|
||||||
const struct {
|
|
||||||
int byte;
|
|
||||||
unsigned char mask;
|
|
||||||
} buttons[] = {
|
|
||||||
{3, 0x01}, // B
|
|
||||||
{3, 0x02}, // A
|
|
||||||
{3, 0x04}, // Y
|
|
||||||
{3, 0x08}, // X
|
|
||||||
{3, 0x10}, // R (GameCube R Click)
|
|
||||||
{3, 0x20}, // ZR (GameCube Z)
|
|
||||||
{3, 0x40}, // PLUS (GameCube Start)
|
|
||||||
{3, 0x80}, // RS (not on GameCube)
|
|
||||||
{4, 0x01}, // DPAD_DOWN
|
|
||||||
{4, 0x02}, // DPAD_RIGHT
|
|
||||||
{4, 0x04}, // DPAD_LEFT
|
|
||||||
{4, 0x08}, // DPAD_UP
|
|
||||||
{4, 0x10}, // L (GameCube L Click)
|
|
||||||
{4, 0x20}, // ZL
|
|
||||||
{4, 0x40}, // MINUS (not on GameCube)
|
|
||||||
{4, 0x80}, // LS (not on GameCube)
|
|
||||||
{5, 0x01}, // Home
|
|
||||||
{5, 0x02}, // Capture
|
|
||||||
{5, 0x04}, // GR (not on GameCube)
|
|
||||||
{5, 0x08}, // GL (not on GameCube)
|
|
||||||
{5, 0x10}, // C
|
|
||||||
};
|
|
||||||
|
|
||||||
SDL_Joystick *joystick = NULL;
|
|
||||||
if (device->num_joysticks > 0) {
|
|
||||||
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
|
|
||||||
}
|
|
||||||
if (joystick == NULL) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read input packet
|
|
||||||
|
|
||||||
Uint8 packet[USB_PACKET_LENGTH];
|
|
||||||
int size;
|
|
||||||
while ((size = SDL_hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) {
|
|
||||||
if (size < 15) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint64 timestamp = SDL_GetTicksNS();
|
|
||||||
for (size_t i = 0; i < SDL_arraysize(buttons); ++i) {
|
|
||||||
SDL_SendJoystickButton(
|
|
||||||
timestamp,
|
|
||||||
joystick,
|
|
||||||
(Uint8) i,
|
|
||||||
(packet[buttons[i].byte] & buttons[i].mask) != 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
MapJoystickAxis(
|
|
||||||
timestamp,
|
|
||||||
joystick,
|
|
||||||
SDL_GAMEPAD_AXIS_LEFTX,
|
|
||||||
&ctx->left_stick.x,
|
|
||||||
(float) (packet[6] | ((packet[7] & 0x0F) << 8))
|
|
||||||
);
|
|
||||||
MapJoystickAxis(
|
|
||||||
timestamp,
|
|
||||||
joystick,
|
|
||||||
SDL_GAMEPAD_AXIS_LEFTY,
|
|
||||||
&ctx->left_stick.y,
|
|
||||||
(float) ((packet[7] >> 4) | (packet[8] << 4))
|
|
||||||
);
|
|
||||||
MapJoystickAxis(
|
|
||||||
timestamp,
|
|
||||||
joystick,
|
|
||||||
SDL_GAMEPAD_AXIS_RIGHTX,
|
|
||||||
&ctx->right_stick.x,
|
|
||||||
(float) (packet[9] | ((packet[10] & 0x0F) << 8))
|
|
||||||
);
|
|
||||||
MapJoystickAxis(
|
|
||||||
timestamp,
|
|
||||||
joystick,
|
|
||||||
SDL_GAMEPAD_AXIS_RIGHTY,
|
|
||||||
&ctx->right_stick.y,
|
|
||||||
(float) ((packet[10] >> 4) | (packet[11] << 4))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER) {
|
|
||||||
MapTriggerAxis(
|
|
||||||
timestamp,
|
|
||||||
joystick,
|
|
||||||
SDL_GAMEPAD_AXIS_LEFT_TRIGGER,
|
|
||||||
ctx->left_trigger_max,
|
|
||||||
packet[13]
|
|
||||||
);
|
|
||||||
MapTriggerAxis(
|
|
||||||
timestamp,
|
|
||||||
joystick,
|
|
||||||
SDL_GAMEPAD_AXIS_RIGHT_TRIGGER,
|
|
||||||
ctx->right_trigger_max,
|
|
||||||
packet[14]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool HIDAPI_DriverSwitch2_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
||||||
{
|
|
||||||
// Initialize the joystick capabilities
|
// Initialize the joystick capabilities
|
||||||
joystick->nbuttons = 21;
|
switch (device->product_id) {
|
||||||
if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER) {
|
case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER:
|
||||||
joystick->naxes = 6;
|
joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH2_GAMECUBE_BUTTONS;
|
||||||
} else {
|
break;
|
||||||
joystick->naxes = 4;
|
case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT:
|
||||||
|
case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT:
|
||||||
|
joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH2_JOYCON_BUTTONS;
|
||||||
|
break;
|
||||||
|
case USB_PRODUCT_NINTENDO_SWITCH2_PRO:
|
||||||
|
joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH2_PRO_BUTTONS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// FIXME: How many buttons does this have?
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
|
||||||
|
joystick->nhats = 1;
|
||||||
|
|
||||||
|
// Set up for vertical mode
|
||||||
|
ctx->vertical_mode = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -516,6 +471,419 @@ static bool HIDAPI_DriverSwitch2_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *de
|
|||||||
return SDL_Unsupported();
|
return SDL_Unsupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void HandleGameCubeState(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size)
|
||||||
|
{
|
||||||
|
if (data[3] != ctx->last_state[3]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x02) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x04) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x08) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_RIGHT_TRIGGER, ((data[3] & 0x10) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_RIGHT_SHOULDER, ((data[3] & 0x20) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_START, ((data[3] & 0x40) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[4] != ctx->last_state[4]) {
|
||||||
|
Uint8 hat = 0;
|
||||||
|
|
||||||
|
if (data[4] & 0x01) {
|
||||||
|
hat |= SDL_HAT_DOWN;
|
||||||
|
}
|
||||||
|
if (data[4] & 0x02) {
|
||||||
|
hat |= SDL_HAT_RIGHT;
|
||||||
|
}
|
||||||
|
if (data[4] & 0x04) {
|
||||||
|
hat |= SDL_HAT_LEFT;
|
||||||
|
}
|
||||||
|
if (data[4] & 0x08) {
|
||||||
|
hat |= SDL_HAT_UP;
|
||||||
|
}
|
||||||
|
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||||
|
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_LEFT_TRIGGER, ((data[4] & 0x10) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_LEFT_SHOULDER, ((data[4] & 0x20) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[5] != ctx->last_state[5]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_GUIDE, ((data[5] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_SHARE, ((data[5] & 0x02) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_C, ((data[5] & 0x10) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
MapTriggerAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFT_TRIGGER,
|
||||||
|
ctx->left_trigger_max,
|
||||||
|
data[13]
|
||||||
|
);
|
||||||
|
MapTriggerAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_RIGHT_TRIGGER,
|
||||||
|
ctx->right_trigger_max,
|
||||||
|
data[14]
|
||||||
|
);
|
||||||
|
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTX,
|
||||||
|
&ctx->left_stick.x,
|
||||||
|
(float) (data[6] | ((data[7] & 0x0F) << 8)),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTY,
|
||||||
|
&ctx->left_stick.y,
|
||||||
|
(float) ((data[7] >> 4) | (data[8] << 4)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_RIGHTX,
|
||||||
|
&ctx->right_stick.x,
|
||||||
|
(float) (data[9] | ((data[10] & 0x0F) << 8)),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_RIGHTY,
|
||||||
|
&ctx->right_stick.y,
|
||||||
|
(float)((data[10] >> 4) | (data[11] << 4)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HandleCombinedControllerStateL(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size)
|
||||||
|
{
|
||||||
|
// FIXME: When we find out what the SL and SR buttons are, map them to paddles
|
||||||
|
|
||||||
|
if (data[3] != ctx->last_state[3]) {
|
||||||
|
Uint8 hat = 0;
|
||||||
|
|
||||||
|
if (data[3] & 0x01) {
|
||||||
|
hat |= SDL_HAT_DOWN;
|
||||||
|
}
|
||||||
|
if (data[3] & 0x02) {
|
||||||
|
hat |= SDL_HAT_RIGHT;
|
||||||
|
}
|
||||||
|
if (data[3] & 0x04) {
|
||||||
|
hat |= SDL_HAT_LEFT;
|
||||||
|
}
|
||||||
|
if (data[3] & 0x08) {
|
||||||
|
hat |= SDL_HAT_UP;
|
||||||
|
}
|
||||||
|
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||||
|
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[3] & 0x10) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[3] & 0x40) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[3] & 0x80) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[4] != ctx->last_state[4]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_SHARE, ((data[4] & 0x01) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
Sint16 axis = (data[3] & 0x20) ? 32767 : -32768;
|
||||||
|
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
|
||||||
|
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTX,
|
||||||
|
&ctx->left_stick.x,
|
||||||
|
(float) (data[6] | ((data[7] & 0x0F) << 8)),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTY,
|
||||||
|
&ctx->left_stick.y,
|
||||||
|
(float) ((data[7] >> 4) | (data[8] << 4)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HandleMiniControllerStateL(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size)
|
||||||
|
{
|
||||||
|
// FIXME: When we find out what the SL and SR buttons are, map them to shoulder buttons
|
||||||
|
|
||||||
|
if (data[3] != ctx->last_state[3]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x02) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x04) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x08) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[3] & 0x40) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE1, ((data[3] & 0x10) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE2, ((data[3] & 0x20) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[3] & 0x80) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[4] != ctx->last_state[4]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[4] & 0x01) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTX,
|
||||||
|
&ctx->left_stick.y,
|
||||||
|
(float) ((data[7] >> 4) | (data[8] << 4)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTY,
|
||||||
|
&ctx->left_stick.x,
|
||||||
|
(float) (data[6] | ((data[7] & 0x0F) << 8)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HandleCombinedControllerStateR(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size)
|
||||||
|
{
|
||||||
|
// FIXME: When we find out what the SL and SR buttons are, map them to paddles
|
||||||
|
|
||||||
|
if (data[3] != ctx->last_state[3]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x02) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x04) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x08) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[3] & 0x10) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[3] & 0x40) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[3] & 0x80) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[4] != ctx->last_state[4]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[4] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_C, ((data[4] & 0x10) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
Sint16 axis = (data[3] & 0x20) ? 32767 : -32768;
|
||||||
|
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
|
||||||
|
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_RIGHTX,
|
||||||
|
&ctx->left_stick.x,
|
||||||
|
(float) (data[6] | ((data[7] & 0x0F) << 8)),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_RIGHTY,
|
||||||
|
&ctx->left_stick.y,
|
||||||
|
(float) ((data[7] >> 4) | (data[8] << 4)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HandleMiniControllerStateR(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size)
|
||||||
|
{
|
||||||
|
// FIXME: When we find out what the SL and SR buttons are, map them to shoulder buttons
|
||||||
|
|
||||||
|
if (data[3] != ctx->last_state[3]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x02) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x04) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x08) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE1, ((data[3] & 0x10) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE2, ((data[3] & 0x20) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[3] & 0x40) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[3] & 0x80) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[4] != ctx->last_state[4]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[4] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_C, ((data[4] & 0x10) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTX,
|
||||||
|
&ctx->left_stick.y,
|
||||||
|
(float) ((data[7] >> 4) | (data[8] << 4)),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTY,
|
||||||
|
&ctx->left_stick.x,
|
||||||
|
(float) (data[6] | ((data[7] & 0x0F) << 8)),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HandleSwitchProState(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size)
|
||||||
|
{
|
||||||
|
Sint16 axis;
|
||||||
|
|
||||||
|
if (data[3] != ctx->last_state[3]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x02) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x04) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x08) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[3] & 0x10) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[3] & 0x40) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[3] & 0x80) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[4] != ctx->last_state[4]) {
|
||||||
|
Uint8 hat = 0;
|
||||||
|
|
||||||
|
if (data[4] & 0x01) {
|
||||||
|
hat |= SDL_HAT_DOWN;
|
||||||
|
}
|
||||||
|
if (data[4] & 0x02) {
|
||||||
|
hat |= SDL_HAT_RIGHT;
|
||||||
|
}
|
||||||
|
if (data[4] & 0x04) {
|
||||||
|
hat |= SDL_HAT_LEFT;
|
||||||
|
}
|
||||||
|
if (data[4] & 0x08) {
|
||||||
|
hat |= SDL_HAT_UP;
|
||||||
|
}
|
||||||
|
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||||
|
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[4] & 0x10) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[4] & 0x40) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[4] & 0x80) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[5] != ctx->last_state[5]) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[5] & 0x01) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_SHARE, ((data[5] & 0x02) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_RIGHT_PADDLE, ((data[5] & 0x04) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_LEFT_PADDLE, ((data[5] & 0x08) != 0));
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_C, ((data[5] & 0x10) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
axis = (data[4] & 0x20) ? 32767 : -32768;
|
||||||
|
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
|
||||||
|
|
||||||
|
axis = (data[3] & 0x20) ? 32767 : -32768;
|
||||||
|
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
|
||||||
|
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTX,
|
||||||
|
&ctx->left_stick.x,
|
||||||
|
(float) (data[6] | ((data[7] & 0x0F) << 8)),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_LEFTY,
|
||||||
|
&ctx->left_stick.y,
|
||||||
|
(float) ((data[7] >> 4) | (data[8] << 4)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_RIGHTX,
|
||||||
|
&ctx->right_stick.x,
|
||||||
|
(float) (data[9] | ((data[10] & 0x0F) << 8)),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
MapJoystickAxis(
|
||||||
|
timestamp,
|
||||||
|
joystick,
|
||||||
|
SDL_GAMEPAD_AXIS_RIGHTY,
|
||||||
|
&ctx->right_stick.y,
|
||||||
|
(float)((data[10] >> 4) | (data[11] << 4)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HIDAPI_DriverSwitch2_HandleStatePacket(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size)
|
||||||
|
{
|
||||||
|
Uint64 timestamp = SDL_GetTicksNS();
|
||||||
|
|
||||||
|
if (size < 15) {
|
||||||
|
// We don't know how to handle this report
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (device->product_id) {
|
||||||
|
case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER:
|
||||||
|
HandleGameCubeState(timestamp, joystick, ctx, data, size);
|
||||||
|
break;
|
||||||
|
case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT:
|
||||||
|
if (device->parent || ctx->vertical_mode) {
|
||||||
|
HandleCombinedControllerStateL(timestamp, joystick, ctx, data, size);
|
||||||
|
} else {
|
||||||
|
HandleMiniControllerStateL(timestamp, joystick, ctx, data, size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT:
|
||||||
|
if (device->parent || ctx->vertical_mode) {
|
||||||
|
HandleCombinedControllerStateR(timestamp, joystick, ctx, data, size);
|
||||||
|
} else {
|
||||||
|
HandleMiniControllerStateR(timestamp, joystick, ctx, data, size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB_PRODUCT_NINTENDO_SWITCH2_PRO:
|
||||||
|
HandleSwitchProState(timestamp, joystick, ctx, data, size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// FIXME: Need state handling implementation
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HIDAPI_DriverSwitch2_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||||
|
{
|
||||||
|
SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context;
|
||||||
|
SDL_Joystick *joystick = NULL;
|
||||||
|
Uint8 data[USB_PACKET_LENGTH];
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
if (device->num_joysticks > 0) {
|
||||||
|
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
|
||||||
|
#ifdef DEBUG_SWITCH2_PROTOCOL
|
||||||
|
if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT) {
|
||||||
|
HIDAPI_DumpPacket("Nintendo Joy-Con(L) packet: size = %d", data, size);
|
||||||
|
} else if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT) {
|
||||||
|
HIDAPI_DumpPacket("Nintendo Joy-Con(R) packet: size = %d", data, size);
|
||||||
|
} else {
|
||||||
|
HIDAPI_DumpPacket("Nintendo Switch2 packet: size = %d", data, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!joystick) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HIDAPI_DriverSwitch2_HandleStatePacket(device, joystick, ctx, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
// Read error, device is disconnected
|
||||||
|
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||||
|
}
|
||||||
|
return (size >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void HIDAPI_DriverSwitch2_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
static void HIDAPI_DriverSwitch2_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,7 +452,9 @@ static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, bool *removed) S
|
|||||||
if (device->driver) {
|
if (device->driver) {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
|
||||||
if (device->vendor_id == USB_VENDOR_NINTENDO && device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR) {
|
if (device->vendor_id == USB_VENDOR_NINTENDO &&
|
||||||
|
(device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR ||
|
||||||
|
device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR)) {
|
||||||
enabled = SDL_HIDAPI_combine_joycons;
|
enabled = SDL_HIDAPI_combine_joycons;
|
||||||
} else {
|
} else {
|
||||||
enabled = device->driver->enabled;
|
enabled = device->driver->enabled;
|
||||||
@@ -1068,7 +1070,11 @@ static bool HIDAPI_CreateCombinedJoyCons(void)
|
|||||||
SDL_zero(info);
|
SDL_zero(info);
|
||||||
info.path = "nintendo_joycons_combined";
|
info.path = "nintendo_joycons_combined";
|
||||||
info.vendor_id = USB_VENDOR_NINTENDO;
|
info.vendor_id = USB_VENDOR_NINTENDO;
|
||||||
info.product_id = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR;
|
if (joycons[0]->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT) {
|
||||||
|
info.product_id = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR;
|
||||||
|
} else {
|
||||||
|
info.product_id = USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR;
|
||||||
|
}
|
||||||
info.interface_number = -1;
|
info.interface_number = -1;
|
||||||
info.usage_page = USB_USAGEPAGE_GENERIC_DESKTOP;
|
info.usage_page = USB_USAGEPAGE_GENERIC_DESKTOP;
|
||||||
info.usage = USB_USAGE_GENERIC_GAMEPAD;
|
info.usage = USB_USAGE_GENERIC_GAMEPAD;
|
||||||
|
|||||||
@@ -103,8 +103,11 @@
|
|||||||
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR 0x2008 // Used by joycond
|
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR 0x2008 // Used by joycond
|
||||||
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT 0x2007
|
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT 0x2007
|
||||||
#define USB_PRODUCT_NINTENDO_SWITCH_PRO 0x2009
|
#define USB_PRODUCT_NINTENDO_SWITCH_PRO 0x2009
|
||||||
#define USB_PRODUCT_NINTENDO_SWITCH2_PRO 0x2069
|
|
||||||
#define USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER 0x2073
|
#define USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER 0x2073
|
||||||
|
#define USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT 0x2067
|
||||||
|
#define USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR 0x2068
|
||||||
|
#define USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT 0x2066
|
||||||
|
#define USB_PRODUCT_NINTENDO_SWITCH2_PRO 0x2069
|
||||||
#define USB_PRODUCT_NINTENDO_WII_REMOTE 0x0306
|
#define USB_PRODUCT_NINTENDO_WII_REMOTE 0x0306
|
||||||
#define USB_PRODUCT_NINTENDO_WII_REMOTE2 0x0330
|
#define USB_PRODUCT_NINTENDO_WII_REMOTE2 0x0330
|
||||||
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103 0x7210
|
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103 0x7210
|
||||||
@@ -167,7 +170,7 @@
|
|||||||
#define USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC 0x10c6
|
#define USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC 0x10c6
|
||||||
#define USB_PRODUCT_HANDHELDLEGEND_PROGCC 0x10df
|
#define USB_PRODUCT_HANDHELDLEGEND_PROGCC 0x10df
|
||||||
#define USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE 0x10dd
|
#define USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE 0x10dd
|
||||||
#define USB_PRODUCT_BONZIRICHANNEL_FIREBIRD 0x10e0
|
#define USB_PRODUCT_BONZIRICHANNEL_FIREBIRD 0x10e0
|
||||||
|
|
||||||
// USB usage pages
|
// USB usage pages
|
||||||
#define USB_USAGEPAGE_GENERIC_DESKTOP 0x0001
|
#define USB_USAGEPAGE_GENERIC_DESKTOP 0x0001
|
||||||
|
|||||||
Reference in New Issue
Block a user