joystick/wiiu: Add support for WPAD/KPAD controllers

This commit is contained in:
Ash Logan 2019-03-24 21:07:14 +11:00
parent 776380a70f
commit 0eaa9070a2
2 changed files with 286 additions and 29 deletions

View File

@ -25,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"
@ -38,15 +40,11 @@
#include "SDL_wiiujoystick.h"
#define WIIU_DEVICE_INVALID (-1)
#define WIIU_DEVICE_GAMEPAD (0)
#define WIIU_DEVICE_WPAD(x) (x + 1)
#define MAX_CONTROLLERS WIIU_DEVICE_WPAD(4)
//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];
@ -62,14 +60,20 @@ static int WIIU_GetNextDeviceIndex() {
return WIIU_GetIndexForDevice(WIIU_DEVICE_INVALID);
}
static int WIIU_GetInstForIndex(int device_index) {
static SDL_JoystickID WIIU_GetInstForIndex(int device_index) {
if (device_index == -1) return -1;
return instanceMap[device_index];
}
static int WIIU_GetInstForDevice(int wiiu_device) {
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);
@ -92,6 +96,10 @@ static void WIIU_RemoveDevice(int wiiu_device) {
*/
static int WIIU_JoystickInit(void)
{
VPADInit();
KPADInit();
WPADEnableURCC(1);
for (int i = 0; i < MAX_CONTROLLERS; i++) {
deviceMap[i] = WIIU_DEVICE_INVALID;
instanceMap[i] = -1;
@ -151,14 +159,66 @@ static void WIIU_JoystickDetect(void)
}
}
}
/* 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 (WIIU_GetDeviceForIndex(device_index) == WIIU_DEVICE_GAMEPAD)
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";
}
@ -192,16 +252,64 @@ static SDL_JoystickID WIIU_JoystickGetDeviceInstanceID(int device_index)
*/
static int WIIU_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
/* Gamepad */
if (WIIU_GetDeviceForIndex(device_index) == WIIU_DEVICE_GAMEPAD) {
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 = WIIU_GetInstForIndex(device_index);
return 0;
}
@ -219,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 == WIIU_GetInstForDevice(WIIU_DEVICE_GAMEPAD)) {
int16_t x1, y1, x2, y2;
static uint16_t last_touch_x = 0;
static uint16_t last_touch_y = 0;
static uint16_t last_touched = 0;
@ -300,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

@ -11,24 +11,70 @@
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.
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.
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
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);
@ -43,3 +89,24 @@ static int WIIU_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rum
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; \
} \
} \
}