Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions port/include/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ enum mouselockmode {
MLOCK_AUTO = 2
};

enum ConfirmCancelButtonSwap {
CONFIRMCANCEL_SWAP_AUTO = -1, // auto-detect based on controller type
CONFIRMCANCEL_SWAP_OFF = 0, // use standard button layout
CONFIRMCANCEL_SWAP_ON = 1, // use japanese button layout
};

// returns bitmask of connected controllers or -1 if failed
s32 inputInit(void);

Expand Down Expand Up @@ -181,6 +187,9 @@ s32 inputKeyJustPressed(u32 vk);
// idx is controller index, contbtn is one of the CONT_ constants
s32 inputButtonPressed(s32 idx, u32 contbtn);

// Remaps UI button for a controller (handles Confirm/Cancel Face Button swap)
u32 inputConfirmCancelButtonSwap(int cidx, u32 button);

// bind virtkey vk to n64 pad #idx's button/axis ck as represented by its contkey value
// if bind is -1, picks a bind slot automatically
void inputKeyBind(s32 idx, u32 ck, s32 bind, u32 vk);
Expand Down
58 changes: 56 additions & 2 deletions port/src/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "utils.h"
#include "system.h"
#include "fs.h"
#include "constants.h"

#if !SDL_VERSION_ATLEAST(2, 0, 14)
// this was added in 2.0.14
Expand Down Expand Up @@ -46,6 +47,7 @@ static SDL_GameController *pads[INPUT_MAX_CONTROLLERS];
.swapSticks = 1, \
.deviceIndex = -1, \
.cancelCButtons = 0, \
.swapAcceptCancelButtons = -1, \
}

static struct controllercfg {
Expand All @@ -58,6 +60,7 @@ static struct controllercfg {
s32 swapSticks;
s32 deviceIndex;
s32 cancelCButtons;
s32 swapAcceptCancelButtons;
} padsCfg[INPUT_MAX_CONTROLLERS] = {
CONTROLLERCFG_DEFAULT,
CONTROLLERCFG_DEFAULT,
Expand Down Expand Up @@ -350,6 +353,51 @@ static inline void inputInitController(const s32 cidx, const s32 jidx)
}
}

static int inputIsNintendoSwitchController(SDL_GameController *controller) {
#if SDL_VERSION_ATLEAST(2, 0, 12)
switch (SDL_GameControllerGetType(controller)) {
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
#if SDL_VERSION_ATLEAST(2, 24, 0)
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT:
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT:
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
#endif
return 1;
default:
break;
}
#endif

return 0;
}

static int inputConfirmCancelSwapActive(int cidx)
{
if (cidx < 0 || cidx >= INPUT_MAX_CONTROLLERS) {
return 0;
}

switch (padsCfg[cidx].swapAcceptCancelButtons) {
case CONFIRMCANCEL_SWAP_ON:
return 1;
case CONFIRMCANCEL_SWAP_OFF:
return 0;
case CONFIRMCANCEL_SWAP_AUTO:
default:
// Nintendo controllers uses BAYX Layout (B=A, A=B)
return pads[cidx] && inputIsNintendoSwitchController(pads[cidx]);
}
}

u32 inputConfirmCancelButtonSwap(int cidx, u32 button)
{
if (inputConfirmCancelSwapActive(cidx)) {
if (button == BUTTON_UI_ACCEPT) return BUTTON_UI_CANCEL;
if (button == BUTTON_UI_CANCEL) return BUTTON_UI_ACCEPT;
}
return button;
}

