Clean up gamepad code a bit, rename buttons

- renamed gamepad/joystick actions and keys to have some meaning
  for buttons (instead of just JOY1, JOY2 etc)
- compiles with SDL1.2 again (there gamepads aren't supported though)
- shorter names for gamepad keys/axis in the key bindings menu
This commit is contained in:
Daniel Gibson 2024-01-08 05:26:27 +01:00
parent ab53e9aa13
commit 700b3ee558
6 changed files with 244 additions and 101 deletions

View file

@ -2919,8 +2919,14 @@ void idCommonLocal::Init( int argc, char **argv ) {
#endif
#endif
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER)) // init joystick to work around SDL 2.0.9 bug #4391
#else
if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO)) // no gamecontroller support in SDL1
#endif
{
Sys_Error("Error while initializing SDL: %s", SDL_GetError());
}
Sys_InitThreads();

View file

@ -109,39 +109,42 @@ static const keyname_t keynames[] =
{"MWHEELUP", K_MWHEELUP, "#str_07131"},
{"MWHEELDOWN", K_MWHEELDOWN, "#str_07132"},
{"JOY1", K_JOY1, "#str_07062"},
{"JOY2", K_JOY2, "#str_07063"},
{"JOY3", K_JOY3, "#str_07064"},
{"JOY4", K_JOY4, "#str_07065"},
{"JOY5", K_JOY5, "#str_07066"},
{"JOY6", K_JOY6, "#str_07067"},
{"JOY7", K_JOY7, "#str_07068"},
{"JOY8", K_JOY8, "#str_07069"},
{"JOY9", K_JOY9, "#str_07070"},
{"JOY10", K_JOY10, "#str_07071"},
{"JOY11", K_JOY11, "#str_07072"},
{"JOY12", K_JOY12, "#str_07073"},
{"JOY13", K_JOY13, "#str_07074"},
{"JOY14", K_JOY14, "#str_07075"},
{"JOY15", K_JOY15, "#str_07076"},
// Note: for localized gamepad key names, we use Sys_GetLocalizedJoyKeyName()
// so the last column is just NULL
{"JOY_BTN_SOUTH", K_JOY_BTN_SOUTH, NULL},
{"JOY_BTN_EAST", K_JOY_BTN_EAST, NULL},
{"JOY_BTN_WEST", K_JOY_BTN_WEST, NULL},
{"JOY_BTN_NORTH", K_JOY_BTN_NORTH, NULL},
{"JOY_BTN_BACK", K_JOY_BTN_BACK, NULL},
// leaving out K_JOY_BTN_GUIDE, as I think it shouldn't be used (might open Steam or similar)
{"JOY_BTN_START", K_JOY_BTN_START, NULL},
{"JOY_BTN_LSTICK", K_JOY_BTN_LSTICK, NULL},
{"JOY_BTN_RSTICK", K_JOY_BTN_RSTICK, NULL},
{"JOY_BTN_LSHOULDER", K_JOY_BTN_LSHOULDER, NULL},
{"JOY_BTN_RSHOULDER", K_JOY_BTN_RSHOULDER, NULL},
{"JOY_BTN_MISC1", K_JOY_BTN_MISC1, NULL},
{"JOY_BTN_RPADDLE1", K_JOY_BTN_RPADDLE1, NULL},
{"JOY_BTN_LPADDLE1", K_JOY_BTN_LPADDLE1, NULL},
{"JOY_BTN_RPADDLE2", K_JOY_BTN_RPADDLE2, NULL},
{"JOY_BTN_LPADDLE2", K_JOY_BTN_LPADDLE2, NULL},
{"JOY_STICK1_UP", K_JOY_STICK1_UP, "JOY_STICK1_UP"},
{"JOY_STICK1_DOWN", K_JOY_STICK1_DOWN, "JOY_STICK1_DOWN"},
{"JOY_STICK1_LEFT", K_JOY_STICK1_LEFT, "JOY_STICK1_LEFT"},
{"JOY_STICK1_RIGHT", K_JOY_STICK1_RIGHT, "JOY_STICK1_RIGHT"},
{"JOY_STICK1_UP", K_JOY_STICK1_UP, NULL},
{"JOY_STICK1_DOWN", K_JOY_STICK1_DOWN, NULL},
{"JOY_STICK1_LEFT", K_JOY_STICK1_LEFT, NULL},
{"JOY_STICK1_RIGHT", K_JOY_STICK1_RIGHT, NULL},
{"JOY_STICK2_UP", K_JOY_STICK2_UP, "JOY_STICK2_UP"},
{"JOY_STICK2_DOWN", K_JOY_STICK2_DOWN, "JOY_STICK2_DOWN"},
{"JOY_STICK2_LEFT", K_JOY_STICK2_LEFT, "JOY_STICK2_LEFT"},
{"JOY_STICK2_RIGHT", K_JOY_STICK2_RIGHT, "JOY_STICK2_RIGHT"},
{"JOY_STICK2_UP", K_JOY_STICK2_UP, NULL},
{"JOY_STICK2_DOWN", K_JOY_STICK2_DOWN, NULL},
{"JOY_STICK2_LEFT", K_JOY_STICK2_LEFT, NULL},
{"JOY_STICK2_RIGHT", K_JOY_STICK2_RIGHT, NULL},
{"JOY_TRIGGER1", K_JOY_TRIGGER1, "JOY_TRIGGER1"},
{"JOY_TRIGGER2", K_JOY_TRIGGER2, "JOY_TRIGGER2"},
{"JOY_TRIGGER1", K_JOY_TRIGGER1, NULL},
{"JOY_TRIGGER2", K_JOY_TRIGGER2, NULL},
{"JOY_DPAD_UP", K_JOY_DPAD_UP, "JOY_DPAD_UP"},
{"JOY_DPAD_DOWN", K_JOY_DPAD_DOWN, "JOY_DPAD_DOWN"},
{"JOY_DPAD_LEFT", K_JOY_DPAD_LEFT, "JOY_DPAD_LEFT"},
{"JOY_DPAD_RIGHT", K_JOY_DPAD_RIGHT, "JOY_DPAD_RIGHT"},
{"JOY_DPAD_UP", K_JOY_DPAD_UP, NULL},
{"JOY_DPAD_DOWN", K_JOY_DPAD_DOWN, NULL},
{"JOY_DPAD_LEFT", K_JOY_DPAD_LEFT, NULL},
{"JOY_DPAD_RIGHT", K_JOY_DPAD_RIGHT, NULL},
{"AUX1", K_AUX1, "#str_07094"},
{"AUX2", K_AUX2, "#str_07095"},
@ -410,6 +413,12 @@ const char *idKeyInput::KeyNumToString( int keynum, bool localized ) {
}
}
if ( localized && keynum >= K_FIRST_JOY && keynum <= K_LAST_JOY ) {
const char* jname = Sys_GetLocalizedJoyKeyName(keynum);
if(jname != NULL)
return jname;
}
// check for a key string
for ( kn = keynames; kn->name; kn++ ) {
if ( keynum == kn->keynum ) {

View file

@ -139,25 +139,27 @@ typedef enum {
K_MWHEELUP,
//------------------------
// K_JOY codes must be contiguous, too
// K_JOY codes must be contiguous, too, and K_JOY_BTN_* should be kept in sync with J_BTN_* of sys_jEvents
//------------------------
K_JOY1 = 197,
K_JOY2,
K_JOY3,
K_JOY4,
K_JOY5,
K_JOY6,
K_JOY7,
K_JOY8,
K_JOY9,
K_JOY10,
K_JOY11,
K_JOY12,
K_JOY13,
K_JOY14,
K_JOY15,
K_JOY16,
K_FIRST_JOY = 197,
K_JOY_BTN_SOUTH = K_FIRST_JOY, // bottom face button, like Xbox A
K_JOY_BTN_EAST, // right face button, like Xbox B
K_JOY_BTN_WEST, // left face button, like Xbox X
K_JOY_BTN_NORTH, // top face button, like Xbox Y
K_JOY_BTN_BACK,
K_JOY_BTN_GUIDE, // Note: this one should probably not be used?
K_JOY_BTN_START,
K_JOY_BTN_LSTICK, // press left stick
K_JOY_BTN_RSTICK, // press right stick
K_JOY_BTN_LSHOULDER,
K_JOY_BTN_RSHOULDER,
// NOTE: in SDL3, the 4 DPAD buttons would be following, we have those later
K_JOY_BTN_MISC1, // Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button)
K_JOY_BTN_RPADDLE1, // Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1)
K_JOY_BTN_LPADDLE1, // Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3)
K_JOY_BTN_RPADDLE2, // Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2)
K_JOY_BTN_LPADDLE2, // Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4)
K_JOY_STICK1_UP,
K_JOY_STICK1_DOWN,
@ -176,6 +178,7 @@ typedef enum {
K_JOY_DPAD_DOWN,
K_JOY_DPAD_LEFT,
K_JOY_DPAD_RIGHT,
K_LAST_JOY = K_JOY_DPAD_RIGHT,
K_GRAVE_A = 229, // lowercase a with grave accent FIXME: used to be 224; this probably isn't used anyway

View file

@ -1254,8 +1254,8 @@ void idUsercmdGenLocal::Joystick( void ) {
int action;
int value;
if ( Sys_ReturnJoystickInputEvent( i, action, value ) ) {
if ( action >= J_ACTION1 && action <= J_ACTION_MAX ) {
int joyButton = K_JOY1 + ( action - J_ACTION1 );
if ( action >= J_ACTION_FIRST && action <= J_ACTION_MAX ) {
int joyButton = K_FIRST_JOY + ( action - J_ACTION_FIRST );
Key( joyButton, ( value != 0 ) );
} else if ( ( action >= J_AXIS_MIN ) && ( action <= J_AXIS_MAX ) ) {
joystickAxis[ action - J_AXIS_MIN ] = static_cast<float>( value ) / 32767.0f;

View file

@ -189,7 +189,7 @@ static scancodename_t scancodemappings[] = {
D3_SC_MAPPING(COMMA),
D3_SC_MAPPING(PERIOD),
D3_SC_MAPPING(SLASH),
// leaving out lots of key incl. from keypad, we already handle them as normal keys
// leaving out lots of keys incl. from keypad, we already handle them as normal keys
D3_SC_MAPPING(NONUSBACKSLASH),
D3_SC_MAPPING(INTERNATIONAL1), /**< used on Asian keyboards, see footnotes in USB doc */
D3_SC_MAPPING(INTERNATIONAL2),
@ -264,6 +264,121 @@ static bool utf8ToISO8859_1(const char* inbuf, char* outbuf, size_t outsize) {
}
#endif // SDL2
const char* Sys_GetLocalizedJoyKeyName( int key ) {
// Note: trying to keep the returned names short, because the Doom3 binding window doesn't have much space for names..
#if SDL_VERSION_ATLEAST(2, 0, 0) // gamecontroller/gamepad not supported in SDL1
if (key >= K_FIRST_JOY && key <= K_LAST_JOY) {
if (key <= K_JOY_BTN_NORTH) {
#if SDL_VERSION_ATLEAST(3, 0, 0)
SDL_GamepadButton gpbtn = SDL_GAMEPAD_BUTTON_SOUTH + (key - K_JOY_BTN_NORTH);
SDL_GamepadButtonLabel label = SDL_GetGamepadButtonLabeForTypel(TODO, gpbtn);
switch(label) {
case SDL_GAMEPAD_BUTTON_LABEL_A:
return "Pad A";
case SDL_GAMEPAD_BUTTON_LABEL_B:
return "Pad B";
case SDL_GAMEPAD_BUTTON_LABEL_X:
return "Pad X";
case SDL_GAMEPAD_BUTTON_LABEL_Y:
return "Pad Y";
case SDL_GAMEPAD_BUTTON_LABEL_CROSS:
return "Pad Cross";
case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE:
return "Pad Circle";
case SDL_GAMEPAD_BUTTON_LABEL_SQUARE:
return "Pad Square";
case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE:
return "Pad Triangle";
}
#else // SDL2
// using xbox-style names, like SDL2 does (SDL can't tell us if this is a xbox or PS or nintendo or whatever-style gamepad)
switch(key) {
case K_JOY_BTN_SOUTH:
return "Pad A";
case K_JOY_BTN_EAST:
return "Pad B";
case K_JOY_BTN_WEST:
return "Pad X";
case K_JOY_BTN_NORTH:
return "Pad Y";
}
#endif // face button names for SDL2
}
// the labels for the remaining keys are the same for SDL2 and SDL3 (and all controllers)
// Note: Would be nicer with "Pad " at the beginning, but then it's too long for the keybinding window :-/
switch(key) {
case K_JOY_BTN_BACK:
return "Pad Back";
case K_JOY_BTN_GUIDE:
return NULL; // ???
case K_JOY_BTN_START:
return "Pad Start";
case K_JOY_BTN_LSTICK:
return "Pad LStick";
case K_JOY_BTN_RSTICK:
return "Pad RStick";
case K_JOY_BTN_LSHOULDER:
return "Pad LShoulder";
case K_JOY_BTN_RSHOULDER:
return "Pad RShoulder";
// NOTE: in SDL3, the 4 DPAD buttons would be following, we have those later
case K_JOY_BTN_MISC1:
return "Pad Misc";
case K_JOY_BTN_RPADDLE1:
return "Pad P1";
case K_JOY_BTN_LPADDLE1:
return "Pad P3";
case K_JOY_BTN_RPADDLE2:
return "Pad P2";
case K_JOY_BTN_LPADDLE2:
return "Pad P4";
case K_JOY_STICK1_UP:
return "Stick1 Up";
case K_JOY_STICK1_DOWN:
return "Stick1 Down";
case K_JOY_STICK1_LEFT:
return "Stick1 Left";
case K_JOY_STICK1_RIGHT:
return "Stick1 Right";
case K_JOY_STICK2_UP:
return "Stick2 Up";
case K_JOY_STICK2_DOWN:
return "Stick2 Down";
case K_JOY_STICK2_LEFT:
return "Stick2 Left";
case K_JOY_STICK2_RIGHT:
return "Stick2 Right";
case K_JOY_TRIGGER1:
return "Trigger 1";
case K_JOY_TRIGGER2:
return "Trigger 2";
case K_JOY_DPAD_UP:
return "DPad Up";
case K_JOY_DPAD_DOWN:
return "DPad Down";
case K_JOY_DPAD_LEFT:
return "DPad Left";
case K_JOY_DPAD_RIGHT:
return "DPad Right";
default:
assert(0 && "missing a case in Sys_GetLocalizedJoyKeyName() for axes or dpad!");
}
}
#endif // SDL2+
return NULL;
}
// returns localized name of the key (between K_FIRST_SCANCODE and K_LAST_SCANCODE),
// regarding the current keyboard layout - if that name is in ASCII or corresponds
// to a "High-ASCII" char supported by Doom3.
@ -495,33 +610,35 @@ static byte mapkey(SDL_Keycode key) {
return 0;
}
static sys_jEvents mapjoybutton(SDL_GameControllerButton button) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
static sys_jEvents mapjoybutton(SDL_GameControllerButton button) {
switch (button)
{
case SDL_CONTROLLER_BUTTON_A:
return J_ACTION1;
return J_BTN_SOUTH;
case SDL_CONTROLLER_BUTTON_B:
return J_ACTION2;
return J_BTN_EAST;
case SDL_CONTROLLER_BUTTON_X:
return J_ACTION3;
return J_BTN_WEST;
case SDL_CONTROLLER_BUTTON_Y:
return J_ACTION4;
return J_BTN_NORTH;
case SDL_CONTROLLER_BUTTON_BACK:
return J_ACTION10;
return J_BTN_BACK;
case SDL_CONTROLLER_BUTTON_GUIDE:
// TODO:
// TODO: this one should probably not be bindable?
//return J_BTN_GUIDE;
break;
case SDL_CONTROLLER_BUTTON_START:
return J_ACTION9;
return J_BTN_START;
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
return J_ACTION7;
return J_BTN_LSTICK;
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
return J_ACTION8;
return J_BTN_RSTICK;
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
return J_ACTION5;
return J_BTN_LSHOULDER;
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
return J_ACTION6;
return J_BTN_RSHOULDER;
case SDL_CONTROLLER_BUTTON_DPAD_UP:
return J_DPAD_UP;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
@ -530,16 +647,26 @@ static sys_jEvents mapjoybutton(SDL_GameControllerButton button) {
return J_DPAD_LEFT;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
return J_DPAD_RIGHT;
// TODO: have the following always been supported in SDL2?
case SDL_CONTROLLER_BUTTON_MISC1:
return J_BTN_MISC1;
case SDL_CONTROLLER_BUTTON_PADDLE1:
return J_BTN_RPADDLE1;
case SDL_CONTROLLER_BUTTON_PADDLE2:
return J_BTN_RPADDLE2;
case SDL_CONTROLLER_BUTTON_PADDLE3:
return J_BTN_LPADDLE1;
case SDL_CONTROLLER_BUTTON_PADDLE4:
return J_BTN_LPADDLE2;
default:
common->Warning("unknown game controller button %u", button);
break;
}
return MAX_JOY_EVENT;
}
static sys_jEvents mapjoyaxis(SDL_GameControllerAxis axis) {
switch (axis)
{
case SDL_CONTROLLER_AXIS_LEFTX:
@ -558,9 +685,9 @@ static sys_jEvents mapjoyaxis(SDL_GameControllerAxis axis) {
common->Warning("unknown game controller axis %u", axis);
break;
}
return J_AXIS_MAX;
}
#endif // SDL2+ gamecontroller code
static void PushConsoleEvent(const char *s) {
char *b;
@ -623,12 +750,13 @@ void Sys_InitInput() {
memset( buttonStates, 0, sizeof( buttonStates ) );
memset( joyAxis, 0, sizeof( joyAxis ) );
#if SDL_VERSION_ATLEAST(2, 0, 0) // gamecontroller/gamepad not supported in SDL1
const int NumJoysticks = SDL_NumJoysticks();
printf("XXX found %d joysticks\n", NumJoysticks);
for( int i = 0; i < NumJoysticks; ++i )
{
SDL_GameController* gc = SDL_GameControllerOpen( i );
}
#endif
}
/*
@ -1078,6 +1206,7 @@ sysEvent_t Sys_GetEvent() {
return res;
#if SDL_VERSION_ATLEAST(2, 0, 0) // gamecontroller/gamepad not supported in SDL1
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
{
@ -1086,8 +1215,8 @@ sysEvent_t Sys_GetEvent() {
res.evType = SE_KEY;
res.evValue2 = ev.cbutton.state == SDL_PRESSED ? 1 : 0;
if ( ( jEvent >= J_ACTION1 ) && ( jEvent <= J_ACTION_MAX ) ) {
res.evValue = K_JOY1 + ( jEvent - J_ACTION1 );
if ( ( jEvent >= J_BTN_SOUTH ) && ( jEvent <= J_ACTION_MAX ) ) {
res.evValue = K_JOY_BTN_SOUTH + ( jEvent - J_BTN_SOUTH );
return res;
} else if ( ( jEvent >= J_DPAD_UP ) && ( jEvent <= J_DPAD_RIGHT ) ) {
res.evValue = K_JOY_DPAD_UP + ( jEvent - J_DPAD_UP );
@ -1147,6 +1276,7 @@ sysEvent_t Sys_GetEvent() {
// TODO: hot swapping maybe.
//lbOnControllerUnPlug(event.jdevice.which);
break;
#endif // SDL2+
case SDL_QUIT:
PushConsoleEvent("quit");

View file

@ -78,41 +78,30 @@ typedef enum {
} sys_mEvents;
typedef enum {
J_ACTION1,
J_ACTION2,
J_ACTION3,
J_ACTION4,
J_ACTION5,
J_ACTION6,
J_ACTION7,
J_ACTION8,
J_ACTION9,
J_ACTION10,
J_ACTION11,
J_ACTION12,
J_ACTION13,
J_ACTION14,
J_ACTION15,
J_ACTION16,
J_ACTION17,
J_ACTION18,
J_ACTION19,
J_ACTION20,
J_ACTION21,
J_ACTION22,
J_ACTION23,
J_ACTION24,
J_ACTION25,
J_ACTION26,
J_ACTION27,
J_ACTION28,
J_ACTION29,
J_ACTION30,
J_ACTION31,
J_ACTION32,
J_ACTION_MAX = J_ACTION32,
J_ACTION_FIRST,
// these names are similar to the SDL3 SDL_GamepadButton names
J_BTN_SOUTH = J_ACTION_FIRST, // bottom face button, like Xbox A
J_BTN_EAST, // right face button, like Xbox B
J_BTN_WEST, // left face button, like Xbox X
J_BTN_NORTH, // top face button, like Xbox Y
J_BTN_BACK,
J_BTN_GUIDE, // Note: this one should probably not be used?
J_BTN_START,
J_BTN_LSTICK, // press left stick
J_BTN_RSTICK, // press right stick
J_BTN_LSHOULDER,
J_BTN_RSHOULDER,
// NOTE: in SDL3, the 4 DPAD buttons would be following, we have those at the end
J_BTN_MISC1, // Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button)
J_BTN_RPADDLE1, // Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1)
J_BTN_LPADDLE1, // Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3)
J_BTN_RPADDLE2, // Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2)
J_BTN_LPADDLE2, // Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4)
J_AXIS_MIN,
J_ACTION_MAX = J_BTN_LPADDLE2,
// leaving some space here for about 16 additional J_ACTIONs, if needed
J_AXIS_MIN = 32,
J_AXIS_LEFT_X = J_AXIS_MIN + AXIS_LEFT_X,
J_AXIS_LEFT_Y = J_AXIS_MIN + AXIS_LEFT_Y,
J_AXIS_RIGHT_X = J_AXIS_MIN + AXIS_RIGHT_X,
@ -232,6 +221,12 @@ const char* Sys_GetLocalizedScancodeName( int key );
// returns keyNum_t (K_SC_* constant) for given scancode name (like "SC_A")
int Sys_GetKeynumForScancodeName( const char* name );
// returns display name of the key (between K_FIRST_JOY and K_LAST_JOY)
// With SDL2 it'll return the name in the SDL_GameController standard layout
// (which is based on XBox/XInput => on Nintendo gamepads, A/B and X/Y will be flipped),
// with SDL3 it will return the "real" button name
const char* Sys_GetLocalizedJoyKeyName( int key );
// keyboard input polling
int Sys_PollKeyboardInputEvents( void );
int Sys_ReturnKeyboardInputEvent( const int n, int &ch, bool &state );