SDL2 Game Controller support

git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1293 af15c1b1-3010-417e-b628-4374ebc0bcbd
This commit is contained in:
Eric Wasylishen 2016-03-01 21:58:08 +00:00
parent 9c9facfe7b
commit dc2218b9c8
12 changed files with 501 additions and 26 deletions

View file

@ -93,6 +93,14 @@ bind MOUSE1 +attack
bind MOUSE2 +jump bind MOUSE2 +jump
//bind MOUSE3 +mlook //bind MOUSE3 +mlook
//
// game controller
//
bind LSHOULDER "impulse 12"
bind RSHOULDER "impulse 10"
bind LTRIGGER +jump
bind RTRIGGER +attack
// //
// default cvars // default cvars
// //

View file

@ -701,10 +701,10 @@ void GL_SetCanvas (canvastype newcanvas)
glViewport (glx, gly, glwidth, glheight); glViewport (glx, gly, glwidth, glheight);
break; break;
case CANVAS_MENU: case CANVAS_MENU:
s = q_min((float)glwidth / 320.0, (float)glheight / 200.0); s = q_min((float)glwidth / 640.0, (float)glheight / 200.0); // ericw -- doubled width to 640 to accommodate long keybindings
s = CLAMP (1.0, scr_menuscale.value, s); s = CLAMP (1.0, scr_menuscale.value, s);
glOrtho (0, 320, 200, 0, -99999, 99999); glOrtho (0, 640, 200, 0, -99999, 99999);
glViewport (glx + (glwidth - 320*s) / 2, gly + (glheight - 200*s) / 2, 320*s, 200*s); glViewport (glx + (glwidth - 320*s) / 2, gly + (glheight - 200*s) / 2, 640*s, 200*s);
break; break;
case CANVAS_SBAR: case CANVAS_SBAR:
s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);

View file

@ -924,6 +924,8 @@ int SCR_ModalMessage (const char *text, float timeout) //johnfitz -- timeout
} while (lastchar != 'y' && lastchar != 'Y' && } while (lastchar != 'y' && lastchar != 'Y' &&
lastchar != 'n' && lastchar != 'N' && lastchar != 'n' && lastchar != 'N' &&
lastkey != K_ESCAPE && lastkey != K_ESCAPE &&
lastkey != K_ABUTTON &&
lastkey != K_BBUTTON &&
time2 <= time1); time2 <= time1);
Key_EndInputGrab (); Key_EndInputGrab ();
@ -934,7 +936,7 @@ int SCR_ModalMessage (const char *text, float timeout) //johnfitz -- timeout
return false; return false;
//johnfitz //johnfitz
return (lastchar == 'y' || lastchar == 'Y'); return (lastchar == 'y' || lastchar == 'Y' || lastkey == K_ABUTTON);
} }

View file

