RetroArch/input/drivers_joypad/switch_joypad.c

472 lines
15 KiB
C
Raw Normal View History

2017-12-23 17:26:58 -08:00
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif
#include "../../config.def.h"
#ifdef HAVE_LIBNX
#include <switch.h>
#else
#include <libtransistor/nx.h>
#endif
2017-12-29 00:44:41 +01:00
#include "../configuration.h"
2017-12-23 17:26:58 -08:00
#include "../../tasks/tasks_internal.h"
#include "../../retroarch.h"
#include "../../command.h"
/* TODO/FIXME - weird header include */
2017-12-23 17:26:58 -08:00
#include "string.h"
/* TODO/FIXME - global referenced outside */
2017-12-23 17:26:58 -08:00
extern uint64_t lifecycle_state;
/* TODO/FIXME - static globals */
2021-03-12 09:11:43 +00:00
static uint16_t button_state[DEFAULT_MAX_PADS];
static int16_t analog_state[DEFAULT_MAX_PADS][2][2];
2019-03-05 21:13:02 -08:00
#ifdef HAVE_LIBNX
2021-03-12 09:11:43 +00:00
static PadState pad_states[DEFAULT_MAX_PADS];
2021-03-11 18:00:43 +00:00
static HidVibrationDeviceHandle vibration_handles[DEFAULT_MAX_PADS][2];
static HidVibrationDeviceHandle vibration_handleheld[2];
static HidVibrationValue vibration_values[DEFAULT_MAX_PADS][2];
2019-03-05 21:13:02 -08:00
static HidVibrationValue vibration_stop;
2019-07-23 13:59:51 +02:00
static int previous_handheld = -1;
/* 1 = handheld, 0 = docked, -1 = first use */
static uint previous_split_joycon_setting[MAX_USERS] = { 0 };
2019-03-05 21:13:02 -08:00
#endif
2017-12-29 00:44:41 +01:00
static const char *switch_joypad_name(unsigned pad)
{
return "Switch Controller";
2017-12-23 17:26:58 -08:00
}
2017-12-29 00:44:41 +01:00
static void switch_joypad_autodetect_add(unsigned autoconf_pad)
{
input_autoconfigure_connect(
2017-12-29 00:44:41 +01:00
switch_joypad_name(autoconf_pad), /* name */
NULL, /* display name */
switch_joypad.ident, /* driver */
autoconf_pad, /* idx */
0, /* vid */
0); /* pid */
2017-12-23 17:26:58 -08:00
}
static void *switch_joypad_init(void *data)
2017-12-29 00:44:41 +01:00
{
#ifdef HAVE_LIBNX
unsigned i;
hidSetNpadJoyHoldType(HidNpadJoyHoldType_Horizontal);
2021-03-12 09:11:43 +00:00
padConfigureInput(DEFAULT_MAX_PADS, HidNpadStyleSet_NpadStandard);
2019-03-05 21:13:02 -08:00
2019-07-16 14:34:37 +02:00
/* Switch like stop behavior with muted band channels
* and frequencies set to default. */
2019-03-05 21:13:02 -08:00
vibration_stop.amp_low = 0.0f;
vibration_stop.freq_low = 160.0f;
vibration_stop.amp_high = 0.0f;
vibration_stop.freq_high = 320.0f;
for (i = 0; i < DEFAULT_MAX_PADS; i++)
2019-03-05 21:13:02 -08:00
{
2023-02-23 13:15:14 +01:00
if (i == 0)
2021-03-12 09:11:43 +00:00
padInitializeDefault(&pad_states[0]);
2021-06-28 17:37:22 +02:00
else
2021-03-12 09:11:43 +00:00
padInitialize(&pad_states[i], i);
2021-06-28 17:37:22 +02:00
2021-03-12 09:11:43 +00:00
padUpdate(&pad_states[i]);
switch_joypad_autodetect_add(i);
2019-07-23 13:59:51 +02:00
hidInitializeVibrationDevices(
vibration_handles[i], 2, i,
2021-03-11 18:00:43 +00:00
HidNpadStyleTag_NpadHandheld | HidNpadStyleTag_NpadJoyDual);
2019-07-23 13:59:51 +02:00
memcpy(&vibration_values[i][0],
&vibration_stop, sizeof(HidVibrationValue));
memcpy(&vibration_values[i][1],
&vibration_stop, sizeof(HidVibrationValue));
2019-03-05 21:13:02 -08:00
}
2019-07-23 13:59:51 +02:00
hidInitializeVibrationDevices(vibration_handleheld,
2021-03-11 18:00:43 +00:00
2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld | HidNpadStyleTag_NpadJoyDual);
#else
2017-12-29 00:44:41 +01:00
hid_init();
switch_joypad_autodetect_add(0);
switch_joypad_autodetect_add(1);
#endif
2017-12-29 00:44:41 +01:00
return (void*)-1;
2017-12-23 17:26:58 -08:00
}
static int32_t switch_joypad_button(unsigned port_num, uint16_t joykey)
2017-12-29 00:44:41 +01:00
{
if (port_num >= DEFAULT_MAX_PADS)
return 0;
2021-03-12 09:11:43 +00:00
return (button_state[port_num] & (1 << joykey));
2017-12-23 17:26:58 -08:00
}
2018-04-08 20:21:12 +02:00
static void switch_joypad_get_buttons(unsigned port_num, input_bits_t *state)
2017-12-29 00:44:41 +01:00
{
if (port_num < DEFAULT_MAX_PADS)
2017-12-29 00:44:41 +01:00
{
2021-03-12 09:11:43 +00:00
BITS_COPY16_PTR(state, button_state[port_num]);
2017-12-29 00:44:41 +01:00
}
else
{
BIT256_CLEAR_ALL_PTR(state);
}
2017-12-23 17:26:58 -08:00
}
static int16_t switch_joypad_axis_state(unsigned port, uint32_t joyaxis)
2017-12-29 00:44:41 +01:00
{
2019-07-16 14:34:37 +02:00
if (AXIS_NEG_GET(joyaxis) < 4)
2017-12-29 00:44:41 +01:00
{
int16_t val = 0;
int16_t axis = AXIS_NEG_GET(joyaxis);
switch (axis)
{
case 0:
case 1:
val = analog_state[port][0][axis];
break;
case 2:
case 3:
val = analog_state[port][1][axis - 2];
break;
}
if (val < 0)
return val;
2017-12-29 00:44:41 +01:00
}
2019-07-16 14:34:37 +02:00
else if (AXIS_POS_GET(joyaxis) < 4)
2017-12-29 00:44:41 +01:00
{
int16_t val = 0;
int16_t axis = AXIS_POS_GET(joyaxis);
switch (axis)
{
case 0:
case 1:
val = analog_state[port][0][axis];
break;
case 2:
case 3:
val = analog_state[port][1][axis - 2];
break;
}
if (val > 0)
return val;
2017-12-29 00:44:41 +01:00
}
return 0;
2017-12-23 17:26:58 -08:00
}
static int16_t switch_joypad_axis(unsigned port, uint32_t joyaxis)
{
if (port >= DEFAULT_MAX_PADS)
return 0;
return switch_joypad_axis_state(port, joyaxis);
}
static int16_t switch_joypad_state(
rarch_joypad_info_t *joypad_info,
const struct retro_keybind *binds,
unsigned port)
{
unsigned i;
int16_t ret = 0;
2020-07-29 05:31:23 +02:00
uint16_t port_idx = joypad_info->joy_idx;
2020-07-29 05:31:23 +02:00
if (port_idx >= DEFAULT_MAX_PADS)
return 0;
for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
{
/* Auto-binds are per joypad, not per user. */
const uint64_t joykey = (binds[i].joykey != NO_BTN)
? binds[i].joykey : joypad_info->auto_binds[i].joykey;
const uint32_t joyaxis = (binds[i].joyaxis != AXIS_NONE)
? binds[i].joyaxis : joypad_info->auto_binds[i].joyaxis;
if (
(uint16_t)joykey != NO_BTN
2021-03-12 09:11:43 +00:00
&& (button_state[port_idx] & (1 << (uint16_t)joykey))
)
ret |= ( 1 << i);
else if (joyaxis != AXIS_NONE &&
2020-07-29 05:31:23 +02:00
((float)abs(switch_joypad_axis_state(port_idx, joyaxis))
/ 0x8000) > joypad_info->axis_threshold)
ret |= (1 << i);
}
return ret;
}
2017-12-29 00:44:41 +01:00
static bool switch_joypad_query_pad(unsigned pad)
{
2021-03-12 09:11:43 +00:00
return pad < DEFAULT_MAX_PADS && button_state[pad];
2017-12-23 17:26:58 -08:00
}
2017-12-29 00:44:41 +01:00
static void switch_joypad_destroy(void)
{
2019-03-05 21:13:02 -08:00
#ifdef HAVE_LIBNX
unsigned i;
2019-07-23 13:59:51 +02:00
previous_handheld = -1;
for (i = 0; i < MAX_USERS; i++)
previous_split_joycon_setting[i] = 0;
2019-07-23 13:59:51 +02:00
for (i = 0; i < DEFAULT_MAX_PADS; i++)
2019-03-05 21:13:02 -08:00
{
2019-07-16 14:34:37 +02:00
memcpy(&vibration_values[i][0],
&vibration_stop, sizeof(HidVibrationValue));
memcpy(&vibration_values[i][1],
&vibration_stop, sizeof(HidVibrationValue));
2019-03-05 21:13:02 -08:00
hidSendVibrationValues(vibration_handles[i], vibration_values[i], 2);
}
hidSendVibrationValues(vibration_handleheld, vibration_values[0], 2);
#else
2017-12-29 00:44:41 +01:00
hid_finalize();
#endif
2017-12-23 17:26:58 -08:00
}
#ifdef HAVE_LIBNX
static void switch_joypad_poll(void)
{
int i, handheld;
settings_t *settings = config_get_ptr();
for(i = 0; i < DEFAULT_MAX_PADS; i++)
padUpdate(&pad_states[i]);
2021-03-12 09:11:43 +00:00
handheld = padIsHandheld(&pad_states[0]);
if (previous_handheld == -1)
{
/* First call of this function, apply joycon settings
* according to preferences, init variables */
if (!handheld)
{
for (i = 0; i < MAX_USERS; i += 2)
{
2020-02-23 06:05:23 +01:00
unsigned input_split_joycon =
settings->uints.input_split_joycon[i];
if (input_split_joycon)
{
hidSetNpadJoyAssignmentModeSingleByDefault(i);
hidSetNpadJoyAssignmentModeSingleByDefault(i + 1);
}
2020-02-23 06:05:23 +01:00
else if (!input_split_joycon)
{
hidSetNpadJoyAssignmentModeDual(i);
hidSetNpadJoyAssignmentModeDual(i + 1);
hidMergeSingleJoyAsDualJoy(i, i + 1);
}
}
}
previous_handheld = handheld;
for (i = 0; i < MAX_USERS; i += 2)
previous_split_joycon_setting[i] = settings->uints.input_split_joycon[i];
}
if (!handheld && previous_handheld)
{
/* switching out of handheld, so make sure
* joycons are correctly split. */
for (i = 0; i < MAX_USERS; i += 2)
{
2020-02-23 06:05:23 +01:00
unsigned input_split_joycon = settings->uints.input_split_joycon[i];
/* CONTROLLER_PLAYER_X, X == i++ */
2020-02-23 06:05:23 +01:00
if (input_split_joycon)
{
hidSetNpadJoyAssignmentModeSingleByDefault(i);
hidSetNpadJoyAssignmentModeSingleByDefault(i + 1);
}
else
{
hidSetNpadJoyAssignmentModeDual(i);
hidSetNpadJoyAssignmentModeDual(i + 1);
hidMergeSingleJoyAsDualJoy(i, i + 1);
}
}
}
else if (!handheld)
{
/* split or join joycons every time the user changes a setting */
for (i = 0; i < MAX_USERS; i += 2)
{
2020-02-23 06:05:23 +01:00
unsigned input_split_joycon = settings->uints.input_split_joycon[i];
if (input_split_joycon
&& !previous_split_joycon_setting[i])
{
hidSetNpadJoyAssignmentModeSingleByDefault(i);
hidSetNpadJoyAssignmentModeSingleByDefault(i + 1);
}
2020-02-23 06:05:23 +01:00
else if (!input_split_joycon
&& previous_split_joycon_setting[i])
{
hidSetNpadJoyAssignmentModeDual(i);
hidSetNpadJoyAssignmentModeDual(i + 1);
hidMergeSingleJoyAsDualJoy(i, i + 1);
}
}
}
for (i = 0; i < MAX_USERS; i += 2)
previous_split_joycon_setting[i] = settings->uints.input_split_joycon[i];
2021-09-23 13:38:52 +02:00
previous_handheld = handheld;
2019-07-23 13:59:51 +02:00
for (i = 0; i < DEFAULT_MAX_PADS; i++)
{
2021-03-12 09:11:43 +00:00
HidAnalogStickState stick_left_state = padGetStickPos(&pad_states[i], 0);
HidAnalogStickState stick_right_state = padGetStickPos(&pad_states[i], 1);
2021-07-29 12:18:11 +08:00
unsigned input_split_joycon = settings->uints.input_split_joycon[i];
int pad_button = padGetButtons(&pad_states[i]);
if (input_split_joycon && !handheld) {
2021-09-23 13:38:52 +02:00
button_state[i] = 0;
2021-07-29 12:18:11 +08:00
if (hidGetNpadDeviceType((HidNpadIdType)i) & HidDeviceTypeBits_JoyLeft) {
if (pad_button & HidNpadButton_Left)
2021-09-23 13:38:52 +02:00
button_state[i] |= (uint16_t)HidNpadButton_B;
if (pad_button & HidNpadButton_Up)
button_state[i] |= (uint16_t)HidNpadButton_Y;
if (pad_button & HidNpadButton_Right)
button_state[i] |= (uint16_t)HidNpadButton_X;
if (pad_button & HidNpadButton_Down)
button_state[i] |= (uint16_t)HidNpadButton_A;
if (pad_button & HidNpadButton_LeftSL)
button_state[i] |= (uint16_t)HidNpadButton_L;
if (pad_button & HidNpadButton_LeftSR)
button_state[i] |= (uint16_t)HidNpadButton_R;
if (pad_button & HidNpadButton_StickL)
button_state[i] |= (uint16_t)HidNpadButton_StickL;
if (pad_button & HidNpadButton_Minus)
button_state[i] |= (uint16_t)HidNpadButton_Plus;
2021-09-23 13:38:52 +02:00
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_X] = -stick_left_state.y;
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_Y] = -stick_left_state.x;
} else if (hidGetNpadDeviceType((HidNpadIdType)i) & HidDeviceTypeBits_JoyRight) {
2021-07-29 12:18:11 +08:00
if (pad_button & HidNpadButton_A)
2021-09-23 13:38:52 +02:00
button_state[i] |= (uint16_t)HidNpadButton_B;
if (pad_button & HidNpadButton_B)
button_state[i] |= (uint16_t)HidNpadButton_Y;
if (pad_button & HidNpadButton_X)
button_state[i] |= (uint16_t)HidNpadButton_A;
if (pad_button & HidNpadButton_Y)
button_state[i] |= (uint16_t)HidNpadButton_X;
if (pad_button & HidNpadButton_RightSL)
button_state[i] |= (uint16_t)HidNpadButton_L;
if (pad_button & HidNpadButton_RightSR)
button_state[i] |= (uint16_t)HidNpadButton_R;
if (pad_button & HidNpadButton_StickR)
button_state[i] |= (uint16_t)HidNpadButton_StickL;
if (pad_button & HidNpadButton_Plus)
button_state[i] |= (uint16_t)HidNpadButton_Plus;
2021-09-23 13:38:52 +02:00
/* Throw JoyRight state into retro left analog */
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_X] = stick_right_state.y;
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_Y] = stick_right_state.x;
} else {
/* Handle other types via Default Input Handling */
goto lblDefaultInputHandling;
2021-07-29 12:18:11 +08:00
}
}
else
{
2021-09-23 13:38:52 +02:00
/* Default Input Handling */
lblDefaultInputHandling:
2021-07-29 12:18:11 +08:00
button_state[i] = pad_button;
2021-09-23 13:38:52 +02:00
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_X] = stick_left_state.x;
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_Y] = -stick_left_state.y;
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X] = stick_right_state.x;
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y] = -stick_right_state.y;
2021-07-29 12:18:11 +08:00
}
}
}
#else
static void switch_joypad_poll(void)
{
int16_t lsx, lsy, rsx, rsy;
2018-01-05 16:31:18 -05:00
hid_controller_t *controllers = hid_get_shared_memory()->controllers;
hid_controller_t *cont = &controllers[0];
hid_controller_state_entry_t ent = cont->main.entries[cont->main.latest_idx];
hid_controller_state_entry_t ent8 = (cont+8)->main.entries[(cont+8)->main.latest_idx];
2021-03-12 09:11:43 +00:00
button_state[0] = ent.button_state | ent8.button_state;
2018-05-24 00:18:38 -07:00
lsx = ent.left_stick_x;
lsy = ent.left_stick_y;
rsx = ent.right_stick_x;
rsy = ent.right_stick_y;
if (ent8.left_stick_x != 0 || ent8.left_stick_y != 0)
{
/* handheld overrides player 1 */
2021-03-12 09:11:43 +00:00
lsx = ent8.left_stick_x;
lsy = ent8.left_stick_y;
2018-05-24 00:18:38 -07:00
}
if (ent8.right_stick_x != 0 || ent8.right_stick_y != 0)
{
/* handheld overrides player 1 */
2021-03-12 09:11:43 +00:00
rsx = ent8.right_stick_x;
rsy = ent8.right_stick_y;
2018-05-24 00:18:38 -07:00
}
2019-02-03 15:49:35 -08:00
2019-07-23 13:59:51 +02:00
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_LEFT]
[RETRO_DEVICE_ID_ANALOG_X] = lsx;
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_LEFT]
[RETRO_DEVICE_ID_ANALOG_Y] = -lsy;
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT]
[RETRO_DEVICE_ID_ANALOG_X] = rsx;
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT]
[RETRO_DEVICE_ID_ANALOG_Y] = -rsy;
2017-12-23 17:26:58 -08:00
}
#endif
2017-12-23 17:26:58 -08:00
2019-03-05 21:13:02 -08:00
#ifdef HAVE_LIBNX
bool switch_joypad_set_rumble(unsigned pad,
enum retro_rumble_effect type, uint16_t strength)
{
2021-03-11 18:00:43 +00:00
HidVibrationDeviceHandle* handle;
2019-03-05 21:13:02 -08:00
float amp;
if (pad >= DEFAULT_MAX_PADS || !vibration_handles[pad])
2019-03-05 21:13:02 -08:00
return false;
2019-07-23 13:59:51 +02:00
amp = (float)strength / 65535.0f;
2019-07-16 14:34:37 +02:00
amp *= 0.5f; /* Max strength is too strong */
2019-07-23 13:59:51 +02:00
2019-03-05 21:13:02 -08:00
if (type == RETRO_RUMBLE_STRONG)
{
vibration_values[pad][0].amp_low = amp;
vibration_values[pad][1].amp_low = amp;
}
else
{
vibration_values[pad][0].amp_high = amp;
vibration_values[pad][1].amp_high = amp;
}
2021-03-12 09:11:43 +00:00
handle = (pad == 0 && !padIsNpadActive(&pad_states[0], HidNpadIdType_No1))
2019-07-23 13:59:51 +02:00
? vibration_handleheld : vibration_handles[pad];
2019-03-05 21:13:02 -08:00
return R_SUCCEEDED(hidSendVibrationValues(handle, vibration_values[pad], 2));
}
#endif
2017-12-23 17:26:58 -08:00
input_device_driver_t switch_joypad = {
2021-03-12 09:11:43 +00:00
switch_joypad_init,
switch_joypad_query_pad,
switch_joypad_destroy,
switch_joypad_button,
switch_joypad_state,
2021-03-12 09:11:43 +00:00
switch_joypad_get_buttons,
switch_joypad_axis,
switch_joypad_poll,
2019-03-05 21:13:02 -08:00
#ifdef HAVE_LIBNX
switch_joypad_set_rumble,
#else
2021-03-12 09:11:43 +00:00
NULL, /* set_rumble */
2019-03-05 21:13:02 -08:00
#endif
NULL,
2021-03-12 09:11:43 +00:00
switch_joypad_name,
"switch"
2017-12-23 17:26:58 -08:00
};