From 0eaa9070a2764fe3ea5b9ce86be9234717a76bb7 Mon Sep 17 00:00:00 2001 From: Ash Logan Date: Sun, 24 Mar 2019 21:07:14 +1100 Subject: [PATCH] joystick/wiiu: Add support for WPAD/KPAD controllers --- src/joystick/wiiu/SDL_wiiujoystick.c | 224 +++++++++++++++++++++++++-- src/joystick/wiiu/SDL_wiiujoystick.h | 91 +++++++++-- 2 files changed, 286 insertions(+), 29 deletions(-) diff --git a/src/joystick/wiiu/SDL_wiiujoystick.c b/src/joystick/wiiu/SDL_wiiujoystick.c index 8e65484cc..cf7bdbe53 100644 --- a/src/joystick/wiiu/SDL_wiiujoystick.c +++ b/src/joystick/wiiu/SDL_wiiujoystick.c @@ -25,6 +25,8 @@ #if SDL_JOYSTICK_WIIU #include +#include +#include #include #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; + } + } } } diff --git a/src/joystick/wiiu/SDL_wiiujoystick.h b/src/joystick/wiiu/SDL_wiiujoystick.h index a2ccebb0f..64fcf50e5 100644 --- a/src/joystick/wiiu/SDL_wiiujoystick.h +++ b/src/joystick/wiiu/SDL_wiiujoystick.h @@ -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 + +#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; \ + } \ + } \ +}