From 0705288edd688dd403d33e9bab4634acff51403f Mon Sep 17 00:00:00 2001 From: cpasjuste Date: Mon, 11 Apr 2022 13:44:35 +0200 Subject: [PATCH] switch: handle single joycons --- src/joystick/switch/SDL_sysjoystick.c | 281 ++++++++++++++++---------- 1 file changed, 171 insertions(+), 110 deletions(-) diff --git a/src/joystick/switch/SDL_sysjoystick.c b/src/joystick/switch/SDL_sysjoystick.c index 6204371c2..b884d40ac 100644 --- a/src/joystick/switch/SDL_sysjoystick.c +++ b/src/joystick/switch/SDL_sysjoystick.c @@ -26,88 +26,152 @@ #include "SDL_events.h" #include "../SDL_sysjoystick.h" +#include "SDL_hints.h" #include #define JOYSTICK_COUNT 8 -typedef struct SWITCHJoystickState -{ +typedef struct SWITCHJoystickState { PadState pad; HidAnalogStickState sticks_old[2]; HidVibrationDeviceHandle vibrationDeviceHandles; HidVibrationValue vibrationValues; + HidNpadButton *pad_mapping; + u32 pad_type; + u32 pad_type_prev; + HidNpadStyleTag pad_style; + HidNpadStyleTag pad_style_prev; } SWITCHJoystickState; static SWITCHJoystickState state[JOYSTICK_COUNT]; -static const HidNpadButton pad_mapping[] = { - HidNpadButton_A, HidNpadButton_B, HidNpadButton_X, HidNpadButton_Y, - HidNpadButton_StickL, HidNpadButton_StickR, - HidNpadButton_L, HidNpadButton_R, - HidNpadButton_ZL, HidNpadButton_ZR, - HidNpadButton_Plus, HidNpadButton_Minus, - HidNpadButton_Left, HidNpadButton_Up, HidNpadButton_Right, HidNpadButton_Down, - HidNpadButton_StickLLeft, HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, - HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, HidNpadButton_StickRDown, - HidNpadButton_LeftSL, HidNpadButton_LeftSR, HidNpadButton_RightSL, HidNpadButton_RightSR +static const HidNpadButton pad_mapping_default[] = { + HidNpadButton_A, HidNpadButton_B, HidNpadButton_X, HidNpadButton_Y, + HidNpadButton_StickL, HidNpadButton_StickR, + HidNpadButton_L, HidNpadButton_R, + HidNpadButton_ZL, HidNpadButton_ZR, + HidNpadButton_Plus, HidNpadButton_Minus, + HidNpadButton_Left, HidNpadButton_Up, HidNpadButton_Right, HidNpadButton_Down, + HidNpadButton_StickLLeft, HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, + HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, HidNpadButton_StickRDown, + HidNpadButton_LeftSL, HidNpadButton_LeftSR, HidNpadButton_RightSL, HidNpadButton_RightSR }; +// left single joycon mapping (start = left stick, select = minus) +static const HidNpadButton pad_mapping_left_joy[] = { + HidNpadButton_Down, HidNpadButton_Left, HidNpadButton_Right, HidNpadButton_Up, + BIT(31), BIT(31), + BIT(31), BIT(31), + HidNpadButton_LeftSL, HidNpadButton_LeftSR, + HidNpadButton_StickL, HidNpadButton_Minus, + HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, HidNpadButton_StickLLeft, + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31) +}; + +// right single joycon mapping (start = right stick, select = plus) +static const HidNpadButton pad_mapping_right_joy[] = { + HidNpadButton_X, HidNpadButton_A, HidNpadButton_Y, HidNpadButton_B, + BIT(31), BIT(31), + BIT(31), BIT(31), + HidNpadButton_RightSL, HidNpadButton_RightSR, + HidNpadButton_StickR, HidNpadButton_Plus, + HidNpadButton_StickRDown, HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31) +}; + +static void SWITCH_ShowControllerSupport(void) { + HidLaControllerSupportResultInfo info; + HidLaControllerSupportArg args; + hidLaCreateControllerSupportArg(&args); + args.hdr.player_count_max = JOYSTICK_COUNT; + hidLaShowControllerSupportForSystem(&info, &args, false); + + // update pads states + for (int i = 0; i < JOYSTICK_COUNT; i++) { + SDL_Joystick *joy = SDL_JoystickFromInstanceID(i); + if (joy) { + padUpdate(&state[i].pad); + state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) i); + state[i].pad_style = state[i].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) i); + // update pad mapping + if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[i].pad_type & HidDeviceTypeBits_JoyLeft)) { + state[i].pad_mapping = (HidNpadButton *) &pad_mapping_left_joy; + } else if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[i].pad_type & HidDeviceTypeBits_JoyRight)) { + state[i].pad_mapping = (HidNpadButton *) &pad_mapping_right_joy; + } else { + state[i].pad_mapping = (HidNpadButton *) &pad_mapping_default; + } + // update vibration stuff ? + hidInitializeVibrationDevices(&state[i].vibrationDeviceHandles, 1, + HidNpadIdType_No1 + i, state[i].pad_style); + // reset sdl joysticks states + SDL_PrivateJoystickAxis(joy, 0, 0); + SDL_PrivateJoystickAxis(joy, 1, 0); + SDL_PrivateJoystickAxis(joy, 2, 0); + SDL_PrivateJoystickAxis(joy, 3, 0); + state[i].pad.buttons_cur = 0; + state[i].pad.buttons_old = 0; + for (int j = 0; j < joy->nbuttons; j++) { + SDL_PrivateJoystickButton(joy, j, SDL_RELEASED); + } + } + } +} + /* Function to scan the system for joysticks. * It should return 0, or -1 on an unrecoverable fatal error. */ -static int -SWITCH_JoystickInit(void) -{ +static int SWITCH_JoystickInit(void) { padConfigureInput(JOYSTICK_COUNT, HidNpadStyleSet_NpadStandard); // initialize first pad to defaults padInitializeDefault(&state[0].pad); padUpdate(&state[0].pad); + state[0].pad_mapping = (HidNpadButton *) &pad_mapping_default; + state[0].pad_type = state[0].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) 0); + state[0].pad_style = state[0].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) 0); // initialize pad and vibrations for pad 1 to 7 for (int i = 1; i < JOYSTICK_COUNT; i++) { padInitialize(&state[i].pad, HidNpadIdType_No1 + i); padUpdate(&state[i].pad); - hidInitializeVibrationDevices(&state[i].vibrationDeviceHandles,1, - HidNpadIdType_No1 + i, padGetStyleSet(&state[i].pad)); + state[i].pad_mapping = (HidNpadButton *) &pad_mapping_default; + state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) i); + state[i].pad_style = state[i].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) i); + hidInitializeVibrationDevices(&state[i].vibrationDeviceHandles, 1, + HidNpadIdType_No1 + i, state[i].pad_style); } return JOYSTICK_COUNT; } -static int -SWITCH_JoystickGetCount(void) -{ +static int SWITCH_JoystickGetCount(void) { return JOYSTICK_COUNT; } -static void -SWITCH_JoystickDetect(void) -{ +static void SWITCH_JoystickDetect(void) { } /* Function to get the device-dependent name of a joystick */ -static const char * -SWITCH_JoystickGetDeviceName(int device_index) -{ +static const char *SWITCH_JoystickGetDeviceName(int device_index) { return "Switch Controller"; } -static int -SWITCH_JoystickGetDevicePlayerIndex(int device_index) -{ +static int SWITCH_JoystickGetDevicePlayerIndex(int device_index) { return -1; } -static void -SWITCH_JoystickSetDevicePlayerIndex(int device_index, int player_index) -{ +static void SWITCH_JoystickSetDevicePlayerIndex(int device_index, int player_index) { } -static SDL_JoystickGUID -SWITCH_JoystickGetDeviceGUID(int device_index) -{ +static SDL_JoystickGUID SWITCH_JoystickGetDeviceGUID(int device_index) { SDL_JoystickGUID guid; /* the GUID is just the first 16 chars of the name for now */ const char *name = SWITCH_JoystickGetDeviceName(device_index); @@ -117,9 +181,7 @@ SWITCH_JoystickGetDeviceGUID(int device_index) } /* Function to perform the mapping from device index to the instance id for this index */ -static SDL_JoystickID -SWITCH_JoystickGetDeviceInstanceID(int device_index) -{ +static SDL_JoystickID SWITCH_JoystickGetDeviceInstanceID(int device_index) { return device_index; } @@ -128,10 +190,8 @@ SWITCH_JoystickGetDeviceInstanceID(int device_index) This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ -static int -SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) -{ - joystick->nbuttons = sizeof(pad_mapping) / sizeof(*pad_mapping); +static int SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) { + joystick->nbuttons = sizeof(pad_mapping_default) / sizeof(*pad_mapping_default); joystick->naxes = 4; joystick->nhats = 0; joystick->instance_id = device_index; @@ -139,9 +199,7 @@ SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) return 0; } -static int -SWITCH_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) -{ +static int SWITCH_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { int id = joystick->instance_id; state[id].vibrationValues.amp_low = @@ -156,27 +214,19 @@ SWITCH_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint return 0; } -static int -SWITCH_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left, Uint16 right) -{ +static int SWITCH_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right) { return SDL_Unsupported(); } -static SDL_bool -SWITCH_JoystickHasLED(SDL_Joystick * joystick) -{ +static SDL_bool SWITCH_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } -static int -SWITCH_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) -{ +static int SWITCH_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) { return 0; } -static int -SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) -{ +static int SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); } @@ -185,82 +235,93 @@ SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) * but instead should call SDL_PrivateJoystick*() to deliver events * and update joystick device state. */ -static void -SWITCH_JoystickUpdate(SDL_Joystick *joystick) -{ +static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) { u64 diff; int index = (int) SDL_JoystickInstanceID(joystick); - if (index > JOYSTICK_COUNT || SDL_IsTextInputActive()) { + if (index >= JOYSTICK_COUNT || SDL_IsTextInputActive()) { return; } padUpdate(&state[index].pad); + if (!padIsConnected(&state[index].pad)) { + return; + } - // Axes (left) - if (state[index].sticks_old[0].x != state[index].pad.sticks[0].x) { - SDL_PrivateJoystickAxis(joystick, 0, (Sint16) state[index].pad.sticks[0].x); - state[index].sticks_old[0].x = state[index].pad.sticks[0].x; + // update pad type and style, open controller support applet if needed + state[index].pad_type = hidGetNpadDeviceType((HidNpadIdType) index); + state[index].pad_style = hidGetNpadStyleSet((HidNpadIdType) index); + if (state[index].pad_type != state[index].pad_type_prev + || state[index].pad_style != state[index].pad_style_prev) { + SWITCH_ShowControllerSupport(); + return; } - if (state[index].sticks_old[0].y != state[index].pad.sticks[0].y) { - SDL_PrivateJoystickAxis(joystick, 1, (Sint16) -state[index].pad.sticks[0].y); - state[index].sticks_old[0].y = -state[index].pad.sticks[0].y; - } - state[index].sticks_old[0] = padGetStickPos(&state[index].pad, 0); - // Axes (right) - if (state[index].sticks_old[1].x != state[index].pad.sticks[1].x) { - SDL_PrivateJoystickAxis(joystick, 2, (Sint16) state[index].pad.sticks[1].x); - state[index].sticks_old[1].x = state[index].pad.sticks[1].x; - } - if (state[index].sticks_old[1].y != state[index].pad.sticks[1].y) { - SDL_PrivateJoystickAxis(joystick, 3, (Sint16) -state[index].pad.sticks[1].y); - state[index].sticks_old[1].y = -state[index].pad.sticks[1].y; - } - state[index].sticks_old[1] = padGetStickPos(&state[index].pad, 1); - // Buttons + // only handle axes in non-single joycon mode + if (state[index].pad_style & HidNpadStyleTag_NpadJoyDual + || (state[index].pad_type != HidDeviceTypeBits_JoyLeft + && state[index].pad_type != HidDeviceTypeBits_JoyRight)) { + // axis left + if (state[index].sticks_old[0].x != state[index].pad.sticks[0].x) { + SDL_PrivateJoystickAxis(joystick, 0, (Sint16) state[index].pad.sticks[0].x); + state[index].sticks_old[0].x = state[index].pad.sticks[0].x; + } + if (state[index].sticks_old[0].y != state[index].pad.sticks[0].y) { + SDL_PrivateJoystickAxis(joystick, 1, (Sint16) - state[index].pad.sticks[0].y); + state[index].sticks_old[0].y = -state[index].pad.sticks[0].y; + } + state[index].sticks_old[0] = padGetStickPos(&state[index].pad, 0); + // axis right + if (state[index].sticks_old[1].x != state[index].pad.sticks[1].x) { + SDL_PrivateJoystickAxis(joystick, 2, (Sint16) state[index].pad.sticks[1].x); + state[index].sticks_old[1].x = state[index].pad.sticks[1].x; + } + if (state[index].sticks_old[1].y != state[index].pad.sticks[1].y) { + SDL_PrivateJoystickAxis(joystick, 3, (Sint16) - state[index].pad.sticks[1].y); + state[index].sticks_old[1].y = -state[index].pad.sticks[1].y; + } + state[index].sticks_old[1] = padGetStickPos(&state[index].pad, 1); + } + + // handle buttons diff = state[index].pad.buttons_old ^ state[index].pad.buttons_cur; if (diff) { for (int i = 0; i < joystick->nbuttons; i++) { - if (diff & pad_mapping[i]) { - SDL_PrivateJoystickButton(joystick, i, - state[index].pad.buttons_cur & pad_mapping[i] ? - SDL_PRESSED : SDL_RELEASED); + if (diff & state[index].pad_mapping[i]) { + SDL_PrivateJoystickButton( + joystick, i, + state[index].pad.buttons_cur & state[index].pad_mapping[i] ? + SDL_PRESSED : SDL_RELEASED); } } } } /* Function to close a joystick after use */ -static void -SWITCH_JoystickClose(SDL_Joystick *joystick) -{ +static void SWITCH_JoystickClose(SDL_Joystick *joystick) { } /* Function to perform any system-specific joystick related cleanup */ -static void -SWITCH_JoystickQuit(void) -{ +static void SWITCH_JoystickQuit(void) { } -SDL_JoystickDriver SDL_SWITCH_JoystickDriver = -{ - SWITCH_JoystickInit, - SWITCH_JoystickGetCount, - SWITCH_JoystickDetect, - SWITCH_JoystickGetDeviceName, - SWITCH_JoystickGetDevicePlayerIndex, - SWITCH_JoystickSetDevicePlayerIndex, - SWITCH_JoystickGetDeviceGUID, - SWITCH_JoystickGetDeviceInstanceID, - SWITCH_JoystickOpen, - SWITCH_JoystickRumble, - SWITCH_JoystickRumbleTriggers, - SWITCH_JoystickHasLED, - SWITCH_JoystickSetLED, - SWITCH_JoystickSetSensorsEnabled, - SWITCH_JoystickUpdate, - SWITCH_JoystickClose, - SWITCH_JoystickQuit, +SDL_JoystickDriver SDL_SWITCH_JoystickDriver = { + SWITCH_JoystickInit, + SWITCH_JoystickGetCount, + SWITCH_JoystickDetect, + SWITCH_JoystickGetDeviceName, + SWITCH_JoystickGetDevicePlayerIndex, + SWITCH_JoystickSetDevicePlayerIndex, + SWITCH_JoystickGetDeviceGUID, + SWITCH_JoystickGetDeviceInstanceID, + SWITCH_JoystickOpen, + SWITCH_JoystickRumble, + SWITCH_JoystickRumbleTriggers, + SWITCH_JoystickHasLED, + SWITCH_JoystickSetLED, + SWITCH_JoystickSetSensorsEnabled, + SWITCH_JoystickUpdate, + SWITCH_JoystickClose, + SWITCH_JoystickQuit, }; #endif /* SDL_JOYSTICK_SWITCH */