Merge branch 'wiiu-controllers' into wiiu

This commit is contained in:
rw-r-r-0644 2019-06-29 20:19:44 +02:00
commit 00479f519f
No known key found for this signature in database
GPG Key ID: 9F89C03279187405
2 changed files with 421 additions and 28 deletions

View File

@ -1,6 +1,7 @@
/*
Simple DirectMedia Layer
Copyright (C) 2018 Roberto Van Eeden <r.r.qwertyuiop.r.r@gmail.com>
Copyright (C) 2019 Ash Logan <ash@heyquark.com>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -24,6 +25,8 @@
#if SDL_JOYSTICK_WIIU
#include <vpad/input.h>
#include <padscore/wpad.h>
#include <padscore/kpad.h>
#include <coreinit/debug.h>
#include "SDL_joystick.h"
@ -31,22 +34,61 @@
#include "../SDL_joystick_c.h"
#include "../../events/SDL_touch_c.h"
#include "SDL_log.h"
#include "SDL_assert.h"
#include "SDL_events.h"
#define JOYSTICK_COUNT 1
#include "SDL_wiiujoystick.h"
static VPADButtons vpad_button_map[] =
{
VPAD_BUTTON_A, VPAD_BUTTON_B, VPAD_BUTTON_X, VPAD_BUTTON_Y,
VPAD_BUTTON_STICK_L, VPAD_BUTTON_STICK_R,
VPAD_BUTTON_L, VPAD_BUTTON_R,
VPAD_BUTTON_ZL, VPAD_BUTTON_ZR,
VPAD_BUTTON_PLUS, VPAD_BUTTON_MINUS,
VPAD_BUTTON_LEFT, VPAD_BUTTON_UP, VPAD_BUTTON_RIGHT, VPAD_BUTTON_DOWN,
VPAD_STICK_L_EMULATION_LEFT, VPAD_STICK_L_EMULATION_UP, VPAD_STICK_L_EMULATION_RIGHT, VPAD_STICK_L_EMULATION_DOWN,
VPAD_STICK_R_EMULATION_LEFT, VPAD_STICK_R_EMULATION_UP, VPAD_STICK_R_EMULATION_RIGHT, VPAD_STICK_R_EMULATION_DOWN
};
//index with device_index, get WIIU_DEVICE*
static int deviceMap[MAX_CONTROLLERS];
//index with device_index, get SDL_JoystickID
static SDL_JoystickID instanceMap[MAX_CONTROLLERS];
static WPADExtensionType lastKnownExts[WIIU_NUM_WPADS];
static int WIIU_GetDeviceForIndex(int device_index) {
return deviceMap[device_index];
}
static int WIIU_GetIndexForDevice(int wiiu_device) {
for (int i = 0; i < MAX_CONTROLLERS; i++) {
if (deviceMap[i] == wiiu_device) return i;
}
return -1;
}
static int WIIU_GetNextDeviceIndex() {
return WIIU_GetIndexForDevice(WIIU_DEVICE_INVALID);
}
static SDL_JoystickID WIIU_GetInstForIndex(int device_index) {
if (device_index == -1) return -1;
return instanceMap[device_index];
}
static SDL_JoystickID WIIU_GetInstForDevice(int wiiu_device) {
int device_index = WIIU_GetIndexForDevice(wiiu_device);
return WIIU_GetInstForIndex(device_index);
}
static int WIIU_GetDeviceForInst(SDL_JoystickID instance) {
for (int i = 0; i < MAX_CONTROLLERS; i++) {
if (instanceMap[i] == instance) return deviceMap[i];
}
return WIIU_DEVICE_INVALID;
}
static void WIIU_RemoveDevice(int wiiu_device) {
int device_index = WIIU_GetIndexForDevice(wiiu_device);
if (device_index == -1) return;
/* Move all the other controllers back, so all device_indexes are valid */
for (int i = device_index; i < MAX_CONTROLLERS; i++) {
if (i + 1 < MAX_CONTROLLERS) {
deviceMap[i] = deviceMap[i + 1];
instanceMap[i] = instanceMap[i + 1];
} else {
deviceMap[i] = -1;
instanceMap[i] = -1;
}
}
}
/* Function to scan the system for joysticks.
* Joystick 0 should be the system default joystick.
@ -54,26 +96,129 @@ static VPADButtons vpad_button_map[] =
*/
static int WIIU_JoystickInit(void)
{
return JOYSTICK_COUNT;
VPADInit();
KPADInit();
WPADEnableURCC(1);
for (int i = 0; i < MAX_CONTROLLERS; i++) {
deviceMap[i] = WIIU_DEVICE_INVALID;
instanceMap[i] = -1;
}
WIIU_JoystickDetect();
return 0;
}
/* Function to return the number of joystick devices plugged in right now */
static int WIIU_JoystickGetCount(void)
{
return JOYSTICK_COUNT;
return WIIU_GetNextDeviceIndex();
}
/* Function to cause any queued joystick insertions to be processed */
static void WIIU_JoystickDetect(void)
{
/* Make sure there are no dangling instances or device indexes
These checks *should* be unneccesary, remove once battle-tested */
for (int i = 0; i < MAX_CONTROLLERS; i++) {
if (deviceMap[i] == WIIU_DEVICE_INVALID && instanceMap[i] != -1) {
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
"WiiU device_index %d dangling instance %d!\n",
i, instanceMap[i]
);
/* Make sure that joystick actually got removed */
SDL_PrivateJoystickRemoved(instanceMap[i]);
instanceMap[i] = -1;
}
if (deviceMap[i] != WIIU_DEVICE_INVALID && instanceMap[i] == -1) {
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
"WiiU device_index %d assigned to %d, but has no instance!\n",
i, deviceMap[i]
);
instanceMap[i] = -1;
}
}
/* Check if we are missing the WiiU Gamepad and try to connect it
if the gamepad is disconnected that's handled in SDL_UpdateJoystick */
if (WIIU_GetIndexForDevice(WIIU_DEVICE_GAMEPAD) == -1) {
/* Try and detect a gamepad */
VPADStatus status;
VPADReadError err;
VPADRead(VPAD_CHAN_0, &status, 1, &err);
if (err == VPAD_READ_SUCCESS || err == VPAD_READ_NO_SAMPLES) {
/* We have a gamepad! Assign a device index and instance ID. */
int device_index = WIIU_GetNextDeviceIndex();
if (device_index != -1) {
/* Save its device index */
deviceMap[device_index] = WIIU_DEVICE_GAMEPAD;
instanceMap[device_index] = SDL_GetNextJoystickInstanceID();
SDL_PrivateJoystickAdded(instanceMap[device_index]);
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT,
"WiiU: Detected Gamepad, assigned device %d/instance %d\n",
device_index, instanceMap[device_index]);
}
}
}
/* Check for WPAD/KPAD controllers */
for (int i = 0; i < WIIU_NUM_WPADS; i++) {
WPADExtensionType ext;
int wiiu_device = WIIU_DEVICE_WPAD(i);
int ret = WPADProbe(WIIU_WPAD_CHAN(wiiu_device), &ext);
if (ret == 0) { //controller connected
/* Is this already connected? */
if (WIIU_GetIndexForDevice(wiiu_device) == -1) {
/* No! Let's add it. */
int device_index = WIIU_GetNextDeviceIndex();
if (device_index != -1) {
/* Save its device index */
deviceMap[device_index] = WIIU_DEVICE_WPAD(i);
instanceMap[device_index] = SDL_GetNextJoystickInstanceID();
/* Save its extension controller */
lastKnownExts[WIIU_WPAD_CHAN(wiiu_device)] = ext;
SDL_PrivateJoystickAdded(instanceMap[device_index]);
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT,
"WiiU: Detected WPAD, assigned device %d/instance %d\n",
device_index, instanceMap[device_index]);
}
} else if (ext != lastKnownExts[WIIU_WPAD_CHAN(wiiu_device)]) {
/* If this controller has changed extensions, we should
disconnect and reconnect it. */
SDL_JoystickID instance = WIIU_GetInstForDevice(wiiu_device);
/* Yes! We should disconnect it. */
SDL_PrivateJoystickRemoved(instance);
/* Unlink device_index, instance_id */
WIIU_RemoveDevice(wiiu_device);
}
} else if (ret == -1) { //no controller
/* Is this controller connected? */
if (WIIU_GetIndexForDevice(wiiu_device) != -1) {
SDL_JoystickID instance = WIIU_GetInstForDevice(wiiu_device);
/* Yes! We should disconnect it. */
SDL_PrivateJoystickRemoved(instance);
/* Unlink device_index, instance_id */
WIIU_RemoveDevice(wiiu_device);
}
} // otherwise do nothing (-2: pairing)
}
}
/* Function to get the device-dependent name of a joystick */
static const char *WIIU_JoystickGetDeviceName(int device_index)
{
int wiiu_device = WIIU_GetDeviceForIndex(device_index);
/* Gamepad */
if (device_index == 0)
if (wiiu_device == WIIU_DEVICE_GAMEPAD) {
return "WiiU Gamepad";
} else if (wiiu_device == WIIU_DEVICE_WPAD(0)) {
RETURN_WPAD_NAME(1, lastKnownExts[0]);
} else if (wiiu_device == WIIU_DEVICE_WPAD(1)) {
RETURN_WPAD_NAME(2, lastKnownExts[1]);
} else if (wiiu_device == WIIU_DEVICE_WPAD(2)) {
RETURN_WPAD_NAME(3, lastKnownExts[2]);
} else if (wiiu_device == WIIU_DEVICE_WPAD(3)) {
RETURN_WPAD_NAME(4, lastKnownExts[3]);
}
return "Unknown";
}
@ -97,7 +242,7 @@ static SDL_JoystickGUID WIIU_JoystickGetDeviceGUID(int device_index)
/* Function to get the current instance id of the joystick located at device_index */
static SDL_JoystickID WIIU_JoystickGetDeviceInstanceID(int device_index)
{
return device_index;
return WIIU_GetInstForIndex(device_index);
}
/* Function to open a joystick for use.
@ -107,16 +252,64 @@ static SDL_JoystickID WIIU_JoystickGetDeviceInstanceID(int device_index)
*/
static int WIIU_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
/* Gamepad */
if (device_index == 0) {
SDL_AddTouch(0, "WiiU Gamepad Touchscreen");
joystick->nbuttons = sizeof(vpad_button_map) / sizeof(VPADButtons);
joystick->naxes = 4;
joystick->nhats = 0;
int wiiu_device = WIIU_GetDeviceForIndex(device_index);
switch (wiiu_device) {
case WIIU_DEVICE_GAMEPAD: {
SDL_AddTouch(0, "WiiU Gamepad Touchscreen");
joystick->nbuttons = SIZEOF_ARR(vpad_button_map);
joystick->naxes = 4;
joystick->nhats = 0;
break;
}
case WIIU_DEVICE_WPAD(0):
case WIIU_DEVICE_WPAD(1):
case WIIU_DEVICE_WPAD(2):
case WIIU_DEVICE_WPAD(3): {
WPADExtensionType ext;
int ret = WPADProbe(WIIU_WPAD_CHAN(wiiu_device), &ext);
if (ret != 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
"WiiU_JoystickOpen: WPAD device %d failed probe!",
WIIU_WPAD_CHAN(wiiu_device));
return -1;
}
switch (ext) {
case WPAD_EXT_CORE:
case WPAD_EXT_MPLUS:
default: {
joystick->nbuttons = SIZEOF_ARR(wiimote_button_map);
joystick->naxes = 0;
joystick->nhats = 0;
break;
}
case WPAD_EXT_NUNCHUK:
case WPAD_EXT_MPLUS_NUNCHUK: {
joystick->nbuttons = SIZEOF_ARR(wiimote_button_map);
joystick->naxes = 2;
joystick->nhats = 0;
break;
}
case WPAD_EXT_CLASSIC:
case WPAD_EXT_MPLUS_CLASSIC: {
joystick->nbuttons = SIZEOF_ARR(classic_button_map);
joystick->naxes = 4;
joystick->nhats = 0;
break;
}
case WPAD_EXT_PRO_CONTROLLER: {
joystick->nbuttons = SIZEOF_ARR(pro_button_map);
joystick->naxes = 4;
joystick->nhats = 0;
break;
}
}
break;
}
}
joystick->instance_id = device_index;
joystick->instance_id = WIIU_GetInstForIndex(device_index);
return 0;
}
@ -134,10 +327,9 @@ static int WIIU_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rum
*/
static void WIIU_JoystickUpdate(SDL_Joystick *joystick)
{
int16_t x1, y1, x2, y2;
/* Gamepad */
if (joystick->instance_id == 0) {
int16_t x1, y1, x2, y2;
if (joystick->instance_id == WIIU_GetInstForDevice(WIIU_DEVICE_GAMEPAD)) {
static uint16_t last_touch_x = 0;
static uint16_t last_touch_y = 0;
static uint16_t last_touched = 0;
@ -151,8 +343,14 @@ static void WIIU_JoystickUpdate(SDL_Joystick *joystick)
VPADReadError error;
VPADTouchData tpdata;
VPADRead(VPAD_CHAN_0, &vpad, 1, &error);
if (error != VPAD_READ_SUCCESS)
if (error == VPAD_READ_INVALID_CONTROLLER) {
/* Gamepad disconnected! */
SDL_PrivateJoystickRemoved(joystick->instance_id);
/* Unlink Gamepad, device_index, instance_id */
WIIU_RemoveDevice(WIIU_DEVICE_GAMEPAD);
} else if (error != VPAD_READ_SUCCESS) {
return;
}
/* touchscreen */
VPADGetTPCalibratedPoint(VPAD_CHAN_0, &tpdata, &vpad.tpNormal);
@ -209,6 +407,89 @@ static void WIIU_JoystickUpdate(SDL_Joystick *joystick)
for(int i = 0; i < joystick->nbuttons; i++)
if (vpad.release & vpad_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED);
} else if (
joystick->instance_id == WIIU_GetInstForDevice(WIIU_DEVICE_WPAD(0)) ||
joystick->instance_id == WIIU_GetInstForDevice(WIIU_DEVICE_WPAD(1)) ||
joystick->instance_id == WIIU_GetInstForDevice(WIIU_DEVICE_WPAD(2)) ||
joystick->instance_id == WIIU_GetInstForDevice(WIIU_DEVICE_WPAD(3))) {
int wiiu_device = WIIU_GetDeviceForInst(joystick->instance_id);
WPADExtensionType ext;
KPADStatus kpad;
int32_t err;
if (WPADProbe(WIIU_WPAD_CHAN(wiiu_device), &ext) != 0) {
/* Do nothing, we'll catch it in Detect() */
return;
}
KPADReadEx(WIIU_WPAD_CHAN(wiiu_device), &kpad, 1, &err);
if (err != KPAD_ERROR_OK) return;
switch (ext) {
case WPAD_EXT_CORE:
case WPAD_EXT_MPLUS:
default: {
for(int i = 0; i < joystick->nbuttons; i++)
if (kpad.trigger & wiimote_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_PRESSED);
for(int i = 0; i < joystick->nbuttons; i++)
if (kpad.release & wiimote_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED);
break;
}
case WPAD_EXT_NUNCHUK:
case WPAD_EXT_MPLUS_NUNCHUK: {
for(int i = 0; i < joystick->nbuttons; i++)
if (kpad.trigger & wiimote_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_PRESSED);
for(int i = 0; i < joystick->nbuttons; i++)
if (kpad.release & wiimote_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED);
x1 = (int16_t) ((kpad.nunchuck.stick.x) * 0x7ff0);
y1 = (int16_t) -((kpad.nunchuck.stick.y) * 0x7ff0);
SDL_PrivateJoystickAxis(joystick, 0, x1);
SDL_PrivateJoystickAxis(joystick, 1, y1);
break;
}
case WPAD_EXT_CLASSIC:
case WPAD_EXT_MPLUS_CLASSIC: {
for(int i = 0; i < joystick->nbuttons; i++)
if (kpad.classic.trigger & classic_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_PRESSED);
for(int i = 0; i < joystick->nbuttons; i++)
if (kpad.classic.release & classic_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED);
x1 = (int16_t) ((kpad.classic.leftStick.x) * 0x7ff0);
y1 = (int16_t) -((kpad.classic.leftStick.y) * 0x7ff0);
x2 = (int16_t) ((kpad.classic.rightStick.x) * 0x7ff0);
y2 = (int16_t) -((kpad.classic.rightStick.y) * 0x7ff0);
SDL_PrivateJoystickAxis(joystick, 0, x1);
SDL_PrivateJoystickAxis(joystick, 1, y1);
SDL_PrivateJoystickAxis(joystick, 2, x2);
SDL_PrivateJoystickAxis(joystick, 3, y2);
break;
}
case WPAD_EXT_PRO_CONTROLLER: {
for(int i = 0; i < joystick->nbuttons; i++)
if (kpad.pro.trigger & pro_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_PRESSED);
for(int i = 0; i < joystick->nbuttons; i++)
if (kpad.pro.release & pro_button_map[i])
SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED);
x1 = (int16_t) ((kpad.pro.leftStick.x) * 0x7ff0);
y1 = (int16_t) -((kpad.pro.leftStick.y) * 0x7ff0);
x2 = (int16_t) ((kpad.pro.rightStick.x) * 0x7ff0);
y2 = (int16_t) -((kpad.pro.rightStick.y) * 0x7ff0);
SDL_PrivateJoystickAxis(joystick, 0, x1);
SDL_PrivateJoystickAxis(joystick, 1, y1);
SDL_PrivateJoystickAxis(joystick, 2, x2);
SDL_PrivateJoystickAxis(joystick, 3, y2);
break;
}
}
}
}