@ -1951,6 +1951,7 @@ static void VID_MenuKey (int key)
switch (key) switch (key)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
VID_SyncCvars (); //sync cvars before leaving menu. FIXME: there are other ways to leave menu VID_SyncCvars (); //sync cvars before leaving menu. FIXME: there are other ways to leave menu
S_LocalSound ("misc/menu1.wav"); S_LocalSound ("misc/menu1.wav");
M_Menu_Options_f (); M_Menu_Options_f ();
@ -2014,6 +2015,7 @@ static void VID_MenuKey (int key)
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
m_entersound = true; m_entersound = true;
switch (video_options_cursor) switch (video_options_cursor)
{ {

View file

@ -48,6 +48,21 @@ static cvar_t in_debugkeys = {"in_debugkeys", "0", CVAR_NONE};
#include <IOKit/hidsystem/event_status_driver.h> #include <IOKit/hidsystem/event_status_driver.h>
#endif #endif
// SDL2 Game Controller cvars
cvar_t joy_deadzone = { "joy_deadzone", "0.2", CVAR_NONE };
cvar_t joy_deadzone_trigger = { "joy_deadzone_trigger", "0.001", CVAR_NONE };
cvar_t joy_sensitivity_yaw = { "joy_sensitivity_yaw", "300", CVAR_NONE };
cvar_t joy_sensitivity_pitch = { "joy_sensitivity_pitch", "150", CVAR_NONE };
cvar_t joy_invert = { "joy_invert", "0", CVAR_NONE };
cvar_t joy_exponent = { "joy_exponent", "3", CVAR_NONE };
cvar_t joy_swapmovelook = { "joy_swapmovelook", "0", CVAR_NONE };
cvar_t joy_enable = { "joy_enable", "1", CVAR_NONE };
#if defined(USE_SDL2)
static SDL_JoystickID joy_active_instaceid = -1;
static SDL_GameController *joy_active_controller = NULL;
#endif
static qboolean no_mouse = false; static qboolean no_mouse = false;
static int buttonremap[] = static int buttonremap[] =
@ -257,6 +272,63 @@ void IN_Deactivate (qboolean free_cursor)
IN_BeginIgnoringMouseEvents(); IN_BeginIgnoringMouseEvents();
} }
void IN_StartupJoystick (void)
{
#if defined(USE_SDL2)
int i;
int nummappings;
char controllerdb[MAX_OSPATH];
SDL_GameController *gamecontroller;
if (COM_CheckParm("-nojoy"))
return;
// Load additional SDL2 controller definitions from gamecontrollerdb.txt
q_snprintf (controllerdb, sizeof(controllerdb), "%s/gamecontrollerdb.txt", com_basedir);
nummappings = SDL_GameControllerAddMappingsFromFile(controllerdb);
if (nummappings)
Con_Printf("%d mappings loaded from gamecontrollerdb.txt\n", nummappings);
// Also try host_parms->userdir
if (host_parms->userdir != host_parms->basedir)
{
q_snprintf (controllerdb, sizeof(controllerdb), "%s/gamecontrollerdb.txt", host_parms->userdir);
nummappings = SDL_GameControllerAddMappingsFromFile(controllerdb);
if (nummappings)
Con_Printf("%d mappings loaded from gamecontrollerdb.txt\n", nummappings);
}
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1 )
{
Con_Printf("WARNING: Could not initialize SDL Game Controller\n");
return;
}
for (i = 0; i < SDL_NumJoysticks(); i++)
{
if ( SDL_IsGameController(i) )
{
gamecontroller = SDL_GameControllerOpen(i);
if (gamecontroller)
{
Con_Printf("detected controller: %s\n", SDL_GameControllerNameForIndex(i));
joy_active_instaceid = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller));
joy_active_controller = gamecontroller;
break;
}
}
}
#endif
}
void IN_ShutdownJoystick (void)
{
#if defined(USE_SDL2)
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
#endif
}
void IN_Init (void) void IN_Init (void)
{ {
textmode = Key_TextEntry(); textmode = Key_TextEntry();
@ -282,31 +354,328 @@ void IN_Init (void)
Cvar_RegisterVariable(&in_disablemacosxmouseaccel); Cvar_RegisterVariable(&in_disablemacosxmouseaccel);
#endif #endif
Cvar_RegisterVariable(&in_debugkeys); Cvar_RegisterVariable(&in_debugkeys);
Cvar_RegisterVariable(&joy_sensitivity_yaw);
Cvar_RegisterVariable(&joy_sensitivity_pitch);
Cvar_RegisterVariable(&joy_deadzone);
Cvar_RegisterVariable(&joy_deadzone_trigger);
Cvar_RegisterVariable(&joy_invert);
Cvar_RegisterVariable(&joy_exponent);
Cvar_RegisterVariable(&joy_swapmovelook);
Cvar_RegisterVariable(&joy_enable);
IN_Activate(); IN_Activate();
IN_StartupJoystick();
} }
void IN_Shutdown (void) void IN_Shutdown (void)
{ {
IN_Deactivate(true); IN_Deactivate(true);
} IN_ShutdownJoystick();
void IN_Commands (void)
{
/* TODO: implement this for joystick support */
} }
extern cvar_t cl_maxpitch; /* johnfitz -- variable pitch clamping */ extern cvar_t cl_maxpitch; /* johnfitz -- variable pitch clamping */
extern cvar_t cl_minpitch; /* johnfitz -- variable pitch clamping */ extern cvar_t cl_minpitch; /* johnfitz -- variable pitch clamping */
void IN_MouseMove(int dx, int dy) void IN_MouseMotion(int dx, int dy)
{ {
total_dx += dx; total_dx += dx;
total_dy += dy; total_dy += dy;
} }
void IN_Move (usercmd_t *cmd) #if defined(USE_SDL2)
typedef struct joyaxis_s
{
float x;
float y;
} joyaxis_t;
typedef struct joy_buttonstate_s
{
qboolean buttondown[SDL_CONTROLLER_BUTTON_MAX];
} joybuttonstate_t;
typedef struct axisstate_s
{
float axisvalue[SDL_CONTROLLER_AXIS_MAX]; // normalized to +-1
} joyaxisstate_t;
static joybuttonstate_t joy_buttonstate;
static joyaxisstate_t joy_axisstate;
static double joy_buttontimer[SDL_CONTROLLER_BUTTON_MAX];
static double joy_emulatedkeytimer[10];
/*
================
IN_ApplyEasing
assumes axis values are in [-1, 1]. Raises the axis values to the given exponent, keeping signs.
================
*/
static joyaxis_t IN_ApplyEasing(joyaxis_t axis, float exponent)
{
joyaxis_t result = {0};
float magnitude, eased_magnitude;
magnitude = sqrtf( (axis.x * axis.x) + (axis.y * axis.y) );
if (magnitude > 1)
magnitude = 1;
if (magnitude == 0)
return result;
eased_magnitude = powf(magnitude, exponent);
result.x = axis.x * (eased_magnitude / magnitude);
result.y = axis.y * (eased_magnitude / magnitude);
return result;
}
/*
================
IN_ApplyMoveEasing
clamps coordinates to a square with coordinates +/- sqrt(2)/2, then scales them to +/- 1.
This wastes a bit of stick range, but gives the diagonals coordinates of (+/-1,+/-1),
so holding the stick on a diagonal gives the same speed boost as holding the forward and strafe keyboard keys.
================
*/
static joyaxis_t IN_ApplyMoveEasing(joyaxis_t axis)
{
joyaxis_t result = {0};
const float v = sqrtf(2.0f) / 2.0f;
result.x = q_max(-v, q_min(v, axis.x));
result.y = q_max(-v, q_min(v, axis.y));
result.x /= v;
result.y /= v;
return result;
}
/*
================
IN_ApplyDeadzone
from https://github.com/jeremiah-sypult/Quakespasm-Rift
and adapted from http://www.third-helix.com/2013/04/12/doing-thumbstick-dead-zones-right.html
================
*/
static joyaxis_t IN_ApplyDeadzone(joyaxis_t axis, float deadzone)
{
joyaxis_t result = {0};
float magnitude = sqrtf( (axis.x * axis.x) + (axis.y * axis.y) );
if ( magnitude < deadzone ) {
result.x = result.y = 0.0f;
} else {
joyaxis_t normalized;
float gradient;
if ( magnitude > 1.0f ) {
magnitude = 1.0f;
}
normalized.x = axis.x / magnitude;
normalized.y = axis.y / magnitude;
gradient = ( (magnitude - deadzone) / (1.0f - deadzone) );
result.x = normalized.x * gradient;
result.y = normalized.y * gradient;
}
return result;
}
/*
================
IN_KeyForControllerButton
================
*/
static int IN_KeyForControllerButton(SDL_GameControllerButton button)
{
switch (button)
{
case SDL_CONTROLLER_BUTTON_A: return K_ABUTTON;
case SDL_CONTROLLER_BUTTON_B: return K_BBUTTON;
case SDL_CONTROLLER_BUTTON_X: return K_XBUTTON;
case SDL_CONTROLLER_BUTTON_Y: return K_YBUTTON;
case SDL_CONTROLLER_BUTTON_BACK: return K_TAB;
case SDL_CONTROLLER_BUTTON_START: return K_ESCAPE;
case SDL_CONTROLLER_BUTTON_LEFTSTICK: return K_LTHUMB;
case SDL_CONTROLLER_BUTTON_RIGHTSTICK: return K_RTHUMB;
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return K_LSHOULDER;
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return K_RSHOULDER;
case SDL_CONTROLLER_BUTTON_DPAD_UP: return K_UPARROW;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return K_DOWNARROW;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return K_LEFTARROW;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return K_RIGHTARROW;
default: return 0;
}
}
/*
================
IN_JoyKeyEvent
Sends a Key_Event if a unpressed -> pressed or pressed -> unpressed transition occurred,
and generates key repeats if the button is held down.
Adapted from DarkPlaces by lordhavoc
================
*/
static void IN_JoyKeyEvent(qboolean wasdown, qboolean isdown, int key, double *timer)
{
// we can't use `realtime` for key repeats because it is not monotomic
const double currenttime = Sys_DoubleTime();
if (wasdown)
{
if (isdown)
{
if (currenttime >= *timer)
{
*timer = currenttime + 0.1;
Key_Event(key, true);
}
}
else
{
*timer = 0;
Key_Event(key, false);
}
}
else
{
if (isdown)
{
*timer = currenttime + 0.5;
Key_Event(key, true);
}
}
}
#endif
/*
================
IN_Commands
Emit key events for game controller buttons, including emulated buttons for analog sticks/triggers
================
*/
void IN_Commands (void)
{
#if defined(USE_SDL2)
joyaxisstate_t newaxisstate;
int i;
const float stickthreshold = 0.9;
const float triggerthreshold = joy_deadzone_trigger.value;
if (!joy_enable.value)
return;
if (!joy_active_controller)
return;
// emit key events for controller buttons
for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++)
{
qboolean newstate = SDL_GameControllerGetButton(joy_active_controller, i);
qboolean oldstate = joy_buttonstate.buttondown[i];
joy_buttonstate.buttondown[i] = newstate;
// NOTE: This can cause a reentrant call of IN_Commands, via SCR_ModalMessage when confirming a new game.
IN_JoyKeyEvent(oldstate, newstate, IN_KeyForControllerButton(i), &joy_buttontimer[i]);
}
for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++)
{
newaxisstate.axisvalue[i] = SDL_GameControllerGetAxis(joy_active_controller, i) / 32768.0f;
}
// emit emulated arrow keys so the analog sticks can be used in the menu
if (key_dest != key_game)
{
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX] < -stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX] < -stickthreshold, K_LEFTARROW, &joy_emulatedkeytimer[0]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX] > stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX] > stickthreshold, K_RIGHTARROW, &joy_emulatedkeytimer[1]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY] < -stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY] < -stickthreshold, K_UPARROW, &joy_emulatedkeytimer[2]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY] > stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY] > stickthreshold, K_DOWNARROW, &joy_emulatedkeytimer[3]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTX] < -stickthreshold,newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTX] < -stickthreshold, K_LEFTARROW, &joy_emulatedkeytimer[4]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTX] > stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTX] > stickthreshold, K_RIGHTARROW, &joy_emulatedkeytimer[5]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTY] < -stickthreshold,newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTY] < -stickthreshold, K_UPARROW, &joy_emulatedkeytimer[6]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTY] > stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTY] > stickthreshold, K_DOWNARROW, &joy_emulatedkeytimer[7]);
}
// emit emulated keys for the analog triggers
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERLEFT] > triggerthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERLEFT] > triggerthreshold, K_LTRIGGER, &joy_emulatedkeytimer[8]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] > triggerthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] > triggerthreshold, K_RTRIGGER, &joy_emulatedkeytimer[9]);
joy_axisstate = newaxisstate;
#endif
}
/*
================
IN_JoyMove
================
*/
void IN_JoyMove (usercmd_t *cmd)
{
#if defined(USE_SDL2)
float speed;
joyaxis_t moveAxis, lookAxis;
if (!joy_enable.value)
return;
if (!joy_active_controller)
return;
moveAxis.x = joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX];
moveAxis.y = joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY];
lookAxis.x = joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTX];
lookAxis.y = joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_RIGHTY];
if (joy_swapmovelook.value)
{
joyaxis_t temp = moveAxis;
moveAxis = lookAxis;
lookAxis = temp;
}
moveAxis = IN_ApplyDeadzone(moveAxis, joy_deadzone.value);
lookAxis = IN_ApplyDeadzone(lookAxis, joy_deadzone.value);
moveAxis = IN_ApplyMoveEasing(moveAxis);
lookAxis = IN_ApplyEasing(lookAxis, joy_exponent.value);
if (in_speed.state & 1)
speed = cl_movespeedkey.value;
else
speed = 1;
cmd->sidemove += (cl_sidespeed.value * speed * moveAxis.x);
cmd->forwardmove -= (cl_forwardspeed.value * speed * moveAxis.y);
cl.viewangles[YAW] -= lookAxis.x * joy_sensitivity_yaw.value * host_frametime;
cl.viewangles[PITCH] += lookAxis.y * joy_sensitivity_pitch.value * (joy_invert.value ? -1.0 : 1.0) * host_frametime;
if (lookAxis.x != 0 || lookAxis.y != 0)
V_StopPitchDrift();
/* johnfitz -- variable pitch clamping */
if (cl.viewangles[PITCH] > cl_maxpitch.value)
cl.viewangles[PITCH] = cl_maxpitch.value;
if (cl.viewangles[PITCH] < cl_minpitch.value)
cl.viewangles[PITCH] = cl_minpitch.value;
#endif
}
void IN_MouseMove(usercmd_t *cmd)
{ {
int dmx, dmy; int dmx, dmy;
@ -345,6 +714,12 @@ void IN_Move (usercmd_t *cmd)
} }
} }
void IN_Move(usercmd_t *cmd)
{
IN_JoyMove(cmd);
IN_MouseMove(cmd);
}
void IN_ClearStates (void) void IN_ClearStates (void)
{ {
} }
@ -682,9 +1057,41 @@ void IN_SendKeyEvents (void)
#endif #endif
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
IN_MouseMove(event.motion.xrel, event.motion.yrel); IN_MouseMotion(event.motion.xrel, event.motion.yrel);
break; break;
#if defined(USE_SDL2)
case SDL_CONTROLLERDEVICEADDED:
if (joy_active_instaceid == -1)
{
joy_active_controller = SDL_GameControllerOpen(event.cdevice.which);
if (joy_active_controller == NULL)
Con_DPrintf("Couldn't open game controller\n");
else
{
SDL_Joystick *joy;
joy = SDL_GameControllerGetJoystick(joy_active_controller);
joy_active_instaceid = SDL_JoystickInstanceID(joy);
}
}
else
Con_DPrintf("Ignoring SDL_CONTROLLERDEVICEADDED\n");
break;
case SDL_CONTROLLERDEVICEREMOVED:
if (joy_active_instaceid != -1 && event.cdevice.which == joy_active_instaceid)
{
SDL_GameControllerClose(joy_active_controller);
joy_active_controller = NULL;
joy_active_instaceid = -1;
}
else
Con_DPrintf("Ignoring SDL_CONTROLLERDEVICEREMOVED\n");
break;
case SDL_CONTROLLERDEVICEREMAPPED:
Con_DPrintf("Ignoring SDL_CONTROLLERDEVICEREMAPPED\n");
break;
#endif
case SDL_QUIT: case SDL_QUIT:
CL_Disconnect (); CL_Disconnect ();
Sys_Quit (); Sys_Quit ();

