Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5b569e5
added gitignore
AL2009man Jun 9, 2025
487e1ec
fixed Button Layout for Nitntendo Controllers
AL2009man Jun 9, 2025
0e7608f
fixed Face button layout for Nintendo Switch, Japanese face button la…
AL2009man Jun 10, 2025
2d8772c
remove "/vscode" from .gitignore
AL2009man Jun 10, 2025
2467ad1
updated documentation for the new button layout
AL2009man Jun 10, 2025
d805549
changed title from `inputIsSwitchController` to `inputIsNintendoSwitc…
AL2009man Jun 10, 2025
d01f55d
putting guardrails for GitHub Action CI
AL2009man Jun 10, 2025
afe0c56
added UI Menu text to reflect the Japanese layout
AL2009man Jun 10, 2025
58da75e
another attempt to fix build-i686-linux
AL2009man Jun 10, 2025
45da211
replaced Action-based swaps with hardcoded button inputs when using J…
AL2009man Jun 12, 2025
f940d03
ditched hardcoded button inputs for the time being
AL2009man Jun 12, 2025
4d8c870
updated default Joystick deadzone to 6500 / 6
AL2009man Jun 12, 2025
31d17bf
removed NintendoLayout for the time being
AL2009man Jun 13, 2025
372bb61
Restored original default deadzone to prepare for future SDL2 release
AL2009man Jun 24, 2025
5ab41e6
Adjustments Japanese Layout input handling
AL2009man Jul 8, 2025
88ea31b
attempt fix regression for i686-linux
AL2009man Jul 8, 2025
3db08d9
restored previous workaround for GitHub Action compiling
AL2009man Jul 8, 2025
67d3c24
replaced SDL Buttons with CK_BUTTON's
AL2009man Jul 8, 2025
b196c75
removed Getter and Setter for Japanese Layout for now
AL2009man Jul 8, 2025
88ef8b5
Simplified Japanese Layout setup
AL2009man Jul 20, 2025
97e9f2d
attempt whitespace fix
AL2009man Jul 20, 2025
5b9702e
code cleanup
AL2009man Jul 20, 2025
e2aaa2c
fixed `SDL_VERSIONATLEAST number
AL2009man Jul 25, 2025
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
14 changes: 13 additions & 1 deletion 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 japaneseButtonLayout {
JAPANESE_LAYOUT_AUTO = 0, // auto-detect based on controller type
JAPANESE_LAYOUT_OFF = 1, // use standard button layout
JAPANESE_LAYOUT_ON = 2 // use Japanese button layout
};

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

Expand Down Expand Up @@ -181,6 +187,12 @@ 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 Japanese layout)
u32 inputConfirmCancelButtonSwap(int cidx, u32 button);

// Returns 1 if the given controller index is a Nintendo Switch controller, 0 otherwise
int inputControllerIsNintendoSwitch(int cidx);

// 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 Expand Up @@ -270,4 +282,4 @@ const char *inputGetClipboard(void);
// returns keymod values
u32 inputGetKeyModState(void);

#endif
#endif
77 changes: 75 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, \
.japaneseButtonLayout = 0, \
}

