Added mapping for the Wii Nunchuk extension
parent
e19b36d871
commit
396411c090
|
@ -30,6 +30,7 @@
|
|||
#include "SDL_gamecontrollerdb.h"
|
||||
#include "controller_type.h"
|
||||
#include "usb_ids.h"
|
||||
#include "hidapi/SDL_hidapi_nintendo.h"
|
||||
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
#include "../events/SDL_events_c.h"
|
||||
|
@ -570,25 +571,39 @@ 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 && guid.data[15] != 0 && guid.data[15] != 3) {
|
||||
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||
guid.data[15] != k_eSwitchDeviceInfoControllerType_Unknown &&
|
||||
guid.data[15] != k_eSwitchDeviceInfoControllerType_ProController &&
|
||||
guid.data[15] != k_eWiiExtensionControllerType_WiiUPro) {
|
||||
switch (guid.data[15]) {
|
||||
case 9:
|
||||
case 10:
|
||||
/* NES Controller */
|
||||
case k_eSwitchDeviceInfoControllerType_NESLeft:
|
||||
case k_eSwitchDeviceInfoControllerType_NESRight:
|
||||
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 */
|
||||
case k_eSwitchDeviceInfoControllerType_SNES:
|
||||
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 */
|
||||
case k_eSwitchDeviceInfoControllerType_N64:
|
||||
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 */
|
||||
case k_eSwitchDeviceInfoControllerType_SEGA_Genesis:
|
||||
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;
|
||||
case k_eWiiExtensionControllerType_None:
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,start:b6,x:b2,y:b3,", sizeof(mapping_string));
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_Nunchuck:
|
||||
{
|
||||
/* FIXME: Should we map this to the left or right side? */
|
||||
const SDL_bool map_nunchuck_left_side = SDL_TRUE;
|
||||
|
||||
if (map_nunchuck_left_side) {
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,start:b6,x:b2,y:b3,", sizeof(mapping_string));
|
||||
} else {
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,rightshoulder:b9,righttrigger:a4,rightx:a0,righty:a1,start:b6,x:b2,y:b3,", 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));
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* These are values used in the controller type byte of the controller GUID */
|
||||
|
||||
/* These values come directly out of the hardware, so don't change them */
|
||||
typedef enum {
|
||||
k_eSwitchDeviceInfoControllerType_Unknown = 0,
|
||||
k_eSwitchDeviceInfoControllerType_JoyConLeft = 1,
|
||||
k_eSwitchDeviceInfoControllerType_JoyConRight = 2,
|
||||
k_eSwitchDeviceInfoControllerType_ProController = 3,
|
||||
k_eSwitchDeviceInfoControllerType_NESLeft = 9,
|
||||
k_eSwitchDeviceInfoControllerType_NESRight = 10,
|
||||
k_eSwitchDeviceInfoControllerType_SNES = 11,
|
||||
k_eSwitchDeviceInfoControllerType_N64 = 12,
|
||||
k_eSwitchDeviceInfoControllerType_SEGA_Genesis = 13,
|
||||
} ESwitchDeviceInfoControllerType;
|
||||
|
||||
/* These values are used internally but can be updated as needed */
|
||||
typedef enum {
|
||||
k_eWiiExtensionControllerType_Unknown = 0,
|
||||
k_eWiiExtensionControllerType_None = 128,
|
||||
k_eWiiExtensionControllerType_Nunchuck = 129,
|
||||
k_eWiiExtensionControllerType_ClassicController = 130,
|
||||
k_eWiiExtensionControllerType_ClassicControllerPro = 131,
|
||||
k_eWiiExtensionControllerType_WiiUPro = 132,
|
||||
} EWiiExtensionControllerType;
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -33,6 +33,7 @@
|
|||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
#include "SDL_hidapi_nintendo.h"
|
||||
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH
|
||||
|
@ -102,18 +103,6 @@ typedef enum {
|
|||
k_eSwitchProprietaryCommandIDs_ResetMCU = 0x06,
|
||||
} ESwitchProprietaryCommandIDs;
|
||||
|
||||
typedef enum {
|
||||
k_eSwitchDeviceInfoControllerType_Unknown = 0,
|
||||
k_eSwitchDeviceInfoControllerType_JoyConLeft = 1,
|
||||
k_eSwitchDeviceInfoControllerType_JoyConRight = 2,
|
||||
k_eSwitchDeviceInfoControllerType_ProController = 3,
|
||||
k_eSwitchDeviceInfoControllerType_NESLeft = 9,
|
||||
k_eSwitchDeviceInfoControllerType_NESRight = 10,
|
||||
k_eSwitchDeviceInfoControllerType_SNES = 11,
|
||||
k_eSwitchDeviceInfoControllerType_N64 = 12,
|
||||
k_eSwitchDeviceInfoControllerType_SEGA_Genesis = 13,
|
||||
} ESwitchDeviceInfoControllerType;
|
||||
|
||||
#define k_unSwitchOutputPacketDataLength 49
|
||||
#define k_unSwitchMaxOutputPacketLength 64
|
||||
#define k_unSwitchBluetoothPacketLength k_unSwitchOutputPacketDataLength
|
||||
|
@ -1244,6 +1233,7 @@ UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
|||
if (name && (!name || SDL_strcmp(name, device->name) != 0)) {
|
||||
SDL_free(device->name);
|
||||
device->name = SDL_strdup(name);
|
||||
SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,13 +31,13 @@
|
|||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
#include "SDL_hidapi_nintendo.h"
|
||||
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_WII
|
||||
|
||||
/* Define this if you want to log all packets from the controller */
|
||||
/*#define DEBUG_WII_PROTOCOL*/
|
||||
#define DEBUG_WII_PROTOCOL
|
||||
|
||||
#undef clamp
|
||||
#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val)))
|
||||
|
@ -80,15 +80,6 @@ typedef enum {
|
|||
k_eWiiPlayerLEDs_P4 = 0x80,
|
||||
} EWiiPlayerLEDs;
|
||||
|
||||
typedef enum {
|
||||
k_eWiiExtensionControllerType_None,
|
||||
k_eWiiExtensionControllerType_Unknown,
|
||||
k_eWiiExtensionControllerType_Nunchuck,
|
||||
k_eWiiExtensionControllerType_ClassicController,
|
||||
k_eWiiExtensionControllerType_ClassicControllerPro,
|
||||
k_eWiiExtensionControllerType_WiiUPro,
|
||||
} EWiiExtensionControllerType;
|
||||
|
||||
#define k_unWiiPacketDataLength 22
|
||||
|
||||
typedef struct {
|
||||
|
@ -312,13 +303,13 @@ static SDL_bool ParseExtensionResponse(SDL_DriverWii_Context *ctx)
|
|||
static void UpdatePowerLevelWii(SDL_Joystick *joystick, Uint8 batteryLevelByte)
|
||||
{
|
||||
if (batteryLevelByte > 178) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL);
|
||||
} else if (batteryLevelByte > 51) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_MEDIUM);
|
||||
} else if (batteryLevelByte > 13) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_LOW);
|
||||
} else {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,45 +326,18 @@ static void UpdatePowerLevelWiiU(SDL_Joystick *joystick, Uint8 extensionBatteryB
|
|||
* No value above 4 has been observed.
|
||||
*/
|
||||
if (pluggedIn && !charging) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_WIRED);
|
||||
} else if (batteryLevel >= 4) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL);
|
||||
} else if (batteryLevel > 1) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_MEDIUM);
|
||||
} else if (batteryLevel == 1) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_LOW);
|
||||
} else {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool IdentifyController(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick)
|
||||
{
|
||||
const Uint8 statusRequest[2] = { k_eWiiOutputReportIDs_StatusRequest, 0 };
|
||||
SDL_bool hasExtension;
|
||||
WriteOutput(ctx, statusRequest, sizeof(statusRequest), SDL_TRUE);
|
||||
if (!ReadInputSync(ctx, k_eWiiInputReportIDs_Status, NULL)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
UpdatePowerLevelWii(joystick, ctx->m_rgucReadBuffer[6]);
|
||||
hasExtension = ctx->m_rgucReadBuffer[3] & 2 ? SDL_TRUE : SDL_FALSE;
|
||||
if (hasExtension) {
|
||||
/* http://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way */
|
||||
Uint8 data_0x55 = 0x55;
|
||||
Uint8 data_0x00 = 0x00;
|
||||
SDL_bool ok = WriteRegister(ctx, 0xA400F0, &data_0x55, sizeof(data_0x55), SDL_TRUE)
|
||||
&& WriteRegister(ctx, 0xA400FB, &data_0x00, sizeof(data_0x00), SDL_TRUE)
|
||||
&& ReadRegister(ctx, 0xA400FA, 6, SDL_TRUE)
|
||||
&& ParseExtensionResponse(ctx);
|
||||
if (!ok) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
} else {
|
||||
ctx->m_eExtensionControllerType = k_eWiiExtensionControllerType_None;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static EWiiInputReportIDs GetButtonPacketType(SDL_DriverWii_Context *ctx)
|
||||
{
|
||||
switch (ctx->m_eExtensionControllerType) {
|
||||
|
@ -434,24 +398,6 @@ static void InitStickCalibrationData(SDL_DriverWii_Context *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static const char* GetNameFromExtensionInfo(SDL_DriverWii_Context *ctx)
|
||||
{
|
||||
switch (ctx->m_eExtensionControllerType) {
|
||||
case k_eWiiExtensionControllerType_None:
|
||||
return "Nintendo Wii Remote";
|
||||
case k_eWiiExtensionControllerType_Nunchuck:
|
||||
return "Nintendo Wii Remote with Nunchuck";
|
||||
case k_eWiiExtensionControllerType_ClassicController:
|
||||
return "Nintendo Wii Remote with Classic Controller";
|
||||
case k_eWiiExtensionControllerType_ClassicControllerPro:
|
||||
return "Nintendo Wii Remote with Classic Controller Pro";
|
||||
case k_eWiiExtensionControllerType_WiiUPro:
|
||||
return "Nintendo Wii U Pro Controller";
|
||||
default:
|
||||
return "Nintendo Wii Remote with Unknown Extension";
|
||||
}
|
||||
}
|
||||
|
||||
static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)userdata;
|
||||
|
@ -523,9 +469,84 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c
|
|||
}
|
||||
}
|
||||
|
||||
static EWiiExtensionControllerType
|
||||
ReadControllerType(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
EWiiExtensionControllerType eControllerType = k_eWiiExtensionControllerType_Unknown;
|
||||
|
||||
/* Create enough of a context to read the controller type from the device */
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (ctx) {
|
||||
ctx->device = device;
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (device->dev) {
|
||||
const Uint8 statusRequest[2] = { k_eWiiOutputReportIDs_StatusRequest, 0 };
|
||||
WriteOutput(ctx, statusRequest, sizeof(statusRequest), SDL_TRUE);
|
||||
if (ReadInputSync(ctx, k_eWiiInputReportIDs_Status, NULL)) {
|
||||
SDL_bool hasExtension = (ctx->m_rgucReadBuffer[3] & 2) ? SDL_TRUE : SDL_FALSE;
|
||||
if (hasExtension) {
|
||||
/* http://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way */
|
||||
Uint8 data_0x55 = 0x55;
|
||||
Uint8 data_0x00 = 0x00;
|
||||
if (WriteRegister(ctx, 0xA400F0, &data_0x55, sizeof(data_0x55), SDL_TRUE) &&
|
||||
WriteRegister(ctx, 0xA400FB, &data_0x00, sizeof(data_0x00), SDL_TRUE) &&
|
||||
ReadRegister(ctx, 0xA400FA, 6, SDL_TRUE) && ParseExtensionResponse(ctx)) {
|
||||
eControllerType = ctx->m_eExtensionControllerType;
|
||||
}
|
||||
} else {
|
||||
eControllerType = k_eWiiExtensionControllerType_None;
|
||||
}
|
||||
}
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
SDL_free(ctx);
|
||||
}
|
||||
return eControllerType;
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
EWiiExtensionControllerType eControllerType = (EWiiExtensionControllerType)device->guid.data[15];
|
||||
const char *name = NULL;
|
||||
|
||||
switch (eControllerType) {
|
||||
case k_eWiiExtensionControllerType_None:
|
||||
name = "Nintendo Wii Remote";
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_Nunchuck:
|
||||
name = "Nintendo Wii Remote with Nunchuck";
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_ClassicController:
|
||||
name = "Nintendo Wii Remote with Classic Controller";
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_ClassicControllerPro:
|
||||
name = "Nintendo Wii Remote with Classic Controller Pro";
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_WiiUPro:
|
||||
name = "Nintendo Wii U Pro Controller";
|
||||
break;
|
||||
default:
|
||||
name = "Nintendo Wii Remote with Unknown Extension";
|
||||
break;
|
||||
}
|
||||
if (name && (!name || SDL_strcmp(name, device->name) != 0)) {
|
||||
SDL_free(device->name);
|
||||
device->name = SDL_strdup(name);
|
||||
SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name)));
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
if (device->vendor_id == USB_VENDOR_NINTENDO) {
|
||||
EWiiExtensionControllerType eControllerType = ReadControllerType(device);
|
||||
device->guid.data[15] = eControllerType;
|
||||
UpdateDeviceIdentity(device);
|
||||
}
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -568,19 +589,12 @@ HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|||
goto error;
|
||||
}
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
|
||||
SDL_GameControllerButtonReportingHintChanged, ctx);
|
||||
|
||||
if (!IdentifyController(ctx, joystick)) {
|
||||
char msg[512];
|
||||
SDL_GetErrorMsg(msg, sizeof(msg) - 1);
|
||||
SDL_SetError("Couldn't read device info: %s", msg);
|
||||
goto error;
|
||||
}
|
||||
ctx->m_eExtensionControllerType = (EWiiExtensionControllerType)device->guid.data[15];
|
||||
|
||||
InitStickCalibrationData(ctx);
|
||||
SDL_free(device->name);
|
||||
device->name = SDL_strdup(GetNameFromExtensionInfo(ctx));
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
|
||||
SDL_GameControllerButtonReportingHintChanged, ctx);
|
||||
|
||||
/* Initialize player index (needed for setting LEDs) */
|
||||
ctx->m_nPlayerIndex = SDL_JoystickGetPlayerIndex(joystick);
|
||||
|
@ -953,7 +967,7 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
}
|
||||
|
||||
/* Request a status update periodically to make sure our battery value is up to date */
|
||||
if (SDL_TICKS_PASSED(now, ctx->m_unLastStatus + FIFTEEN_MINUTES_IN_MS)) {
|
||||
if (!ctx->m_unLastStatus || SDL_TICKS_PASSED(now, ctx->m_unLastStatus + FIFTEEN_MINUTES_IN_MS)) {
|
||||
Uint8 data[2];
|
||||
|
||||
data[0] = k_eWiiOutputReportIDs_StatusRequest;
|
||||
|
|
Loading…
Reference in New Issue