static inline void inputCloseController(const s32 cidx)
{
sysLogPrintf(LOG_NOTE, "input: removed controller '%d: (%s)' (id %d) from player %d",
Expand Down Expand Up @@ -761,9 +809,14 @@ s32 inputInit(void)

static inline s32 inputBindPressed(const s32 idx, const u32 ck)
{
u32 swapped_ck = ck;
if (inputConfirmCancelButtonSwap(idx, ck)) {
if (ck == CK_A) swapped_ck = CK_B;
else if (ck == CK_B) swapped_ck = CK_A;
}
for (s32 i = 0; i < INPUT_MAX_BINDS; ++i) {
if (binds[idx][ck][i]) {
if (inputKeyPressed(binds[idx][ck][i])) {
if (binds[idx][swapped_ck][i]) {
if (inputKeyPressed(binds[idx][swapped_ck][i])) {
return 1;
}
}
Expand Down Expand Up @@ -1543,6 +1596,7 @@ PD_CONSTRUCTOR static void inputConfigInit(void)
configRegisterInt(strFmt("%s.CancelCButtons", secname), &padsCfg[c].cancelCButtons, 0, 1);
configRegisterInt(strFmt("%s.SwapSticks", secname), &padsCfg[c].swapSticks, 0, 1);
configRegisterInt(strFmt("%s.ControllerIndex", secname), &padsCfg[c].deviceIndex, -1, 0x7FFFFFFF);
configRegisterInt(strFmt("%s.swapAcceptCancelButtons", secname), &padsCfg[c].swapAcceptCancelButtons, CONFIRMCANCEL_SWAP_AUTO, CONFIRMCANCEL_SWAP_ON);
secname[13] = '.';
for (u32 ck = 0; ck < CK_TOTAL_COUNT; ++ck) {
snprintf(keyname, sizeof(keyname), "%s.%s", secname, inputGetContKeyName(ck));
Expand Down
46 changes: 41 additions & 5 deletions port/src/optionsmenu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1754,6 +1754,32 @@ struct menuitem g_ExtendedBindsMenuItems[] = {
{ MENUITEMTYPE_END },
};

static s32 menuSwapConfirmCancel(s32 key, u32 bindKey)
{
// Only swap for CK_ACCEPT/CK_CANCEL
if ((bindKey != CK_ACCEPT && bindKey != CK_CANCEL) ||
key < VK_JOY_BEGIN || key >= VK_TOTAL_COUNT) {
return key;
}

// Check which controller this key belongs to
s32 controllerIdx = (key - VK_JOY_BEGIN) / INPUT_MAX_CONTROLLER_BUTTONS;

// Check if swap is NOT active for this controller
if (inputConfirmCancelButtonSwap(controllerIdx, BUTTON_UI_ACCEPT) == BUTTON_UI_ACCEPT) {
return key;
}

s32 buttonIdx = (key - VK_JOY_BEGIN) % INPUT_MAX_CONTROLLER_BUTTONS;
if (buttonIdx == 0) {
return key + 1;
} else if (buttonIdx == 1) {
return key - 1;
}

return key;
}

static MenuItemHandlerResult menuhandlerDoBind(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (!menuIsDialogOpen(&g_ExtendedBindKeyMenuDialog)) {
Expand All @@ -1766,8 +1792,13 @@ static MenuItemHandlerResult menuhandlerDoBind(s32 operation, struct menuitem *i
}

const s32 key = inputGetLastKey();
if (key && key != VK_ESCAPE) {
inputKeyBind(g_ExtMenuPlayer, g_BindContKey, g_BindIndex, (key == VK_DELETE ? 0 : key));
if (key && key != VK_DELETE && key != VK_ESCAPE) {
s32 adjustedKey = menuSwapConfirmCancel(key, g_BindContKey);

inputKeyBind(g_ExtMenuPlayer, g_BindContKey, g_BindIndex, adjustedKey);
menuPopDialog();
} else if (key == VK_DELETE) {
inputKeyBind(g_ExtMenuPlayer, g_BindContKey, g_BindIndex, 0);
menuPopDialog();
}

Expand All @@ -1776,9 +1807,12 @@ static MenuItemHandlerResult menuhandlerDoBind(s32 operation, struct menuitem *i

static const char *menutextBind(struct menuitem *item)
{
return g_PlayerExtCfg[g_ExtMenuPlayer].extcontrols ?
menuBinds[item - g_ExtendedBindsMenuItems].name :
menuBinds[item - g_ExtendedBindsMenuItems].n64name;
int idx = item - g_ExtendedBindsMenuItems;
u32 ck = menuBinds[idx].ck;

return g_PlayerExtCfg[g_ExtMenuPlayer].extcontrols ?
menuBinds[idx].name :
menuBinds[idx].n64name;
}

static MenuItemHandlerResult menuhandlerBind(s32 operation, struct menuitem *item, union handlerdata *data)
Expand All @@ -1795,6 +1829,8 @@ static MenuItemHandlerResult menuhandlerBind(s32 operation, struct menuitem *ite
case MENUOP_GETOPTIONTEXT:
binds = inputKeyGetBinds(g_ExtMenuPlayer, menuBinds[idx].ck);
if (binds && binds[data->dropdown.value]) {
s32 displayKey = menuSwapConfirmCancel(binds[data->dropdown.value], menuBinds[idx].ck);

strncpy(keyname, inputGetKeyName(binds[data->dropdown.value]), sizeof(keyname) - 1);
for (char *p = keyname; *p; ++p) {
if (*p == '_') *p = ' ';
Expand Down
17 changes: 10 additions & 7 deletions src/game/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4831,13 +4831,16 @@ void menuProcessInput(void)

#ifndef PLATFORM_N64
// separate buttons for UI accept/cancel
if (buttonsnow & BUTTON_UI_ACCEPT) {
inputs.select = 1;
}

if (buttonsnow & BUTTON_UI_CANCEL) {
inputs.back = 1;
}
// cancel/confirm layout can be swapped either controller type or user preference
u32 acceptBtn = inputConfirmCancelButtonSwap(contpadnums[i], BUTTON_UI_ACCEPT);
u32 cancelBtn = inputConfirmCancelButtonSwap(contpadnums[i], BUTTON_UI_CANCEL);

if (buttonsnow & acceptBtn) {
inputs.select = 1;
}
if (buttonsnow & cancelBtn) {
inputs.back = 1;
}
#endif

if (buttonsnow & B_BUTTON) {
Expand Down