static struct controllercfg {
Expand All @@ -58,6 +60,7 @@ static struct controllercfg {
s32 swapSticks;
s32 deviceIndex;
s32 cancelCButtons;
s32 japaneseButtonLayout;
} padsCfg[INPUT_MAX_CONTROLLERS] = {
CONTROLLERCFG_DEFAULT,
CONTROLLERCFG_DEFAULT,
Expand All @@ -67,6 +70,7 @@ static struct controllercfg {

static u32 binds[MAXCONTROLLERS][CK_TOTAL_COUNT][INPUT_MAX_BINDS];
static char bindStrs[MAXCONTROLLERS][CK_TOTAL_COUNT][MAX_BIND_STR];
static int inputIsNintendoSwitchController(SDL_GameController *controller);

static s32 fakeControllers = 0;
static s32 firstController = 0;
Expand Down Expand Up @@ -346,6 +350,23 @@ static inline void inputInitController(const s32 cidx, const s32 jidx)
SDL_JoystickGetGUIDString(guid, guidStr, sizeof(guidStr));
sysLogPrintf(LOG_NOTE, "input: GUID for controller %d: %s", jidx, guidStr);
}

// Set default key binds for this controller
inputSetDefaultKeyBinds(cidx, 0);
}

u32 inputConfirmCancelButtonSwap(int cidx, u32 button) {
int japaneseActive = 0;
if (padsCfg[cidx].japaneseButtonLayout == JAPANESE_LAYOUT_ON) {
japaneseActive = 1;
} else if (padsCfg[cidx].japaneseButtonLayout == JAPANESE_LAYOUT_AUTO) {
japaneseActive = pads[cidx] && inputIsNintendoSwitchController(pads[cidx]);
}
if (japaneseActive) {
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)
Expand Down Expand Up @@ -748,11 +769,62 @@ s32 inputInit(void)
return connectedMask;
}

static int inputIsNintendoSwitchController(SDL_GameController *controller) {
#if defined(SDL_VERSION_ATLEAST)
#if SDL_VERSION_ATLEAST(2, 0, 12)
SDL_GameControllerType type = SDL_GameControllerGetType(controller);
if (
#if defined(SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO)
type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO
#else
0
#endif
#if SDL_VERSION_ATLEAST(2, 24, 0)
#if defined(SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT)
|| type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT
#endif
#if defined(SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT)
|| type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT
#endif
#if defined(SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR)
|| type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
#endif
#endif // SDL_VERSION_ATLEAST(2, 24, 0)
) {
return 1;
}
#endif // SDL_VERSION_ATLEAST(2, 0, 12)
#endif // defined(SDL_VERSION_ATLEAST)
#ifdef SDL_JOYSTICK_VENDOR_NINTENDO
SDL_Joystick *joy = SDL_GameControllerGetJoystick(controller);
if (joy && SDL_JoystickGetVendor(joy) == SDL_JOYSTICK_VENDOR_NINTENDO) {
return 1;
}
#else
// Check for Nintendo controllers by vendor ID (includes Nintendo Switch, Wii, etc.)
SDL_Joystick *joy = SDL_GameControllerGetJoystick(controller);
if (joy && SDL_JoystickGetVendor(joy) == 0x057e) {
return 1;
}
#endif
return 0;
}

int inputControllerIsNintendoSwitch(int cidx) {
return (cidx >= 0 && cidx < INPUT_MAX_CONTROLLERS && pads[cidx])
? inputIsNintendoSwitchController(pads[cidx]) : 0;
}

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 @@ -1532,6 +1604,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.JapaneseButtonLayout", secname), &padsCfg[c].japaneseButtonLayout, 0, 2);
secname[13] = '.';
for (u32 ck = 0; ck < CK_TOTAL_COUNT; ++ck) {
snprintf(keyname, sizeof(keyname), "%s.%s", secname, inputGetContKeyName(ck));
Expand Down
38 changes: 32 additions & 6 deletions port/src/optionsmenu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1742,8 +1742,31 @@ 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 = key;

// Handle Nintendo Switch controller button swapping for Japanese layout
if (inputControllerIsNintendoSwitch(g_ExtMenuPlayer) &&
inputConfirmCancelButtonSwap(g_ExtMenuPlayer, key) &&
key >= VK_JOY_BEGIN && key < VK_TOTAL_COUNT) {

s32 keyControllerIdx = (key - VK_JOY_BEGIN) / INPUT_MAX_CONTROLLER_BUTTONS;
if (keyControllerIdx == g_ExtMenuPlayer) {
s32 buttonInController = (key - VK_JOY_BEGIN) % INPUT_MAX_CONTROLLER_BUTTONS;

// Swap A and B buttons for Japanese layout
if (buttonInController == CK_A) {
adjustedKey = key + (CK_B - CK_A);
} else if (buttonInController == CK_B) {
adjustedKey = key + (CK_A - CK_B);
}
}
}

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 @@ -1752,9 +1775,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 Down Expand Up @@ -1922,4 +1948,4 @@ struct menudialogdef g_ExtendedMenuDialog = {
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
};
18 changes: 10 additions & 8 deletions src/game/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4830,14 +4830,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;
}
// Use remapped UI buttons for accept/cancel (handles Japanese layout)
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