View File

@ -0,0 +1,112 @@
/*
Simple DirectMedia Layer
Copyright (C) 2018 Roberto Van Eeden <r.r.qwertyuiop.r.r@gmail.com>
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.
*/
#include <padscore/wpad.h>
#define WIIU_DEVICE_INVALID (-1)
#define WIIU_DEVICE_GAMEPAD (0)
#define WIIU_DEVICE_WPAD(x) (x + 1)
#define WIIU_WPAD_CHAN(device) (device - 1)
#define WIIU_NUM_WPADS (4)
#define MAX_CONTROLLERS WIIU_DEVICE_WPAD(WIIU_NUM_WPADS)
#define SIZEOF_ARR(arr) (sizeof(arr) / sizeof(arr[0]))
static VPADButtons vpad_button_map[] =
{
VPAD_BUTTON_A, VPAD_BUTTON_B, VPAD_BUTTON_X, VPAD_BUTTON_Y,
VPAD_BUTTON_STICK_L, VPAD_BUTTON_STICK_R,
VPAD_BUTTON_L, VPAD_BUTTON_R,
VPAD_BUTTON_ZL, VPAD_BUTTON_ZR,
VPAD_BUTTON_PLUS, VPAD_BUTTON_MINUS,
VPAD_BUTTON_LEFT, VPAD_BUTTON_UP, VPAD_BUTTON_RIGHT, VPAD_BUTTON_DOWN,
VPAD_STICK_L_EMULATION_LEFT, VPAD_STICK_L_EMULATION_UP, VPAD_STICK_L_EMULATION_RIGHT, VPAD_STICK_L_EMULATION_DOWN,
VPAD_STICK_R_EMULATION_LEFT, VPAD_STICK_R_EMULATION_UP, VPAD_STICK_R_EMULATION_RIGHT, VPAD_STICK_R_EMULATION_DOWN
};
static WPADButton wiimote_button_map[] = {
WPAD_BUTTON_A, WPAD_BUTTON_B, WPAD_BUTTON_Z, WPAD_BUTTON_C,
0, 0,
WPAD_BUTTON_1, WPAD_BUTTON_2,
0, 0,
WPAD_BUTTON_PLUS, WPAD_BUTTON_MINUS,
WPAD_BUTTON_LEFT, WPAD_BUTTON_UP, WPAD_BUTTON_RIGHT, WPAD_BUTTON_DOWN,
};
static WPADClassicButton classic_button_map[] = {
WPAD_CLASSIC_BUTTON_A, WPAD_CLASSIC_BUTTON_B, WPAD_CLASSIC_BUTTON_X,
WPAD_CLASSIC_BUTTON_Y,
0, 0,
WPAD_CLASSIC_BUTTON_L, WPAD_CLASSIC_BUTTON_R,
WPAD_CLASSIC_BUTTON_ZL, WPAD_CLASSIC_BUTTON_ZR,
WPAD_CLASSIC_BUTTON_PLUS, WPAD_CLASSIC_BUTTON_MINUS,
WPAD_CLASSIC_BUTTON_LEFT, WPAD_CLASSIC_BUTTON_UP, WPAD_CLASSIC_BUTTON_RIGHT,
WPAD_CLASSIC_BUTTON_DOWN,
};
static WPADProButton pro_button_map[] = {
WPAD_PRO_BUTTON_A, WPAD_PRO_BUTTON_B, WPAD_PRO_BUTTON_X, WPAD_PRO_BUTTON_Y,
WPAD_PRO_BUTTON_STICK_L, WPAD_PRO_BUTTON_STICK_R,
WPAD_PRO_TRIGGER_L, WPAD_PRO_TRIGGER_R,
WPAD_PRO_TRIGGER_ZL, WPAD_PRO_TRIGGER_ZR,
WPAD_PRO_BUTTON_PLUS, WPAD_PRO_BUTTON_MINUS,
WPAD_PRO_BUTTON_LEFT, WPAD_PRO_BUTTON_UP,
WPAD_PRO_BUTTON_RIGHT, WPAD_PRO_BUTTON_DOWN,
WPAD_PRO_STICK_L_EMULATION_LEFT, WPAD_PRO_STICK_L_EMULATION_UP,
WPAD_PRO_STICK_L_EMULATION_RIGHT, WPAD_PRO_STICK_L_EMULATION_DOWN,
WPAD_PRO_STICK_R_EMULATION_LEFT, WPAD_PRO_STICK_R_EMULATION_UP,
WPAD_PRO_STICK_R_EMULATION_RIGHT, WPAD_PRO_STICK_R_EMULATION_DOWN
};
static int WIIU_JoystickInit(void);
static int WIIU_JoystickGetCount(void);
static void WIIU_JoystickDetect(void);
static const char *WIIU_JoystickGetDeviceName(int device_index);
static int WIIU_JoystickGetDevicePlayerIndex(int device_index);
static SDL_JoystickGUID WIIU_JoystickGetDeviceGUID(int device_index);
static SDL_JoystickID WIIU_JoystickGetDeviceInstanceID(int device_index);
static int WIIU_JoystickOpen(SDL_Joystick *joystick, int device_index);
static int WIIU_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
static void WIIU_JoystickUpdate(SDL_Joystick *joystick);
static void WIIU_JoystickClose(SDL_Joystick *joystick);
static void WIIU_JoystickQuit(void);
#define RETURN_WPAD_NAME(chan, ext) { \
switch (ext) { \
case WPAD_EXT_CORE: \
case WPAD_EXT_MPLUS: \
default: { \
return "Wii Remote #" #chan; \
} \
case WPAD_EXT_NUNCHUK: \
case WPAD_EXT_MPLUS_NUNCHUK: { \
return "Wii Remote #" #chan " and Nunchuk"; \
} \
case WPAD_EXT_CLASSIC: \
case WPAD_EXT_MPLUS_CLASSIC: { \
return "Wii Classic Controller #" #chan; \
} \
case WPAD_EXT_PRO_CONTROLLER: { \
return "WiiU Pro Controller #" #chan; \
} \
} \
}