[iortcw] 96/152: All: Better gamepad support
Simon McVittie
smcv at debian.org
Fri Sep 8 10:40:17 UTC 2017
This is an automated email from the git hooks/post-receive script.
smcv pushed a commit to annotated tag 1.5a
in repository iortcw.
commit 83c804e4a623cb667e557e620caecbef4cafe756
Author: MAN-AT-ARMS <M4N4T4RMS at gmail.com>
Date: Sun Aug 14 21:25:52 2016 -0400
All: Better gamepad support
---
MP/code/client/cl_input.c | 24 +++--
MP/code/client/cl_keys.c | 27 ++++++
MP/code/client/keycodes.h | 30 +++++++
MP/code/sdl/sdl_input.c | 225 +++++++++++++++++++++++++++++++++++++++++++++-
SP/code/client/cl_input.c | 24 +++--
SP/code/client/cl_keys.c | 27 ++++++
SP/code/client/keycodes.h | 30 +++++++
SP/code/sdl/sdl_input.c | 225 +++++++++++++++++++++++++++++++++++++++++++++-
8 files changed, 590 insertions(+), 22 deletions(-)
diff --git a/MP/code/client/cl_input.c b/MP/code/client/cl_input.c
index 04bf4ce..1b05aa0 100644
--- a/MP/code/client/cl_input.c
+++ b/MP/code/client/cl_input.c
@@ -463,6 +463,12 @@ CL_JoystickMove
void CL_JoystickMove( usercmd_t *cmd ) {
float anglespeed;
+ float yaw = j_yaw->value * cl.joystickAxis[j_yaw_axis->integer];
+ float right = j_side->value * cl.joystickAxis[j_side_axis->integer];
+ float forward = j_forward->value * cl.joystickAxis[j_forward_axis->integer];
+ float pitch = j_pitch->value * cl.joystickAxis[j_pitch_axis->integer];
+ float up = j_up->value * cl.joystickAxis[j_up_axis->integer];
+
if ( !( kb[KB_SPEED].active ^ cl_run->integer ) ) {
cmd->buttons |= BUTTON_WALKING;
}
@@ -474,21 +480,21 @@ void CL_JoystickMove( usercmd_t *cmd ) {
}
if ( !kb[KB_STRAFE].active ) {
- cl.viewangles[YAW] += anglespeed * j_yaw->value * cl.joystickAxis[j_yaw_axis->integer];
- cmd->rightmove = ClampChar( cmd->rightmove + (int) (j_side->value * cl.joystickAxis[j_side_axis->integer]) );
+ cl.viewangles[YAW] += anglespeed * yaw;
+ cmd->rightmove = ClampChar( cmd->rightmove + (int)right );
} else {
- cl.viewangles[YAW] += anglespeed * j_side->value * cl.joystickAxis[j_side_axis->integer];
- cmd->rightmove = ClampChar( cmd->rightmove + (int) (j_yaw->value * cl.joystickAxis[j_yaw_axis->integer]) );
+ cl.viewangles[YAW] += anglespeed * right;
+ cmd->rightmove = ClampChar( cmd->rightmove + (int)yaw );
}
if ( kb[KB_MLOOK].active ) {
- cl.viewangles[PITCH] += anglespeed * j_forward->value * cl.joystickAxis[j_forward_axis->integer];
- cmd->forwardmove = ClampChar( cmd->forwardmove + (int) (j_pitch->value * cl.joystickAxis[j_pitch_axis->integer]) );
+ cl.viewangles[PITCH] += anglespeed * forward;
+ cmd->forwardmove = ClampChar( cmd->forwardmove + (int)pitch );
} else {
- cl.viewangles[PITCH] += anglespeed * j_pitch->value * cl.joystickAxis[j_pitch_axis->integer];
- cmd->forwardmove = ClampChar( cmd->forwardmove + (int) (j_forward->value * cl.joystickAxis[j_forward_axis->integer]) );
+ cl.viewangles[PITCH] += anglespeed * pitch;
+ cmd->forwardmove = ClampChar( cmd->forwardmove + (int)forward );
}
- cmd->upmove = ClampChar( cmd->upmove + (int) (j_up->value * cl.joystickAxis[j_up_axis->integer]) );
+ cmd->upmove = ClampChar( cmd->upmove + (int)up );
}
/*
diff --git a/MP/code/client/cl_keys.c b/MP/code/client/cl_keys.c
index 985b82c..1dceb5f 100644
--- a/MP/code/client/cl_keys.c
+++ b/MP/code/client/cl_keys.c
@@ -298,6 +298,33 @@ keyname_t keynames[] =
{"EURO", K_EURO},
{"UNDO", K_UNDO},
+ {"PAD0_A", K_PAD0_A },
+ {"PAD0_B", K_PAD0_B },
+ {"PAD0_X", K_PAD0_X },
+ {"PAD0_Y", K_PAD0_Y },
+ {"PAD0_BACK", K_PAD0_BACK },
+ {"PAD0_GUIDE", K_PAD0_GUIDE },
+ {"PAD0_START", K_PAD0_START },
+ {"PAD0_LEFTSTICK_CLICK", K_PAD0_LEFTSTICK_CLICK },
+ {"PAD0_RIGHTSTICK_CLICK", K_PAD0_RIGHTSTICK_CLICK },
+ {"PAD0_LEFTSHOULDER", K_PAD0_LEFTSHOULDER },
+ {"PAD0_RIGHTSHOULDER", K_PAD0_RIGHTSHOULDER },
+ {"PAD0_DPAD_UP", K_PAD0_DPAD_UP },
+ {"PAD0_DPAD_DOWN", K_PAD0_DPAD_DOWN },
+ {"PAD0_DPAD_LEFT", K_PAD0_DPAD_LEFT },
+ {"PAD0_DPAD_RIGHT", K_PAD0_DPAD_RIGHT },
+
+ {"PAD0_LEFTSTICK_LEFT", K_PAD0_LEFTSTICK_LEFT },
+ {"PAD0_LEFTSTICK_RIGHT", K_PAD0_LEFTSTICK_RIGHT },
+ {"PAD0_LEFTSTICK_UP", K_PAD0_LEFTSTICK_UP },
+ {"PAD0_LEFTSTICK_DOWN", K_PAD0_LEFTSTICK_DOWN },
+ {"PAD0_RIGHTSTICK_LEFT", K_PAD0_RIGHTSTICK_LEFT },
+ {"PAD0_RIGHTSTICK_RIGHT", K_PAD0_RIGHTSTICK_RIGHT },
+ {"PAD0_RIGHTSTICK_UP", K_PAD0_RIGHTSTICK_UP },
+ {"PAD0_RIGHTSTICK_DOWN", K_PAD0_RIGHTSTICK_DOWN },
+ {"PAD0_LEFTTRIGGER", K_PAD0_LEFTTRIGGER },
+ {"PAD0_RIGHTTRIGGER", K_PAD0_RIGHTTRIGGER },
+
{NULL,0}
};
diff --git a/MP/code/client/keycodes.h b/MP/code/client/keycodes.h
index 320687e..bde0eeb 100644
--- a/MP/code/client/keycodes.h
+++ b/MP/code/client/keycodes.h
@@ -266,6 +266,36 @@ typedef enum {
K_EURO,
K_UNDO,
+ // Gamepad controls
+ // Ordered to match SDL2 game controller buttons and axes
+ // Do not change this order without also changing IN_GamepadMove() in SDL_input.c
+ K_PAD0_A,
+ K_PAD0_B,
+ K_PAD0_X,
+ K_PAD0_Y,
+ K_PAD0_BACK,
+ K_PAD0_GUIDE,
+ K_PAD0_START,
+ K_PAD0_LEFTSTICK_CLICK,
+ K_PAD0_RIGHTSTICK_CLICK,
+ K_PAD0_LEFTSHOULDER,
+ K_PAD0_RIGHTSHOULDER,
+ K_PAD0_DPAD_UP,
+ K_PAD0_DPAD_DOWN,
+ K_PAD0_DPAD_LEFT,
+ K_PAD0_DPAD_RIGHT,
+
+ K_PAD0_LEFTSTICK_LEFT,
+ K_PAD0_LEFTSTICK_RIGHT,
+ K_PAD0_LEFTSTICK_UP,
+ K_PAD0_LEFTSTICK_DOWN,
+ K_PAD0_RIGHTSTICK_LEFT,
+ K_PAD0_RIGHTSTICK_RIGHT,
+ K_PAD0_RIGHTSTICK_UP,
+ K_PAD0_RIGHTSTICK_DOWN,
+ K_PAD0_LEFTTRIGGER,
+ K_PAD0_RIGHTTRIGGER,
+
// Pseudo-key that brings the console down
K_CONSOLE,
diff --git a/MP/code/sdl/sdl_input.c b/MP/code/sdl/sdl_input.c
index 4991095..887bff7 100644
--- a/MP/code/sdl/sdl_input.c
+++ b/MP/code/sdl/sdl_input.c
@@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
static cvar_t *in_keyboardDebug = NULL;
+static SDL_GameController *gamepad = NULL;
static SDL_Joystick *stick = NULL;
static qboolean mouseAvailable = qfalse;
@@ -410,7 +411,7 @@ static int hat_keys[16] = {
struct
{
- qboolean buttons[16]; // !!! FIXME: these might be too many.
+ qboolean buttons[SDL_CONTROLLER_BUTTON_MAX + 1]; // +1 because old max was 16, current SDL_CONTROLLER_BUTTON_MAX is 15
unsigned int oldaxes;
int oldaaxes[MAX_JOYSTICK_AXIS];
unsigned int oldhats;
@@ -428,10 +429,14 @@ static void IN_InitJoystick( void )
int total = 0;
char buf[16384] = "";
+ if (gamepad)
+ SDL_GameControllerClose(gamepad);
+
if (stick != NULL)
SDL_JoystickClose(stick);
stick = NULL;
+ gamepad = NULL;
memset(&stick_state, '\0', sizeof (stick_state));
if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER))
@@ -476,6 +481,9 @@ static void IN_InitJoystick( void )
return;
}
+ if (SDL_IsGameController(in_joystickNo->integer))
+ gamepad = SDL_GameControllerOpen(in_joystickNo->integer);
+
Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer );
Com_DPrintf( "Name: %s\n", SDL_JoystickNameForIndex(in_joystickNo->integer) );
Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) );
@@ -483,8 +491,10 @@ static void IN_InitJoystick( void )
Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) );
Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) );
Com_DPrintf( "Use Analog: %s\n", in_joystickUseAnalog->integer ? "Yes" : "No" );
+ Com_DPrintf( "Is gamepad: %s\n", gamepad ? "Yes" : "No" );
SDL_JoystickEventState(SDL_QUERY);
+ SDL_GameControllerEventState(SDL_QUERY);
}
/*
@@ -497,6 +507,12 @@ static void IN_ShutdownJoystick( void )
if ( !SDL_WasInit( SDL_INIT_GAMECONTROLLER ) )
return;
+ if (gamepad)
+ {
+ SDL_GameControllerClose(gamepad);
+ gamepad = NULL;
+ }
+
if (stick)
{
SDL_JoystickClose(stick);
@@ -506,6 +522,204 @@ static void IN_ShutdownJoystick( void )
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
}
+
+static qboolean KeyToAxisAndSign(int keynum, int *outAxis, int *outSign)
+{
+ char *bind;
+
+ if (!keynum)
+ return qfalse;
+
+ bind = Key_GetBinding(keynum);
+
+ if (!bind || *bind != '+')
+ return qfalse;
+
+ *outSign = 0;
+
+ if (Q_stricmp(bind, "+forward") == 0)
+ {
+ *outAxis = j_forward_axis->integer;
+ *outSign = j_forward->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+back") == 0)
+ {
+ *outAxis = j_forward_axis->integer;
+ *outSign = j_forward->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveleft") == 0)
+ {
+ *outAxis = j_side_axis->integer;
+ *outSign = j_side->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveright") == 0)
+ {
+ *outAxis = j_side_axis->integer;
+ *outSign = j_side->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+lookup") == 0)
+ {
+ *outAxis = j_pitch_axis->integer;
+ *outSign = j_pitch->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+lookdown") == 0)
+ {
+ *outAxis = j_pitch_axis->integer;
+ *outSign = j_pitch->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+left") == 0)
+ {
+ *outAxis = j_yaw_axis->integer;
+ *outSign = j_yaw->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+right") == 0)
+ {
+ *outAxis = j_yaw_axis->integer;
+ *outSign = j_yaw->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveup") == 0)
+ {
+ *outAxis = j_up_axis->integer;
+ *outSign = j_up->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+movedown") == 0)
+ {
+ *outAxis = j_up_axis->integer;
+ *outSign = j_up->value > 0.0f ? -1 : 1;
+ }
+
+ return *outSign != 0;
+}
+
+/*
+===============
+IN_GamepadMove
+===============
+*/
+static void IN_GamepadMove( void )
+{
+ int i;
+ int translatedAxes[MAX_JOYSTICK_AXIS];
+ qboolean translatedAxesSet[MAX_JOYSTICK_AXIS];
+
+ SDL_GameControllerUpdate();
+
+ // check buttons
+ for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++)
+ {
+ qboolean pressed = SDL_GameControllerGetButton(gamepad, SDL_CONTROLLER_BUTTON_A + i);
+ if (pressed != stick_state.buttons[i])
+ {
+ Com_QueueEvent(0, SE_KEY, K_PAD0_A + i, pressed, 0, NULL);
+ stick_state.buttons[i] = pressed;
+ }
+ }
+
+ // must defer translated axes until all real axes are processed
+ // must be done this way to prevent a later mapped axis from zeroing out a previous one
+ if (in_joystickUseAnalog->integer)
+ {
+ for (i = 0; i < MAX_JOYSTICK_AXIS; i++)
+ {
+ translatedAxes[i] = 0;
+ translatedAxesSet[i] = qfalse;
+ }
+ }
+
+ // check axes
+ for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++)
+ {
+ int axis = SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_LEFTX + i);
+ int oldAxis = stick_state.oldaaxes[i];
+
+ // Smoothly ramp from dead zone to maximum value
+ float f = ((float)abs(axis) / 32767.0f - in_joystickThreshold->value) / (1.0f - in_joystickThreshold->value);
+
+ if (f < 0.0f)
+ f = 0.0f;
+
+ axis = (int)(32767 * ((axis < 0) ? -f : f));
+
+ if (axis != oldAxis)
+ {
+ const int negMap[SDL_CONTROLLER_AXIS_MAX] = { K_PAD0_LEFTSTICK_LEFT, K_PAD0_LEFTSTICK_UP, K_PAD0_RIGHTSTICK_LEFT, K_PAD0_RIGHTSTICK_UP, 0, 0 };
+ const int posMap[SDL_CONTROLLER_AXIS_MAX] = { K_PAD0_LEFTSTICK_RIGHT, K_PAD0_LEFTSTICK_DOWN, K_PAD0_RIGHTSTICK_RIGHT, K_PAD0_RIGHTSTICK_DOWN, K_PAD0_LEFTTRIGGER, K_PAD0_RIGHTTRIGGER };
+
+ qboolean posAnalog = qfalse, negAnalog = qfalse;
+ int negKey = negMap[i];
+ int posKey = posMap[i];
+
+ if (in_joystickUseAnalog->integer)
+ {
+ int posAxis = 0, posSign = 0, negAxis = 0, negSign = 0;
+
+ // get axes and axes signs for keys if available
+ posAnalog = KeyToAxisAndSign(posKey, &posAxis, &posSign);
+ negAnalog = KeyToAxisAndSign(negKey, &negAxis, &negSign);
+
+ // positive to negative/neutral -> keyup if axis hasn't yet been set
+ if (posAnalog && !translatedAxesSet[posAxis] && oldAxis > 0 && axis <= 0)
+ {
+ translatedAxes[posAxis] = 0;
+ translatedAxesSet[posAxis] = qtrue;
+ }
+
+ // negative to positive/neutral -> keyup if axis hasn't yet been set
+ if (negAnalog && !translatedAxesSet[negAxis] && oldAxis < 0 && axis >= 0)
+ {
+ translatedAxes[negAxis] = 0;
+ translatedAxesSet[negAxis] = qtrue;
+ }
+
+ // negative/neutral to positive -> keydown
+ if (posAnalog && axis > 0)
+ {
+ translatedAxes[posAxis] = axis * posSign;
+ translatedAxesSet[posAxis] = qtrue;
+ }
+
+ // positive/neutral to negative -> keydown
+ if (negAnalog && axis < 0)
+ {
+ translatedAxes[negAxis] = -axis * negSign;
+ translatedAxesSet[negAxis] = qtrue;
+ }
+ }
+
+ // keyups first so they get overridden by keydowns later
+
+ // positive to negative/neutral -> keyup
+ if (!posAnalog && posKey && oldAxis > 0 && axis <= 0)
+ Com_QueueEvent(0, SE_KEY, posKey, qfalse, 0, NULL);
+
+ // negative to positive/neutral -> keyup
+ if (!negAnalog && negKey && oldAxis < 0 && axis >= 0)
+ Com_QueueEvent(0, SE_KEY, negKey, qfalse, 0, NULL);
+
+ // negative/neutral to positive -> keydown
+ if (!posAnalog && posKey && oldAxis <= 0 && axis > 0)
+ Com_QueueEvent(0, SE_KEY, posKey, qtrue, 0, NULL);
+
+ // positive/neutral to negative -> keydown
+ if (!negAnalog && negKey && oldAxis >= 0 && axis < 0)
+ Com_QueueEvent(0, SE_KEY, negKey, qtrue, 0, NULL);
+
+ stick_state.oldaaxes[i] = axis;
+ }
+ }
+
+ // set translated axes
+ if (in_joystickUseAnalog->integer)
+ {
+ for (i = 0; i < MAX_JOYSTICK_AXIS; i++)
+ {
+ if (translatedAxesSet[i])
+ Com_QueueEvent(0, SE_JOYSTICK_AXIS, i, translatedAxes[i], 0, NULL);
+ }
+ }
+}
+
+
/*
===============
IN_JoyMove
@@ -518,6 +732,12 @@ static void IN_JoyMove( void )
int total = 0;
int i = 0;
+ if (gamepad)
+ {
+ IN_GamepadMove();
+ return;
+ }
+
if (!stick)
return;
@@ -872,7 +1092,8 @@ static void IN_ProcessEvents( void )
case SDL_CONTROLLERDEVICEADDED:
case SDL_CONTROLLERDEVICEREMOVED:
- IN_InitJoystick();
+ if (in_joystick->integer)
+ IN_InitJoystick();
break;
case SDL_QUIT:
diff --git a/SP/code/client/cl_input.c b/SP/code/client/cl_input.c
index 3c2a5ee..2ef75cd 100644
--- a/SP/code/client/cl_input.c
+++ b/SP/code/client/cl_input.c
@@ -439,6 +439,12 @@ CL_JoystickMove
void CL_JoystickMove( usercmd_t *cmd ) {
float anglespeed;
+ float yaw = j_yaw->value * cl.joystickAxis[j_yaw_axis->integer];
+ float right = j_side->value * cl.joystickAxis[j_side_axis->integer];
+ float forward = j_forward->value * cl.joystickAxis[j_forward_axis->integer];
+ float pitch = j_pitch->value * cl.joystickAxis[j_pitch_axis->integer];
+ float up = j_up->value * cl.joystickAxis[j_up_axis->integer];
+
if ( !(kb[KB_SPEED].active ^ cl_run->integer )) {
cmd->buttons |= BUTTON_WALKING;
}
@@ -450,21 +456,21 @@ void CL_JoystickMove( usercmd_t *cmd ) {
}
if ( !kb[KB_STRAFE].active ) {
- cl.viewangles[YAW] += anglespeed * j_yaw->value * cl.joystickAxis[j_yaw_axis->integer];
- cmd->rightmove = ClampChar( cmd->rightmove + (int) (j_side->value * cl.joystickAxis[j_side_axis->integer]) );
+ cl.viewangles[YAW] += anglespeed * yaw;
+ cmd->rightmove = ClampChar( cmd->rightmove + (int)right );
} else {
- cl.viewangles[YAW] += anglespeed * j_side->value * cl.joystickAxis[j_side_axis->integer];
- cmd->rightmove = ClampChar( cmd->rightmove + (int) (j_yaw->value * cl.joystickAxis[j_yaw_axis->integer]) );
+ cl.viewangles[YAW] += anglespeed * right;
+ cmd->rightmove = ClampChar( cmd->rightmove + (int)yaw );
}
if ( kb[KB_MLOOK].active ) {
- cl.viewangles[PITCH] += anglespeed * j_forward->value * cl.joystickAxis[j_forward_axis->integer];
- cmd->forwardmove = ClampChar( cmd->forwardmove + (int) (j_pitch->value * cl.joystickAxis[j_pitch_axis->integer]) );
+ cl.viewangles[PITCH] += anglespeed * forward;
+ cmd->forwardmove = ClampChar( cmd->forwardmove + (int)pitch );
} else {
- cl.viewangles[PITCH] += anglespeed * j_pitch->value * cl.joystickAxis[j_pitch_axis->integer];
- cmd->forwardmove = ClampChar( cmd->forwardmove + (int) (j_forward->value * cl.joystickAxis[j_forward_axis->integer]) );
+ cl.viewangles[PITCH] += anglespeed * pitch;
+ cmd->forwardmove = ClampChar( cmd->forwardmove + (int)forward );
}
- cmd->upmove = ClampChar( cmd->upmove + (int) (j_up->value * cl.joystickAxis[j_up_axis->integer]) );
+ cmd->upmove = ClampChar( cmd->upmove + (int)up );
}
/*
diff --git a/SP/code/client/cl_keys.c b/SP/code/client/cl_keys.c
index 005809a..413bb1f 100644
--- a/SP/code/client/cl_keys.c
+++ b/SP/code/client/cl_keys.c
@@ -298,6 +298,33 @@ keyname_t keynames[] =
{"EURO", K_EURO},
{"UNDO", K_UNDO},
+ {"PAD0_A", K_PAD0_A },
+ {"PAD0_B", K_PAD0_B },
+ {"PAD0_X", K_PAD0_X },
+ {"PAD0_Y", K_PAD0_Y },
+ {"PAD0_BACK", K_PAD0_BACK },
+ {"PAD0_GUIDE", K_PAD0_GUIDE },
+ {"PAD0_START", K_PAD0_START },
+ {"PAD0_LEFTSTICK_CLICK", K_PAD0_LEFTSTICK_CLICK },
+ {"PAD0_RIGHTSTICK_CLICK", K_PAD0_RIGHTSTICK_CLICK },
+ {"PAD0_LEFTSHOULDER", K_PAD0_LEFTSHOULDER },
+ {"PAD0_RIGHTSHOULDER", K_PAD0_RIGHTSHOULDER },
+ {"PAD0_DPAD_UP", K_PAD0_DPAD_UP },
+ {"PAD0_DPAD_DOWN", K_PAD0_DPAD_DOWN },
+ {"PAD0_DPAD_LEFT", K_PAD0_DPAD_LEFT },
+ {"PAD0_DPAD_RIGHT", K_PAD0_DPAD_RIGHT },
+
+ {"PAD0_LEFTSTICK_LEFT", K_PAD0_LEFTSTICK_LEFT },
+ {"PAD0_LEFTSTICK_RIGHT", K_PAD0_LEFTSTICK_RIGHT },
+ {"PAD0_LEFTSTICK_UP", K_PAD0_LEFTSTICK_UP },
+ {"PAD0_LEFTSTICK_DOWN", K_PAD0_LEFTSTICK_DOWN },
+ {"PAD0_RIGHTSTICK_LEFT", K_PAD0_RIGHTSTICK_LEFT },
+ {"PAD0_RIGHTSTICK_RIGHT", K_PAD0_RIGHTSTICK_RIGHT },
+ {"PAD0_RIGHTSTICK_UP", K_PAD0_RIGHTSTICK_UP },
+ {"PAD0_RIGHTSTICK_DOWN", K_PAD0_RIGHTSTICK_DOWN },
+ {"PAD0_LEFTTRIGGER", K_PAD0_LEFTTRIGGER },
+ {"PAD0_RIGHTTRIGGER", K_PAD0_RIGHTTRIGGER },
+
{NULL,0}
};
diff --git a/SP/code/client/keycodes.h b/SP/code/client/keycodes.h
index 1c4831a..a8fb329 100644
--- a/SP/code/client/keycodes.h
+++ b/SP/code/client/keycodes.h
@@ -266,6 +266,36 @@ typedef enum {
K_EURO,
K_UNDO,
+ // Gamepad controls
+ // Ordered to match SDL2 game controller buttons and axes
+ // Do not change this order without also changing IN_GamepadMove() in SDL_input.c
+ K_PAD0_A,
+ K_PAD0_B,
+ K_PAD0_X,
+ K_PAD0_Y,
+ K_PAD0_BACK,
+ K_PAD0_GUIDE,
+ K_PAD0_START,
+ K_PAD0_LEFTSTICK_CLICK,
+ K_PAD0_RIGHTSTICK_CLICK,
+ K_PAD0_LEFTSHOULDER,
+ K_PAD0_RIGHTSHOULDER,
+ K_PAD0_DPAD_UP,
+ K_PAD0_DPAD_DOWN,
+ K_PAD0_DPAD_LEFT,
+ K_PAD0_DPAD_RIGHT,
+
+ K_PAD0_LEFTSTICK_LEFT,
+ K_PAD0_LEFTSTICK_RIGHT,
+ K_PAD0_LEFTSTICK_UP,
+ K_PAD0_LEFTSTICK_DOWN,
+ K_PAD0_RIGHTSTICK_LEFT,
+ K_PAD0_RIGHTSTICK_RIGHT,
+ K_PAD0_RIGHTSTICK_UP,
+ K_PAD0_RIGHTSTICK_DOWN,
+ K_PAD0_LEFTTRIGGER,
+ K_PAD0_RIGHTTRIGGER,
+
// Pseudo-key that brings the console down
K_CONSOLE,
diff --git a/SP/code/sdl/sdl_input.c b/SP/code/sdl/sdl_input.c
index 4991095..887bff7 100644
--- a/SP/code/sdl/sdl_input.c
+++ b/SP/code/sdl/sdl_input.c
@@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
static cvar_t *in_keyboardDebug = NULL;
+static SDL_GameController *gamepad = NULL;
static SDL_Joystick *stick = NULL;
static qboolean mouseAvailable = qfalse;
@@ -410,7 +411,7 @@ static int hat_keys[16] = {
struct
{
- qboolean buttons[16]; // !!! FIXME: these might be too many.
+ qboolean buttons[SDL_CONTROLLER_BUTTON_MAX + 1]; // +1 because old max was 16, current SDL_CONTROLLER_BUTTON_MAX is 15
unsigned int oldaxes;
int oldaaxes[MAX_JOYSTICK_AXIS];
unsigned int oldhats;
@@ -428,10 +429,14 @@ static void IN_InitJoystick( void )
int total = 0;
char buf[16384] = "";
+ if (gamepad)
+ SDL_GameControllerClose(gamepad);
+
if (stick != NULL)
SDL_JoystickClose(stick);
stick = NULL;
+ gamepad = NULL;
memset(&stick_state, '\0', sizeof (stick_state));
if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER))
@@ -476,6 +481,9 @@ static void IN_InitJoystick( void )
return;
}
+ if (SDL_IsGameController(in_joystickNo->integer))
+ gamepad = SDL_GameControllerOpen(in_joystickNo->integer);
+
Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer );
Com_DPrintf( "Name: %s\n", SDL_JoystickNameForIndex(in_joystickNo->integer) );
Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) );
@@ -483,8 +491,10 @@ static void IN_InitJoystick( void )
Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) );
Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) );
Com_DPrintf( "Use Analog: %s\n", in_joystickUseAnalog->integer ? "Yes" : "No" );
+ Com_DPrintf( "Is gamepad: %s\n", gamepad ? "Yes" : "No" );
SDL_JoystickEventState(SDL_QUERY);
+ SDL_GameControllerEventState(SDL_QUERY);
}
/*
@@ -497,6 +507,12 @@ static void IN_ShutdownJoystick( void )
if ( !SDL_WasInit( SDL_INIT_GAMECONTROLLER ) )
return;
+ if (gamepad)
+ {
+ SDL_GameControllerClose(gamepad);
+ gamepad = NULL;
+ }
+
if (stick)
{
SDL_JoystickClose(stick);
@@ -506,6 +522,204 @@ static void IN_ShutdownJoystick( void )
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
}
+
+static qboolean KeyToAxisAndSign(int keynum, int *outAxis, int *outSign)
+{
+ char *bind;
+
+ if (!keynum)
+ return qfalse;
+
+ bind = Key_GetBinding(keynum);
+
+ if (!bind || *bind != '+')
+ return qfalse;
+
+ *outSign = 0;
+
+ if (Q_stricmp(bind, "+forward") == 0)
+ {
+ *outAxis = j_forward_axis->integer;
+ *outSign = j_forward->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+back") == 0)
+ {
+ *outAxis = j_forward_axis->integer;
+ *outSign = j_forward->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveleft") == 0)
+ {
+ *outAxis = j_side_axis->integer;
+ *outSign = j_side->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveright") == 0)
+ {
+ *outAxis = j_side_axis->integer;
+ *outSign = j_side->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+lookup") == 0)
+ {
+ *outAxis = j_pitch_axis->integer;
+ *outSign = j_pitch->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+lookdown") == 0)
+ {
+ *outAxis = j_pitch_axis->integer;
+ *outSign = j_pitch->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+left") == 0)
+ {
+ *outAxis = j_yaw_axis->integer;
+ *outSign = j_yaw->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+right") == 0)
+ {
+ *outAxis = j_yaw_axis->integer;
+ *outSign = j_yaw->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveup") == 0)
+ {
+ *outAxis = j_up_axis->integer;
+ *outSign = j_up->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+movedown") == 0)
+ {
+ *outAxis = j_up_axis->integer;
+ *outSign = j_up->value > 0.0f ? -1 : 1;
+ }
+
+ return *outSign != 0;
+}
+
+/*
+===============
+IN_GamepadMove
+===============
+*/
+static void IN_GamepadMove( void )
+{
+ int i;
+ int translatedAxes[MAX_JOYSTICK_AXIS];
+ qboolean translatedAxesSet[MAX_JOYSTICK_AXIS];
+
+ SDL_GameControllerUpdate();
+
+ // check buttons
+ for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++)
+ {
+ qboolean pressed = SDL_GameControllerGetButton(gamepad, SDL_CONTROLLER_BUTTON_A + i);
+ if (pressed != stick_state.buttons[i])
+ {
+ Com_QueueEvent(0, SE_KEY, K_PAD0_A + i, pressed, 0, NULL);
+ stick_state.buttons[i] = pressed;
+ }
+ }
+
+ // must defer translated axes until all real axes are processed
+ // must be done this way to prevent a later mapped axis from zeroing out a previous one
+ if (in_joystickUseAnalog->integer)
+ {
+ for (i = 0; i < MAX_JOYSTICK_AXIS; i++)
+ {
+ translatedAxes[i] = 0;
+ translatedAxesSet[i] = qfalse;
+ }
+ }
+
+ // check axes
+ for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++)
+ {
+ int axis = SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_LEFTX + i);
+ int oldAxis = stick_state.oldaaxes[i];
+
+ // Smoothly ramp from dead zone to maximum value
+ float f = ((float)abs(axis) / 32767.0f - in_joystickThreshold->value) / (1.0f - in_joystickThreshold->value);
+
+ if (f < 0.0f)
+ f = 0.0f;
+
+ axis = (int)(32767 * ((axis < 0) ? -f : f));
+
+ if (axis != oldAxis)
+ {
+ const int negMap[SDL_CONTROLLER_AXIS_MAX] = { K_PAD0_LEFTSTICK_LEFT, K_PAD0_LEFTSTICK_UP, K_PAD0_RIGHTSTICK_LEFT, K_PAD0_RIGHTSTICK_UP, 0, 0 };
+ const int posMap[SDL_CONTROLLER_AXIS_MAX] = { K_PAD0_LEFTSTICK_RIGHT, K_PAD0_LEFTSTICK_DOWN, K_PAD0_RIGHTSTICK_RIGHT, K_PAD0_RIGHTSTICK_DOWN, K_PAD0_LEFTTRIGGER, K_PAD0_RIGHTTRIGGER };
+
+ qboolean posAnalog = qfalse, negAnalog = qfalse;
+ int negKey = negMap[i];
+ int posKey = posMap[i];
+
+ if (in_joystickUseAnalog->integer)
+ {
+ int posAxis = 0, posSign = 0, negAxis = 0, negSign = 0;
+
+ // get axes and axes signs for keys if available
+ posAnalog = KeyToAxisAndSign(posKey, &posAxis, &posSign);
+ negAnalog = KeyToAxisAndSign(negKey, &negAxis, &negSign);
+
+ // positive to negative/neutral -> keyup if axis hasn't yet been set
+ if (posAnalog && !translatedAxesSet[posAxis] && oldAxis > 0 && axis <= 0)
+ {
+ translatedAxes[posAxis] = 0;
+ translatedAxesSet[posAxis] = qtrue;
+ }
+
+ // negative to positive/neutral -> keyup if axis hasn't yet been set
+ if (negAnalog && !translatedAxesSet[negAxis] && oldAxis < 0 && axis >= 0)
+ {
+ translatedAxes[negAxis] = 0;
+ translatedAxesSet[negAxis] = qtrue;
+ }
+
+ // negative/neutral to positive -> keydown
+ if (posAnalog && axis > 0)
+ {
+ translatedAxes[posAxis] = axis * posSign;
+ translatedAxesSet[posAxis] = qtrue;
+ }
+
+ // positive/neutral to negative -> keydown
+ if (negAnalog && axis < 0)
+ {
+ translatedAxes[negAxis] = -axis * negSign;
+ translatedAxesSet[negAxis] = qtrue;
+ }
+ }
+
+ // keyups first so they get overridden by keydowns later
+
+ // positive to negative/neutral -> keyup
+ if (!posAnalog && posKey && oldAxis > 0 && axis <= 0)
+ Com_QueueEvent(0, SE_KEY, posKey, qfalse, 0, NULL);
+
+ // negative to positive/neutral -> keyup
+ if (!negAnalog && negKey && oldAxis < 0 && axis >= 0)
+ Com_QueueEvent(0, SE_KEY, negKey, qfalse, 0, NULL);
+
+ // negative/neutral to positive -> keydown
+ if (!posAnalog && posKey && oldAxis <= 0 && axis > 0)
+ Com_QueueEvent(0, SE_KEY, posKey, qtrue, 0, NULL);
+
+ // positive/neutral to negative -> keydown
+ if (!negAnalog && negKey && oldAxis >= 0 && axis < 0)
+ Com_QueueEvent(0, SE_KEY, negKey, qtrue, 0, NULL);
+
+ stick_state.oldaaxes[i] = axis;
+ }
+ }
+
+ // set translated axes
+ if (in_joystickUseAnalog->integer)
+ {
+ for (i = 0; i < MAX_JOYSTICK_AXIS; i++)
+ {
+ if (translatedAxesSet[i])
+ Com_QueueEvent(0, SE_JOYSTICK_AXIS, i, translatedAxes[i], 0, NULL);
+ }
+ }
+}
+
+
/*
===============
IN_JoyMove
@@ -518,6 +732,12 @@ static void IN_JoyMove( void )
int total = 0;
int i = 0;
+ if (gamepad)
+ {
+ IN_GamepadMove();
+ return;
+ }
+
if (!stick)
return;
@@ -872,7 +1092,8 @@ static void IN_ProcessEvents( void )
case SDL_CONTROLLERDEVICEADDED:
case SDL_CONTROLLERDEVICEREMOVED:
- IN_InitJoystick();
+ if (in_joystick->integer)
+ IN_InitJoystick();
break;
case SDL_QUIT:
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/iortcw.git
More information about the Pkg-games-commits
mailing list