port: add keybind menu

This commit is contained in:
fgsfds committed 2023-10-28 18:17:35 +02:00
1 parent cea9527936
commit c8db5fa106
3 files changed
+378 -14

No files matched your search

+8
View File
@@ -6,6 +6,7 @@
#define INPUT_MAX_CONTROLLERS MAXCONTROLLERS
#define INPUT_MAX_CONTROLLER_BUTTONS 32
#define INPUT_MAX_BINDS 4
#define CONT_STICK_XNEG 0x10000
#define CONT_STICK_XPOS 0x20000
@@ -115,6 +116,8 @@ s32 inputButtonPressed(s32 idx, u32 contbtn);
// if bind is -1, picks a bind slot automatically
void inputKeyBind(s32 idx, u32 ck, s32 bind, u32 vk);
const u32 *inputKeyGetBinds(s32 idx, u32 ck);
// get VK_ value from human-readable name
s32 inputGetKeyByName(const char *name);
@@ -165,4 +168,9 @@ void inputUpdate(void);
// call this before configSave()
void inputSaveConfig(void);
void inputSetDefaultKeyBinds(void);
void inputClearLastKey(void);
s32 inputGetLastKey(void);
#endif
+82 -14
View File
@@ -10,7 +10,6 @@
#include "config.h"
#include "system.h"
#define MAX_BINDS 4
#define TRIG_THRESHOLD (30 * 256)
#define DEFAULT_DEADZONE 4096
#define DEFAULT_DEADZONE_RY 6144
@@ -21,7 +20,7 @@
static SDL_GameController *pads[INPUT_MAX_CONTROLLERS];
static s32 rumbleSupported[INPUT_MAX_CONTROLLERS];
static u32 binds[MAXCONTROLLERS][CK_TOTAL_COUNT][MAX_BINDS]; // [i][CK_][b] = [VK_]
static u32 binds[MAXCONTROLLERS][CK_TOTAL_COUNT][INPUT_MAX_BINDS]; // [i][CK_][b] = [VK_]
static s32 connectedMask = 0;
@@ -37,6 +36,8 @@ static f32 mouseSensY = 1.5f;
static f32 rumbleScale = 0.5f;
static s32 lastKey = 0;
// NOTE: by default this gets inverted for 1.2: "right stick" here means left stick on your controller
static u32 axisMap[2][2] = {
{ SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY },
@@ -186,6 +187,8 @@ void inputSetDefaultKeyBinds(void)
{ CK_8000, SDL_CONTROLLER_BUTTON_LEFTSTICK },
};
memset(binds, 0, sizeof(binds));
for (u32 i = 0; i < sizeof(kbbinds) / sizeof(kbbinds[0]); ++i) {
for (s32 j = 1; j < 3; ++j) {
if (kbbinds[i][j]) {
@@ -233,6 +236,18 @@ static inline void inputCloseController(const s32 cidx)
}
}
static inline s32 inputControllerGetIndex(SDL_GameController *ctrl) {
if (ctrl) {
for (s32 i = 0; i < INPUT_MAX_CONTROLLERS; ++i) {
if (pads[i] == ctrl) {
return i;
}
}
}
return -1;
}
static int inputEventFilter(void *data, SDL_Event *event)
{
switch (event->type) {
@@ -250,19 +265,54 @@ static int inputEventFilter(void *data, SDL_Event *event)
case SDL_CONTROLLERDEVICEREMOVED: {
SDL_GameController *ctrl = SDL_GameControllerFromInstanceID(event->cdevice.which);
if (ctrl) {
for (s32 i = 0; i < INPUT_MAX_CONTROLLERS; ++i) {
if (pads[i] == ctrl) {
inputCloseController(i);
break;
}
}
const s32 idx = inputControllerGetIndex(ctrl);
if (idx >= 0) {
inputCloseController(idx);
}
break;
}
case SDL_MOUSEWHEEL:
mouseWheel = event->wheel.y;
if (!lastKey && mouseWheel) {
lastKey = (mouseWheel < 0) + VK_MOUSE_WHEEL_UP;
}
break;
case SDL_MOUSEBUTTONDOWN:
if (!lastKey) {
lastKey = VK_MOUSE_BEGIN - 1 + event->button.button;
}
break;
case SDL_KEYDOWN:
if (!lastKey) {
lastKey = VK_KEYBOARD_BEGIN + event->key.keysym.scancode;
}
break;
case SDL_CONTROLLERBUTTONDOWN:
if (!lastKey) {
lastKey = VK_JOY1_BEGIN + event->cbutton.button;
SDL_GameController *ctrl = SDL_GameControllerFromInstanceID(event->cdevice.which);
const s32 idx = inputControllerGetIndex(ctrl);
if (idx >= 0) {
lastKey += idx * INPUT_MAX_CONTROLLER_BUTTONS;
}
}
break;
case SDL_CONTROLLERAXISMOTION:
if (!lastKey) {
if (event->caxis.axis >= SDL_CONTROLLER_AXIS_TRIGGERLEFT && event->caxis.value > TRIG_THRESHOLD) {
lastKey = VK_JOY1_LTRIG + (event->caxis.axis - SDL_CONTROLLER_AXIS_TRIGGERLEFT);
SDL_GameController *ctrl = SDL_GameControllerFromInstanceID(event->cdevice.which);
const s32 idx = inputControllerGetIndex(ctrl);
if (idx >= 0) {
lastKey += idx * INPUT_MAX_CONTROLLER_BUTTONS;
}
}
}
break;
default:
@@ -349,7 +399,7 @@ static inline void inputSaveBinds(void)
for (u32 ck = 0; ck < CK_TOTAL_COUNT; ++ck) {
snprintf(keyname, sizeof(keyname), "%s.%s", secname, inputGetContKeyName(ck));
bindstr[0] = '\0';
for (s32 b = 0; b < MAX_BINDS; ++b) {
for (s32 b = 0; b < INPUT_MAX_BINDS; ++b) {
if (binds[i][ck][b]) {
if (b) {
strncat(bindstr, ", ", sizeof(bindstr) - 1);
@@ -500,7 +550,7 @@ s32 inputInit(void)
static inline s32 inputBindPressed(const s32 idx, const u32 ck)
{
for (s32 i = 0; i < MAX_BINDS; ++i) {
for (s32 i = 0; i < INPUT_MAX_BINDS; ++i) {
if (binds[idx][ck][i]) {
if (inputKeyPressed(binds[idx][ck][i])) {
return 1;
@@ -733,26 +783,34 @@ void inputControllerSetAxisDeadzone(s32 stick, s32 axis, f32 value)
void inputKeyBind(s32 idx, u32 ck, s32 bind, u32 vk)
{
if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || bind >= MAX_BINDS || ck >= CK_TOTAL_COUNT) {
if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || bind >= INPUT_MAX_BINDS || ck >= CK_TOTAL_COUNT) {
return;
}
if (bind < 0) {
for (s32 i = 0; i < MAX_BINDS; ++i) {
for (s32 i = 0; i < INPUT_MAX_BINDS; ++i) {
if (binds[idx][ck][i] == 0) {
bind = i;
break;
}
}
if (bind < 0) {
bind = MAX_BINDS - 1; // just overwrite last
bind = INPUT_MAX_BINDS - 1; // just overwrite last
}
}
binds[idx][ck][bind] = vk;
}
const u32 *inputKeyGetBinds(s32 idx, u32 ck)
{
if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || ck >= CK_TOTAL_COUNT) {
return NULL;
}
return binds[idx][ck];
}
s32 inputKeyPressed(u32 vk)
{
if (vk >= VK_KEYBOARD_BEGIN && vk < VK_MOUSE_BEGIN) {
@@ -935,3 +993,13 @@ s32 inputGetKeyByName(const char *name)
return -1;
}
void inputClearLastKey(void)
{
lastKey = 0;
}
s32 inputGetLastKey(void)
{
return lastKey;
}
+288
View File
@@ -11,6 +11,11 @@
#include "input.h"
#include "config.h"
static s32 g_BindsPlayer = 0;
static s32 g_BindIndex = 0;
static u32 g_BindContKey = 0;
static char g_BindsPlayerText[] = "Player 1 Bindings";
static MenuItemHandlerResult menuhandlerMouseEnabled(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
@@ -691,6 +696,281 @@ struct menudialogdef g_ExtendedGameMenuDialog = {
NULL,
};
static MenuItemHandlerResult menuhandlerDoBind(s32 operation, struct menuitem *item, union handlerdata *data);
struct menuitem g_ExtendedBindKeyMenuItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"\n",
0,
NULL,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Press new key or button...\n",
0,
menuhandlerDoBind,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_ExtendedBindKeyMenuDialog = {
MENUDIALOGTYPE_WHITE,
(uintptr_t)"Bind",
g_ExtendedBindKeyMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_IGNOREBACK | MENUDIALOGFLAG_STARTSELECTS,
NULL,
};
struct menubind {
u32 ck;
const char *name;
};
static const struct menubind menuBinds[] = {
{ CK_ZTRIG, "Fire [ZT]\n" },
{ CK_LTRIG, "Fire Mode [LT]\n" },
{ CK_RTRIG, "Aim Mode [RT]\n" },
{ CK_A, "Use / Accept [A]\n" },
{ CK_B, "Use / Cancel [B]\n" },
{ CK_X, "Reload [X]\n" },
{ CK_Y, "Next Weapon [Y]\n" },
{ CK_DPAD_L, "Prev Weapon [DL]\n" },
{ CK_DPAD_L, "Radial Menu [DD]\n" },
{ CK_START, "Pause Menu [ST]\n" },
{ CK_8000, "Cycle Crouch [+]\n" },
{ CK_4000, "Half Crouch [+]\n" },
{ CK_2000, "Full Crouch [+]\n" },
};
static const char *menutextBind(struct menuitem *item);
static MenuItemHandlerResult menuhandlerBind(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerResetBinds(s32 operation, struct menuitem *item, union handlerdata *data);
#define DEFINE_MENU_BIND() \
{ \
MENUITEMTYPE_DROPDOWN, \
0, \
0, \
(uintptr_t)menutextBind, \
0, \
menuhandlerBind, \
}
struct menuitem g_ExtendedBindsMenuItems[] = {
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Reset to Defaults\n",
0,
menuhandlerResetBinds,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
static MenuItemHandlerResult menuhandlerDoBind(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (!menuIsDialogOpen(&g_ExtendedBindKeyMenuDialog)) {
return 0;
}
if (inputKeyPressed(VK_ESCAPE)) {
menuPopDialog();
return 0;
}
const s32 key = inputGetLastKey();
if (key && key != VK_ESCAPE) {
inputKeyBind(g_BindsPlayer, g_BindContKey, g_BindIndex, key);
menuPopDialog();
}
return 0;
}
static const char *menutextBind(struct menuitem *item)
{
return menuBinds[item - g_ExtendedBindsMenuItems].name;
}
static MenuItemHandlerResult menuhandlerBind(s32 operation, struct menuitem *item, union handlerdata *data)
{
const s32 idx = item - g_ExtendedBindsMenuItems;
const u32 *binds;
static char keyname[128];
switch (operation) {
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = INPUT_MAX_BINDS;
break;
case MENUOP_GETOPTIONTEXT:
binds = inputKeyGetBinds(g_BindsPlayer, menuBinds[idx].ck);
if (binds && binds[data->dropdown.value]) {
strncpy(keyname, inputGetKeyName(binds[data->dropdown.value]), sizeof(keyname) - 1);
for (char *p = keyname; *p; ++p) {
if (*p == '_') *p = ' ';
}
return (intptr_t)keyname;
}
return (intptr_t)"NONE";
case MENUOP_SET:
g_ExtendedBindKeyMenuItems[0].param2 = (uintptr_t)menuBinds[idx].name;
g_BindIndex = data->dropdown.value;
g_BindContKey = menuBinds[idx].ck;
inputClearLastKey();
menuPushDialog(&g_ExtendedBindKeyMenuDialog);
break;
case MENUOP_GETSELECTEDINDEX:
data->dropdown.value = 0;
}
return 0;
}
static MenuItemHandlerResult menuhandlerResetBinds(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
inputSetDefaultKeyBinds();
}
return 0;
}
struct menudialogdef g_ExtendedBindsMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)g_BindsPlayerText,
g_ExtendedBindsMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_STARTSELECTS | MENUDIALOGFLAG_IGNOREBACK,
NULL,
};
static MenuItemHandlerResult menuhandlerOpenBinds(s32 operation, struct menuitem *item, union handlerdata *data);
struct menuitem g_ExtendedSelectBindsMenuItems[] = {
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Player 1\n",
0,
menuhandlerOpenBinds,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Player 2\n",
0,
menuhandlerOpenBinds,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Player 3\n",
0,
menuhandlerOpenBinds,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Player 4\n",
0,
menuhandlerOpenBinds,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
static MenuItemHandlerResult menuhandlerOpenBinds(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
g_BindsPlayer = item - g_ExtendedSelectBindsMenuItems;
g_BindsPlayerText[7] = g_BindsPlayer + '1';
menuPushDialog(&g_ExtendedBindsMenuDialog);
}
return 0;
}
struct menudialogdef g_ExtendedSelectBindsMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Key Bindings",
g_ExtendedSelectBindsMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
struct menuitem g_ExtendedMenuItems[] = {
{
MENUITEMTYPE_SELECTABLE,
@@ -724,6 +1004,14 @@ struct menuitem g_ExtendedMenuItems[] = {
0,
(void *)&g_ExtendedGameMenuDialog,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_OPENSDIALOG | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Key Bindings\n",
0,
(void *)&g_ExtendedSelectBindsMenuDialog,
},
{
MENUITEMTYPE_SEPARATOR,
0,