View file

@ -32,7 +32,7 @@ void IN_Commands (void);
// oportunity for devices to stick commands on the script buffer // oportunity for devices to stick commands on the script buffer
// mouse moved by dx and dy pixels // mouse moved by dx and dy pixels
void IN_MouseMove(int dx, int dy); void IN_MouseMotion(int dx, int dy);
void IN_SendKeyEvents (void); void IN_SendKeyEvents (void);

View file

@ -40,8 +40,6 @@ int history_line = 0;
keydest_t key_dest; keydest_t key_dest;
#define MAX_KEYS 256
char *keybindings[MAX_KEYS]; char *keybindings[MAX_KEYS];
qboolean consolekeys[MAX_KEYS]; // if true, can't be rebound while in console qboolean consolekeys[MAX_KEYS]; // if true, can't be rebound while in console
qboolean menubound[MAX_KEYS]; // if true, can't be rebound while in menu qboolean menubound[MAX_KEYS]; // if true, can't be rebound while in menu
@ -163,6 +161,17 @@ keyname_t keynames[] =
{"BACKQUOTE", '`'}, // because a raw backquote may toggle the console {"BACKQUOTE", '`'}, // because a raw backquote may toggle the console
{"TILDE", '~'}, // because a raw tilde may toggle the console {"TILDE", '~'}, // because a raw tilde may toggle the console
{"LTHUMB", K_LTHUMB},
{"RTHUMB", K_RTHUMB},
{"LSHOULDER", K_LSHOULDER},
{"RSHOULDER", K_RSHOULDER},
{"ABUTTON", K_ABUTTON},
{"BBUTTON", K_BBUTTON},
{"XBUTTON", K_XBUTTON},
{"YBUTTON", K_YBUTTON},
{"LTRIGGER", K_LTRIGGER},
{"RTRIGGER", K_RTRIGGER},
{NULL, 0} {NULL, 0}
}; };

