Further gamepad improvements

- the gamepad button (or trigger) bound to attack (fire) now always
  acts like the left mouse button in menus
- Display correct button name for "Back" button on Playstation-like
  gamepads, even depending on whether it's PS3-like ("Select") or
  PS4/5-like ("Share")
- Log some more information about detected gamepads
This commit is contained in:
Daniel Gibson 2024-01-18 19:53:45 +01:00
parent e7eb7d17fe
commit 9e8d399257
3 changed files with 54 additions and 35 deletions

View file

@ -93,7 +93,7 @@ typedef enum {
UB_BUTTON6,
UB_BUTTON7,
UB_ATTACK,
UB_ATTACK, // NOTE: this value (20) is hardcoded in idUserInterfaceLocal::HandleEvent() !
UB_SPEED,
UB_ZOOM,
UB_SHOWSCORES,

View file

@ -81,7 +81,7 @@ static idCVar in_grabKeyboard("in_grabKeyboard", "0", CVAR_SYSTEM | CVAR_ARCHIVE
"if enabled, grabs all keyboard input if mouse is grabbed (so keyboard shortcuts from the OS like Alt-Tab or Windows Key won't work)");
idCVar joy_gamepadLayout("joy_gamepadLayout", "-1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_INTEGER,
"Button layout of gamepad - -1: auto (needs SDL 2.0.12 or newer), 0: XBox-style, 1: Nintendo-style, 2: Playstation-style", idCmdSystem::ArgCompletion_Integer<-1, 2> );
"Button layout of gamepad. -1: auto (needs SDL 2.0.12 or newer), 0: XBox-style, 1: Nintendo-style, 2: PS4/5-style, 3: PS2/3-style", idCmdSystem::ArgCompletion_Integer<-1, 3> );
// set in handleMouseGrab(), used in Sys_GetEvent() to decide what kind of internal mouse event to generate
static bool in_relativeMouseMode = true;
@ -91,7 +91,8 @@ static bool in_hasFocus = true;
static enum D3_Gamepad_Type {
D3_GAMEPAD_XINPUT, // XBox/XInput standard, the default
D3_GAMEPAD_NINTENDO, // nintendo-like (A/B and X/Y are switched)
D3_GAMEPAD_PLAYSTATION // PS-like (geometric symbols instead of A/B/X/Y)
D3_GAMEPAD_PLAYSTATION, // PS-like (geometric symbols instead of A/B/X/Y)
D3_GAMEPAD_PLAYSTATION_OLD // PS2/PS3-like: the back button is called "select" instead of "share"
} gamepadType = D3_GAMEPAD_XINPUT;
struct kbd_poll_t {
@ -310,8 +311,7 @@ const char* Sys_GetLocalizedJoyKeyName( int key ) {
// South, East, West, North Back
static const char* xboxBtnNames[5] = { "Pad A", "Pad B", "Pad X", "Pad Y", "Pad Back" };
static const char* nintendoBtnNames[5] = { "Pad B", "Pad A", "Pad Y", "Pad X", "Pad -" };
// TODO: on PS3 and older, back is "Select"; on PS4+ back it might be "share"?
static const char* psBtnNames[5] = { "Pad Cross", "Pad Circle", "Pad Square", "Pad Triangle", "Pad Select" };
static const char* psBtnNames[5] = { "Pad Cross", "Pad Circle", "Pad Square", "Pad Triangle", "Pad Share" };
int layout = joy_gamepadLayout.GetInteger();
if ( layout == -1 ) {
@ -329,6 +329,11 @@ const char* Sys_GetLocalizedJoyKeyName( int key ) {
return xboxBtnNames[btnIdx];
case D3_GAMEPAD_NINTENDO:
return nintendoBtnNames[btnIdx];
case D3_GAMEPAD_PLAYSTATION_OLD:
if ( key == K_JOY_BTN_BACK )
return "Pad Select";
// the other button names are identical for PS2/3 and PS4/5
// fall-through
case D3_GAMEPAD_PLAYSTATION:
return psBtnNames[btnIdx];
}
@ -764,6 +769,9 @@ static void setGamepadType( SDL_GameController* gc )
break;
case SDL_CONTROLLER_TYPE_PS3:
gamepadType = D3_GAMEPAD_PLAYSTATION_OLD;
typestr = "Playstation2/3-like";
break;
case SDL_CONTROLLER_TYPE_PS4:
case SDL_CONTROLLER_TYPE_PS5:
gamepadType = D3_GAMEPAD_PLAYSTATION;
@ -772,6 +780,15 @@ static void setGamepadType( SDL_GameController* gc )
}
common->Printf( "Detected Gamepad %s as type %s\n", SDL_GameControllerName( gc ), typestr );
SDL_Joystick* joy = SDL_GameControllerGetJoystick( gc );
SDL_JoystickGUID guid = SDL_JoystickGetGUID( joy );
char guidstr[34] = {};
SDL_JoystickGetGUIDString( guid, guidstr, sizeof(guidstr) );
Uint16 vendor = SDL_GameControllerGetVendor( gc );
Uint16 product = SDL_GameControllerGetProduct( gc );
const char* joyname = SDL_JoystickName( joy );
common->Printf( " USB IDs: %.4hx:%.4hx Joystick Name: \"%s\" GUID: %s\n", vendor, product, joyname, guidstr );
#endif // SDL_VERSION_ATLEAST(2, 0, 12)
}

View file

@ -442,36 +442,38 @@ const char *idUserInterfaceLocal::HandleEvent( const sysEvent_t *event, int _tim
{
// map some gamepad buttons to SE_KEY events that the UI already knows how to use
int key = 0;
switch(event->evValue) {
// emulate mouse buttons
case K_JOY_TRIGGER2:
// the right trigger is often used for shooting, so for ingame UIs
// it'll behave like mouseclick - do the same in menus
// fall-through
case K_JOY_BTN_SOUTH: // A on xbox controller
key = K_MOUSE1;
break;
case K_JOY_BTN_EAST: // B on xbox controller
key = K_MOUSE2;
break;
// emulate cursor keys (sometimes used for scrolling or selecting in a list)
case K_JOY_DPAD_UP:
key = K_UPARROW;
break;
case K_JOY_DPAD_DOWN:
key = K_DOWNARROW;
break;
case K_JOY_DPAD_LEFT:
key = K_LEFTARROW;
break;
case K_JOY_DPAD_RIGHT:
key = K_RIGHTARROW;
break;
// enter is useful after selecting something with cursor keys (or dpad)
// in a list, like selecting a savegame - I guess left trigger is suitable for that?
case K_JOY_TRIGGER1:
key = K_ENTER;
break;
if( idKeyInput::GetUsercmdAction( event->evValue ) == 20 /* UB_ATTACK*/ ) {
// if this button is bound to _attack (fire), treat it as left mouse button
key = K_MOUSE1;
} else {
switch(event->evValue) {
// emulate mouse buttons
case K_JOY_BTN_SOUTH: // A on xbox controller
key = K_MOUSE1;
break;
case K_JOY_BTN_EAST: // B on xbox controller
key = K_MOUSE2;
break;
// emulate cursor keys (sometimes used for scrolling or selecting in a list)
case K_JOY_DPAD_UP:
key = K_UPARROW;
break;
case K_JOY_DPAD_DOWN:
key = K_DOWNARROW;
break;
case K_JOY_DPAD_LEFT:
key = K_LEFTARROW;
break;
case K_JOY_DPAD_RIGHT:
key = K_RIGHTARROW;
break;
// enter is useful after selecting something with cursor keys (or dpad)
// in a list, like selecting a savegame - I guess left trigger is suitable for that?
// (right trigger is often used for shooting, which we use as K_MOUSE1 here)
case K_JOY_TRIGGER1:
key = K_ENTER;
break;
}
}
if (key != 0) {
fakedEvent = *event;