View file

@ -142,13 +142,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define K_MOUSE4 241 #define K_MOUSE4 241
#define K_MOUSE5 242 #define K_MOUSE5 242
// SDL2 game controller keys
#define K_LTHUMB 243
#define K_RTHUMB 244
#define K_LSHOULDER 245
#define K_RSHOULDER 246
#define K_ABUTTON 247
#define K_BBUTTON 248
#define K_XBUTTON 249
#define K_YBUTTON 250
#define K_LTRIGGER 251
#define K_RTRIGGER 252
#define MAX_KEYS 253
#define MAXCMDLINE 256 #define MAXCMDLINE 256
typedef enum {key_game, key_console, key_message, key_menu} keydest_t; typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
extern keydest_t key_dest; extern keydest_t key_dest;
extern char *keybindings[256]; extern char *keybindings[MAX_KEYS];
extern char key_lines[32][MAXCMDLINE]; extern char key_lines[32][MAXCMDLINE];
extern int edit_line; extern int edit_line;

View file

@ -276,6 +276,7 @@ void M_Main_Key (int key)
switch (key) switch (key)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
IN_Activate(); IN_Activate();
key_dest = key_game; key_dest = key_game;
m_state = m_none; m_state = m_none;
@ -300,6 +301,7 @@ void M_Main_Key (int key)
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
m_entersound = true; m_entersound = true;
switch (m_main_cursor) switch (m_main_cursor)
@ -364,6 +366,7 @@ void M_SinglePlayer_Key (int key)
switch (key) switch (key)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_Main_f (); M_Menu_Main_f ();
break; break;
@ -381,6 +384,7 @@ void M_SinglePlayer_Key (int key)
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
m_entersound = true; m_entersound = true;
switch (m_singleplayer_cursor) switch (m_singleplayer_cursor)
@ -514,11 +518,13 @@ void M_Load_Key (int k)
switch (k) switch (k)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_SinglePlayer_f (); M_Menu_SinglePlayer_f ();
break; break;
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
S_LocalSound ("misc/menu2.wav"); S_LocalSound ("misc/menu2.wav");
if (!loadable[load_cursor]) if (!loadable[load_cursor])
return; return;
@ -558,11 +564,13 @@ void M_Save_Key (int k)
switch (k) switch (k)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_SinglePlayer_f (); M_Menu_SinglePlayer_f ();
break; break;
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
m_state = m_none; m_state = m_none;
IN_Activate(); IN_Activate();
key_dest = key_game; key_dest = key_game;
@ -628,6 +636,7 @@ void M_MultiPlayer_Key (int key)
switch (key) switch (key)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_Main_f (); M_Menu_Main_f ();
break; break;
@ -645,6 +654,7 @@ void M_MultiPlayer_Key (int key)
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
m_entersound = true; m_entersound = true;
switch (m_multiplayer_cursor) switch (m_multiplayer_cursor)
{ {
@ -735,6 +745,7 @@ void M_Setup_Key (int k)
switch (k) switch (k)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_MultiPlayer_f (); M_Menu_MultiPlayer_f ();
break; break;
@ -774,6 +785,7 @@ forward:
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
if (setup_cursor == 0 || setup_cursor == 1) if (setup_cursor == 0 || setup_cursor == 1)
return; return;
@ -926,6 +938,7 @@ again:
switch (k) switch (k)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_MultiPlayer_f (); M_Menu_MultiPlayer_f ();
break; break;
@ -943,6 +956,7 @@ again:
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
m_entersound = true; m_entersound = true;
M_Menu_LanConfig_f (); M_Menu_LanConfig_f ();
break; break;
@ -1221,11 +1235,13 @@ void M_Options_Key (int k)
switch (k) switch (k)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_Main_f (); M_Menu_Main_f ();
break; break;
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
m_entersound = true; m_entersound = true;
switch (options_cursor) switch (options_cursor)
{ {
@ -1325,27 +1341,27 @@ void M_Menu_Keys_f (void)
} }
void M_FindKeysForCommand (const char *command, int *twokeys) void M_FindKeysForCommand (const char *command, int *threekeys)
{ {
int count; int count;
int j; int j;
int l; int l;
char *b; char *b;
twokeys[0] = twokeys[1] = -1; threekeys[0] = threekeys[1] = threekeys[2] = -1;
l = strlen(command); l = strlen(command);
count = 0; count = 0;
for (j = 0; j < 256; j++) for (j = 0; j < MAX_KEYS; j++)
{ {
b = keybindings[j]; b = keybindings[j];
if (!b) if (!b)
continue; continue;
if (!strncmp (b, command, l) ) if (!strncmp (b, command, l) )
{ {
twokeys[count] = j; threekeys[count] = j;
count++; count++;
if (count == 2) if (count == 3)
break; break;
} }
} }
@ -1359,7 +1375,7 @@ void M_UnbindCommand (const char *command)
l = strlen(command); l = strlen(command);
for (j = 0; j < 256; j++) for (j = 0; j < MAX_KEYS; j++)
{ {
b = keybindings[j]; b = keybindings[j];
if (!b) if (!b)
@ -1374,7 +1390,7 @@ extern qpic_t *pic_up, *pic_down;
void M_Keys_Draw (void) void M_Keys_Draw (void)
{ {
int i, x, y; int i, x, y;
int keys[2]; int keys[3];
const char *name; const char *name;
qpic_t *p; qpic_t *p;
@ -1406,8 +1422,15 @@ void M_Keys_Draw (void)
x = strlen(name) * 8; x = strlen(name) * 8;
if (keys[1] != -1) if (keys[1] != -1)
{ {
name = Key_KeynumToString (keys[1]);
M_Print (140 + x + 8, y, "or"); M_Print (140 + x + 8, y, "or");
M_Print (140 + x + 32, y, Key_KeynumToString (keys[1])); M_Print (140 + x + 32, y, name);
x = x + 32 + strlen(name) * 8;
if (keys[2] != -1)
{
M_Print (140 + x + 8, y, "or");
M_Print (140 + x + 32, y, Key_KeynumToString (keys[2]));
}
} }
} }
} }
@ -1422,7 +1445,7 @@ void M_Keys_Draw (void)
void M_Keys_Key (int k) void M_Keys_Key (int k)
{ {
char cmd[80]; char cmd[80];
int keys[2]; int keys[3];
if (bind_grab) if (bind_grab)
{ // defining a key { // defining a key
@ -1441,6 +1464,7 @@ void M_Keys_Key (int k)
switch (k) switch (k)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_Options_f (); M_Menu_Options_f ();
break; break;
@ -1462,9 +1486,10 @@ void M_Keys_Key (int k)
case K_ENTER: // go into bind mode case K_ENTER: // go into bind mode
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
M_FindKeysForCommand (bindnames[keys_cursor][0], keys); M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
S_LocalSound ("misc/menu2.wav"); S_LocalSound ("misc/menu2.wav");
if (keys[1] != -1) if (keys[2] != -1)
M_UnbindCommand (bindnames[keys_cursor][0]); M_UnbindCommand (bindnames[keys_cursor][0]);
bind_grab = true; bind_grab = true;
IN_Activate(); // activate to allow mouse key binding IN_Activate(); // activate to allow mouse key binding
@ -1527,6 +1552,7 @@ void M_Help_Key (int key)
switch (key) switch (key)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_Main_f (); M_Menu_Main_f ();
break; break;
@ -1756,6 +1782,7 @@ void M_LanConfig_Key (int key)
switch (key) switch (key)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_Net_f (); M_Menu_Net_f ();
break; break;
@ -1775,6 +1802,7 @@ void M_LanConfig_Key (int key)
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
if (lanConfig_cursor == 0) if (lanConfig_cursor == 0)
break; break;
@ -2266,6 +2294,7 @@ void M_GameOptions_Key (int key)
switch (key) switch (key)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_Net_f (); M_Menu_Net_f ();
break; break;
@ -2299,6 +2328,7 @@ void M_GameOptions_Key (int key)
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
S_LocalSound ("misc/menu2.wav"); S_LocalSound ("misc/menu2.wav");
if (gameoptions_cursor == 0) if (gameoptions_cursor == 0)
{ {
@ -2430,6 +2460,7 @@ void M_ServerList_Key (int k)
switch (k) switch (k)
{ {
case K_ESCAPE: case K_ESCAPE:
case K_BBUTTON:
M_Menu_LanConfig_f (); M_Menu_LanConfig_f ();
break; break;
@ -2455,6 +2486,7 @@ void M_ServerList_Key (int k)
case K_ENTER: case K_ENTER:
case K_KP_ENTER: case K_KP_ENTER:
case K_ABUTTON:
S_LocalSound ("misc/menu2.wav"); S_LocalSound ("misc/menu2.wav");
m_return_state = m_state; m_return_state = m_state;
m_return_onerror = true; m_return_onerror = true;

Binary file not shown.

View file

@ -469,6 +469,7 @@ void Sys_Sleep (unsigned long msecs)
void Sys_SendKeyEvents (void) void Sys_SendKeyEvents (void)
{ {
IN_Commands(); //ericw -- allow joysticks to add keys so they can be used to confirm SCR_ModalMessage
IN_SendKeyEvents(); IN_SendKeyEvents();
} }

View file

@ -436,6 +436,7 @@ void Sys_Sleep (unsigned long msecs)
void Sys_SendKeyEvents (void) void Sys_SendKeyEvents (void)
{ {
IN_Commands(); //ericw -- allow joysticks to add keys so they can be used to confirm SCR_ModalMessage
IN_SendKeyEvents(); IN_SendKeyEvents();
} }