mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-22 20:51:20 +00:00
Merge GameController support from Quadrilateral Cowboy
https://github.com/blendogames/quadrilateralcowboy pretty much as it is there, with only minimal changes required to work with dhewm3
This commit is contained in:
parent
37b0551ba8
commit
ab53e9aa13
7 changed files with 604 additions and 70 deletions
|
@ -2919,7 +2919,7 @@ void idCommonLocal::Init( int argc, char **argv ) {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)) // init joystick to work around SDL 2.0.9 bug #4391
|
||||
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
|
||||
Sys_Error("Error while initializing SDL: %s", SDL_GetError());
|
||||
|
||||
Sys_InitThreads();
|
||||
|
|
|
@ -124,23 +124,24 @@ static const keyname_t keynames[] =
|
|||
{"JOY13", K_JOY13, "#str_07074"},
|
||||
{"JOY14", K_JOY14, "#str_07075"},
|
||||
{"JOY15", K_JOY15, "#str_07076"},
|
||||
{"JOY16", K_JOY16, "#str_07077"},
|
||||
{"JOY17", K_JOY17, "#str_07078"},
|
||||
{"JOY18", K_JOY18, "#str_07079"},
|
||||
{"JOY19", K_JOY19, "#str_07080"},
|
||||
{"JOY20", K_JOY20, "#str_07081"},
|
||||
{"JOY21", K_JOY21, "#str_07082"},
|
||||
{"JOY22", K_JOY22, "#str_07083"},
|
||||
{"JOY23", K_JOY23, "#str_07084"},
|
||||
{"JOY24", K_JOY24, "#str_07085"},
|
||||
{"JOY25", K_JOY25, "#str_07086"},
|
||||
{"JOY26", K_JOY26, "#str_07087"},
|
||||
{"JOY27", K_JOY27, "#str_07088"},
|
||||
{"JOY28", K_JOY28, "#str_07089"},
|
||||
{"JOY29", K_JOY29, "#str_07090"},
|
||||
{"JOY30", K_JOY30, "#str_07091"},
|
||||
{"JOY31", K_JOY31, "#str_07092"},
|
||||
{"JOY32", K_JOY32, "#str_07093"},
|
||||
|
||||
{"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_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_TRIGGER1", K_JOY_TRIGGER1, "JOY_TRIGGER1"},
|
||||
{"JOY_TRIGGER2", K_JOY_TRIGGER2, "JOY_TRIGGER2"},
|
||||
|
||||
{"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"},
|
||||
|
||||
{"AUX1", K_AUX1, "#str_07094"},
|
||||
{"AUX2", K_AUX2, "#str_07095"},
|
||||
|
|
|
@ -138,6 +138,10 @@ typedef enum {
|
|||
K_MWHEELDOWN = 195,
|
||||
K_MWHEELUP,
|
||||
|
||||
//------------------------
|
||||
// K_JOY codes must be contiguous, too
|
||||
//------------------------
|
||||
|
||||
K_JOY1 = 197,
|
||||
K_JOY2,
|
||||
K_JOY3,
|
||||
|
@ -154,23 +158,26 @@ typedef enum {
|
|||
K_JOY14,
|
||||
K_JOY15,
|
||||
K_JOY16,
|
||||
K_JOY17,
|
||||
K_JOY18,
|
||||
K_JOY19,
|
||||
K_JOY20,
|
||||
K_JOY21,
|
||||
K_JOY22,
|
||||
K_JOY23,
|
||||
K_JOY24,
|
||||
K_JOY25,
|
||||
K_JOY26,
|
||||
K_JOY27,
|
||||
K_GRAVE_A = 224, // lowercase a with grave accent
|
||||
K_JOY28,
|
||||
K_JOY29,
|
||||
K_JOY30,
|
||||
K_JOY31,
|
||||
K_JOY32,
|
||||
|
||||
K_JOY_STICK1_UP,
|
||||
K_JOY_STICK1_DOWN,
|
||||
K_JOY_STICK1_LEFT,
|
||||
K_JOY_STICK1_RIGHT,
|
||||
|
||||
K_JOY_STICK2_UP,
|
||||
K_JOY_STICK2_DOWN,
|
||||
K_JOY_STICK2_LEFT,
|
||||
K_JOY_STICK2_RIGHT,
|
||||
|
||||
K_JOY_TRIGGER1,
|
||||
K_JOY_TRIGGER2,
|
||||
|
||||
K_JOY_DPAD_UP,
|
||||
K_JOY_DPAD_DOWN,
|
||||
K_JOY_DPAD_LEFT,
|
||||
K_JOY_DPAD_RIGHT,
|
||||
|
||||
K_GRAVE_A = 229, // lowercase a with grave accent FIXME: used to be 224; this probably isn't used anyway
|
||||
|
||||
K_AUX1 = 230,
|
||||
K_CEDILLA_C = 231, // lowercase c with Cedilla
|
||||
|
|
|
@ -350,6 +350,8 @@ private:
|
|||
bool Inhibited( void );
|
||||
void AdjustAngles( void );
|
||||
void KeyMove( void );
|
||||
void CircleToSquare( float & axis_x, float & axis_y ) const;
|
||||
void HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive );
|
||||
void JoystickMove( void );
|
||||
void MouseMove( void );
|
||||
void CmdButtons( void );
|
||||
|
@ -384,7 +386,14 @@ private:
|
|||
bool mouseDown;
|
||||
|
||||
int mouseDx, mouseDy; // added to by mouse events
|
||||
int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
|
||||
float joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
|
||||
|
||||
int pollTime;
|
||||
int lastPollTime;
|
||||
float lastLookValuePitch;
|
||||
float lastLookValueYaw;
|
||||
|
||||
bool heldJump; // TODO: ???
|
||||
|
||||
static idCVar in_yawSpeed;
|
||||
static idCVar in_pitchSpeed;
|
||||
|
@ -419,6 +428,24 @@ idCVar idUsercmdGenLocal::m_smooth( "m_smooth", "1", CVAR_SYSTEM | CVAR_ARCHIVE
|
|||
idCVar idUsercmdGenLocal::m_strafeSmooth( "m_strafeSmooth", "4", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "number of samples blended for mouse moving", 1, 8, idCmdSystem::ArgCompletion_Integer<1,8> );
|
||||
idCVar idUsercmdGenLocal::m_showMouseRate( "m_showMouseRate", "0", CVAR_SYSTEM | CVAR_BOOL, "shows mouse movement" );
|
||||
|
||||
idCVar joy_mergedThreshold( "joy_mergedThreshold", "1", CVAR_BOOL | CVAR_ARCHIVE, "If the thresholds aren't merged, you drift more off center" );
|
||||
idCVar joy_newCode( "joy_newCode", "0", CVAR_BOOL | CVAR_ARCHIVE, "Use the new codepath" );
|
||||
idCVar joy_triggerThreshold( "joy_triggerThreshold", "0.05", CVAR_FLOAT | CVAR_ARCHIVE, "how far the joystick triggers have to be pressed before they register as down" );
|
||||
idCVar joy_deadZone( "joy_deadZone", "0.4", CVAR_FLOAT | CVAR_ARCHIVE, "specifies how large the dead-zone is on the joystick" );
|
||||
idCVar joy_range( "joy_range", "1.0", CVAR_FLOAT | CVAR_ARCHIVE, "allow full range to be mapped to a smaller offset" );
|
||||
idCVar joy_gammaLook( "joy_gammaLook", "1", CVAR_INTEGER | CVAR_ARCHIVE, "use a log curve instead of a power curve for movement" );
|
||||
idCVar joy_powerScale( "joy_powerScale", "2", CVAR_FLOAT | CVAR_ARCHIVE, "Raise joystick values to this power" );
|
||||
idCVar joy_pitchSpeed( "joy_pitchSpeed", "130", CVAR_ARCHIVE | CVAR_FLOAT, "pitch speed when pressing up or down on the joystick", 60, 600 );
|
||||
idCVar joy_yawSpeed( "joy_yawSpeed", "240", CVAR_ARCHIVE | CVAR_FLOAT, "pitch speed when pressing left or right on the joystick", 60, 600 );
|
||||
|
||||
// these were a bad idea!
|
||||
idCVar joy_dampenLook( "joy_dampenLook", "1", CVAR_BOOL | CVAR_ARCHIVE, "Do not allow full acceleration on look" );
|
||||
idCVar joy_deltaPerMSLook( "joy_deltaPerMSLook", "0.003", CVAR_FLOAT | CVAR_ARCHIVE, "Max amount to be added on look per MS" );
|
||||
|
||||
idCVar in_useJoystick( "in_useJoystick", "1", CVAR_ARCHIVE | CVAR_BOOL, "enables/disables the gamepad for PC use" );
|
||||
idCVar in_invertLook( "in_invertLook", "0", CVAR_ARCHIVE | CVAR_BOOL, "inverts the look controls so the forward looks up (flight controls) - the proper way to play games!" );
|
||||
idCVar in_mouseInvertLook( "in_mouseInvertLook", "0", CVAR_ARCHIVE | CVAR_BOOL, "inverts the look controls so the forward looks up (flight controls) - the proper way to play games!" );
|
||||
|
||||
static idUsercmdGenLocal localUsercmdGen;
|
||||
idUsercmdGen *usercmdGen = &localUsercmdGen;
|
||||
|
||||
|
@ -573,9 +600,17 @@ void idUsercmdGenLocal::KeyMove( void ) {
|
|||
forward += KEY_MOVESPEED * ButtonState( UB_FORWARD );
|
||||
forward -= KEY_MOVESPEED * ButtonState( UB_BACK );
|
||||
|
||||
cmd.forwardmove = idMath::ClampChar( forward );
|
||||
cmd.rightmove = idMath::ClampChar( side );
|
||||
cmd.upmove = idMath::ClampChar( up );
|
||||
// only set each movement variable if its unset at this point.
|
||||
// NOTE: joystick input happens before this.
|
||||
if (cmd.forwardmove == 0) {
|
||||
cmd.forwardmove = idMath::ClampChar( forward );
|
||||
}
|
||||
if (cmd.rightmove == 0) {
|
||||
cmd.rightmove = idMath::ClampChar( side );
|
||||
}
|
||||
if (cmd.upmove == 0) {
|
||||
cmd.upmove = idMath::ClampChar( up );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -672,29 +707,199 @@ void idUsercmdGenLocal::MouseMove( void ) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idUsercmdGenLocal::CircleToSquare
|
||||
========================
|
||||
*/
|
||||
void idUsercmdGenLocal::CircleToSquare( float & axis_x, float & axis_y ) const {
|
||||
// bring everything in the first quadrant
|
||||
bool flip_x = false;
|
||||
if ( axis_x < 0.0f ) {
|
||||
flip_x = true;
|
||||
axis_x *= -1.0f;
|
||||
}
|
||||
bool flip_y = false;
|
||||
if ( axis_y < 0.0f ) {
|
||||
flip_y = true;
|
||||
axis_y *= -1.0f;
|
||||
}
|
||||
|
||||
// swap the two axes so we project against the vertical line X = 1
|
||||
bool swap = false;
|
||||
if ( axis_y > axis_x ) {
|
||||
float tmp = axis_x;
|
||||
axis_x = axis_y;
|
||||
axis_y = tmp;
|
||||
swap = true;
|
||||
}
|
||||
|
||||
if ( axis_x < 0.001f ) {
|
||||
// on one of the axes where no correction is needed
|
||||
return;
|
||||
}
|
||||
|
||||
// length (max 1.0f at the unit circle)
|
||||
float len = idMath::Sqrt( axis_x * axis_x + axis_y * axis_y );
|
||||
if ( len > 1.0f ) {
|
||||
len = 1.0f;
|
||||
}
|
||||
// thales
|
||||
float axis_y_us = axis_y / axis_x;
|
||||
|
||||
// use a power curve to shift the correction to happen closer to the unit circle
|
||||
float correctionRatio = Square( len );
|
||||
axis_x += correctionRatio * ( len - axis_x );
|
||||
axis_y += correctionRatio * ( axis_y_us - axis_y );
|
||||
|
||||
// go back through the symmetries
|
||||
if ( swap ) {
|
||||
float tmp = axis_x;
|
||||
axis_x = axis_y;
|
||||
axis_y = tmp;
|
||||
}
|
||||
if ( flip_x ) {
|
||||
axis_x *= -1.0f;
|
||||
}
|
||||
if ( flip_y ) {
|
||||
axis_y *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idUsercmdGenLocal::HandleJoystickAxis
|
||||
========================
|
||||
*/
|
||||
void idUsercmdGenLocal::HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive ) {
|
||||
if ( ( unclampedValue > 0.0f ) && !positive ) {
|
||||
return;
|
||||
}
|
||||
if ( ( unclampedValue < 0.0f ) && positive ) {
|
||||
return;
|
||||
}
|
||||
float value = 0.0f;
|
||||
bool pressed = false;
|
||||
if ( unclampedValue > threshold ) {
|
||||
value = idMath::Fabs( ( unclampedValue - threshold ) / ( 1.0f - threshold ) );
|
||||
pressed = true;
|
||||
} else if ( unclampedValue < -threshold ) {
|
||||
value = idMath::Fabs( ( unclampedValue + threshold ) / ( 1.0f - threshold ) );
|
||||
pressed = true;
|
||||
}
|
||||
|
||||
int action = idKeyInput::GetUsercmdAction( keyNum );
|
||||
if ( action >= UB_ATTACK ) {
|
||||
Key( keyNum, pressed );
|
||||
return;
|
||||
}
|
||||
if ( !pressed ) {
|
||||
return;
|
||||
}
|
||||
|
||||
float lookValue = 0.0f;
|
||||
if ( joy_gammaLook.GetBool() ) {
|
||||
lookValue = idMath::Pow( 1.04712854805f, value * 100.0f ) * 0.01f;
|
||||
} else {
|
||||
lookValue = idMath::Pow( value, joy_powerScale.GetFloat() );
|
||||
}
|
||||
|
||||
#if 0 // TODO: aim assist maybe.
|
||||
idGame * game = common->Game();
|
||||
if ( game != NULL ) {
|
||||
lookValue *= game->GetAimAssistSensitivity();
|
||||
}
|
||||
#endif
|
||||
|
||||
switch ( action ) {
|
||||
case UB_FORWARD: {
|
||||
float move = (float)cmd.forwardmove + ( KEY_MOVESPEED * value );
|
||||
cmd.forwardmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
||||
break;
|
||||
}
|
||||
case UB_BACK: {
|
||||
float move = (float)cmd.forwardmove - ( KEY_MOVESPEED * value );
|
||||
cmd.forwardmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
||||
break;
|
||||
}
|
||||
case UB_MOVELEFT: {
|
||||
float move = (float)cmd.rightmove - ( KEY_MOVESPEED * value );
|
||||
cmd.rightmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
||||
break;
|
||||
}
|
||||
case UB_MOVERIGHT: {
|
||||
float move = (float)cmd.rightmove + ( KEY_MOVESPEED * value );
|
||||
cmd.rightmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
||||
break;
|
||||
}
|
||||
case UB_LOOKUP: {
|
||||
if ( joy_dampenLook.GetBool() ) {
|
||||
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValuePitch );
|
||||
lastLookValuePitch = lookValue;
|
||||
}
|
||||
|
||||
float invertPitch = in_invertLook.GetBool() ? -1.0f : 1.0f;
|
||||
viewangles[PITCH] -= MS2SEC( pollTime - lastPollTime ) * lookValue * joy_pitchSpeed.GetFloat() * invertPitch;
|
||||
break;
|
||||
}
|
||||
case UB_LOOKDOWN: {
|
||||
if ( joy_dampenLook.GetBool() ) {
|
||||
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValuePitch );
|
||||
lastLookValuePitch = lookValue;
|
||||
}
|
||||
|
||||
float invertPitch = in_invertLook.GetBool() ? -1.0f : 1.0f;
|
||||
viewangles[PITCH] += MS2SEC( pollTime - lastPollTime ) * lookValue * joy_pitchSpeed.GetFloat() * invertPitch;
|
||||
break;
|
||||
}
|
||||
case UB_LEFT: {
|
||||
if ( joy_dampenLook.GetBool() ) {
|
||||
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValueYaw );
|
||||
lastLookValueYaw = lookValue;
|
||||
}
|
||||
viewangles[YAW] += MS2SEC( pollTime - lastPollTime ) * lookValue * joy_yawSpeed.GetFloat();
|
||||
break;
|
||||
}
|
||||
case UB_RIGHT: {
|
||||
if ( joy_dampenLook.GetBool() ) {
|
||||
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValueYaw );
|
||||
lastLookValueYaw = lookValue;
|
||||
}
|
||||
viewangles[YAW] -= MS2SEC( pollTime - lastPollTime ) * lookValue * joy_yawSpeed.GetFloat();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idUsercmdGenLocal::JoystickMove
|
||||
=================
|
||||
*/
|
||||
void idUsercmdGenLocal::JoystickMove( void ) {
|
||||
float anglespeed;
|
||||
void idUsercmdGenLocal::JoystickMove() {
|
||||
float threshold = joy_deadZone.GetFloat();
|
||||
float triggerThreshold = joy_triggerThreshold.GetFloat();
|
||||
|
||||
if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && idAsyncNetwork::IsActive() ) ) {
|
||||
anglespeed = idMath::M_MS2SEC * USERCMD_MSEC * in_angleSpeedKey.GetFloat();
|
||||
} else {
|
||||
anglespeed = idMath::M_MS2SEC * USERCMD_MSEC;
|
||||
}
|
||||
float axis_y = joystickAxis[ AXIS_LEFT_Y ];
|
||||
float axis_x = joystickAxis[ AXIS_LEFT_X ];
|
||||
CircleToSquare( axis_x, axis_y );
|
||||
|
||||
if ( !ButtonState( UB_STRAFE ) ) {
|
||||
viewangles[YAW] += anglespeed * in_yawSpeed.GetFloat() * joystickAxis[AXIS_SIDE];
|
||||
viewangles[PITCH] += anglespeed * in_pitchSpeed.GetFloat() * joystickAxis[AXIS_FORWARD];
|
||||
} else {
|
||||
cmd.rightmove = idMath::ClampChar( cmd.rightmove + joystickAxis[AXIS_SIDE] );
|
||||
cmd.forwardmove = idMath::ClampChar( cmd.forwardmove + joystickAxis[AXIS_FORWARD] );
|
||||
}
|
||||
HandleJoystickAxis( K_JOY_STICK1_UP, axis_y, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK1_DOWN, axis_y, threshold, true );
|
||||
HandleJoystickAxis( K_JOY_STICK1_LEFT, axis_x, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK1_RIGHT, axis_x, threshold, true );
|
||||
|
||||
cmd.upmove = idMath::ClampChar( cmd.upmove + joystickAxis[AXIS_UP] );
|
||||
axis_y = joystickAxis[ AXIS_RIGHT_Y ];
|
||||
axis_x = joystickAxis[ AXIS_RIGHT_X ];
|
||||
CircleToSquare( axis_x, axis_y );
|
||||
|
||||
HandleJoystickAxis( K_JOY_STICK2_UP, axis_y, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK2_DOWN, axis_y, threshold, true );
|
||||
HandleJoystickAxis( K_JOY_STICK2_LEFT, axis_x, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK2_RIGHT, axis_x, threshold, true );
|
||||
|
||||
HandleJoystickAxis( K_JOY_TRIGGER1, joystickAxis[ AXIS_LEFT_TRIG ], triggerThreshold, true );
|
||||
HandleJoystickAxis( K_JOY_TRIGGER2, joystickAxis[ AXIS_RIGHT_TRIG ], triggerThreshold, true );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -778,6 +983,9 @@ void idUsercmdGenLocal::MakeCurrent( void ) {
|
|||
// keyboard angle adjustment
|
||||
AdjustAngles();
|
||||
|
||||
// get basic movement from joystick
|
||||
JoystickMove();
|
||||
|
||||
// set button bits
|
||||
CmdButtons();
|
||||
|
||||
|
@ -787,9 +995,6 @@ void idUsercmdGenLocal::MakeCurrent( void ) {
|
|||
// get basic movement from mouse
|
||||
MouseMove();
|
||||
|
||||
// get basic movement from joystick
|
||||
JoystickMove();
|
||||
|
||||
// check to make sure the angles haven't wrapped
|
||||
if ( viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
|
||||
viewangles[PITCH] = oldAngles[PITCH] + 90;
|
||||
|
@ -877,6 +1082,7 @@ void idUsercmdGenLocal::Clear( void ) {
|
|||
// clears all key states
|
||||
memset( buttonState, 0, sizeof( buttonState ) );
|
||||
memset( keyState, false, sizeof( keyState ) );
|
||||
memset( joystickAxis, 0, sizeof( joystickAxis ) );
|
||||
|
||||
inhibitCommands = false;
|
||||
|
||||
|
@ -939,6 +1145,8 @@ void idUsercmdGenLocal::Key( int keyNum, bool down ) {
|
|||
|
||||
int action = idKeyInput::GetUsercmdAction( keyNum );
|
||||
|
||||
// TODO: if action == 0 return ?
|
||||
|
||||
if ( down ) {
|
||||
|
||||
buttonState[ action ]++;
|
||||
|
@ -1039,7 +1247,28 @@ idUsercmdGenLocal::Joystick
|
|||
===============
|
||||
*/
|
||||
void idUsercmdGenLocal::Joystick( void ) {
|
||||
memset( joystickAxis, 0, sizeof( joystickAxis ) );
|
||||
int numEvents = Sys_PollJoystickInputEvents( 0 );
|
||||
|
||||
// Study each of the buffer elements and process them.
|
||||
for ( int i = 0; i < numEvents; i++ ) {
|
||||
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 );
|
||||
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;
|
||||
} else if ( action >= J_DPAD_UP && action <= J_DPAD_RIGHT ) {
|
||||
int joyButton = K_JOY_DPAD_UP + ( action - J_DPAD_UP );
|
||||
Key( joyButton, ( value != 0 ) );
|
||||
} else {
|
||||
//assert( !"Unknown joystick event" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sys_EndJoystickInputEvents();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1065,7 +1294,9 @@ void idUsercmdGenLocal::UsercmdInterrupt( void ) {
|
|||
Keyboard();
|
||||
|
||||
// process the system joystick events
|
||||
Joystick();
|
||||
if ( in_useJoystick.GetBool() ) {
|
||||
Joystick();
|
||||
}
|
||||
|
||||
// create the usercmd for com_ticNumber+1
|
||||
MakeCurrent();
|
||||
|
@ -1095,6 +1326,11 @@ idUsercmdGenLocal::GetDirectUsercmd
|
|||
*/
|
||||
usercmd_t idUsercmdGenLocal::GetDirectUsercmd( void ) {
|
||||
|
||||
pollTime = Sys_Milliseconds();
|
||||
if ( pollTime - lastPollTime > 100 ) {
|
||||
lastPollTime = pollTime - 100;
|
||||
}
|
||||
|
||||
// initialize current usercmd
|
||||
InitCurrent();
|
||||
|
||||
|
@ -1105,12 +1341,15 @@ usercmd_t idUsercmdGenLocal::GetDirectUsercmd( void ) {
|
|||
Keyboard();
|
||||
|
||||
// process the system joystick events
|
||||
Joystick();
|
||||
|
||||
if ( in_useJoystick.GetBool() ) {
|
||||
Joystick();
|
||||
}
|
||||
// create the usercmd
|
||||
MakeCurrent();
|
||||
|
||||
cmd.duplicateCount = 0;
|
||||
|
||||
lastPollTime = pollTime;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
|
|
@ -108,8 +108,26 @@ struct mouse_poll_t {
|
|||
}
|
||||
};
|
||||
|
||||
struct joystick_poll_t {
|
||||
int action;
|
||||
int value;
|
||||
|
||||
joystick_poll_t() : action(0), value(0) {} // TODO: or -1?
|
||||
|
||||
joystick_poll_t(int a, int v) {
|
||||
action = a;
|
||||
value = v;
|
||||
}
|
||||
};
|
||||
|
||||
static idList<kbd_poll_t> kbd_polls;
|
||||
static idList<mouse_poll_t> mouse_polls;
|
||||
static idList<joystick_poll_t> joystick_polls;
|
||||
|
||||
static bool buttonStates[K_LAST_KEY];
|
||||
static int joyAxis[MAX_JOYSTICK_AXIS];
|
||||
|
||||
static idList<sysEvent_t> event_overflow;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
// for utf8ToISO8859_1() - used for non-ascii text input and Sys_GetLocalizedScancodeName()
|
||||
|
@ -477,6 +495,73 @@ static byte mapkey(SDL_Keycode key) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static sys_jEvents mapjoybutton(SDL_GameControllerButton button) {
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case SDL_CONTROLLER_BUTTON_A:
|
||||
return J_ACTION1;
|
||||
case SDL_CONTROLLER_BUTTON_B:
|
||||
return J_ACTION2;
|
||||
case SDL_CONTROLLER_BUTTON_X:
|
||||
return J_ACTION3;
|
||||
case SDL_CONTROLLER_BUTTON_Y:
|
||||
return J_ACTION4;
|
||||
case SDL_CONTROLLER_BUTTON_BACK:
|
||||
return J_ACTION10;
|
||||
case SDL_CONTROLLER_BUTTON_GUIDE:
|
||||
// TODO:
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_START:
|
||||
return J_ACTION9;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
||||
return J_ACTION7;
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
|
||||
return J_ACTION8;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
||||
return J_ACTION5;
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
||||
return J_ACTION6;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||
return J_DPAD_UP;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||
return J_DPAD_DOWN;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||
return J_DPAD_LEFT;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||
return J_DPAD_RIGHT;
|
||||
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:
|
||||
return J_AXIS_LEFT_X;
|
||||
case SDL_CONTROLLER_AXIS_LEFTY:
|
||||
return J_AXIS_LEFT_Y;
|
||||
case SDL_CONTROLLER_AXIS_RIGHTX:
|
||||
return J_AXIS_RIGHT_X;
|
||||
case SDL_CONTROLLER_AXIS_RIGHTY:
|
||||
return J_AXIS_RIGHT_Y;
|
||||
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
||||
return J_AXIS_LEFT_TRIG;
|
||||
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
||||
return J_AXIS_RIGHT_TRIG;
|
||||
default:
|
||||
common->Warning("unknown game controller axis %u", axis);
|
||||
break;
|
||||
}
|
||||
|
||||
return J_AXIS_MAX;
|
||||
}
|
||||
|
||||
static void PushConsoleEvent(const char *s) {
|
||||
char *b;
|
||||
size_t len;
|
||||
|
@ -531,6 +616,19 @@ void Sys_InitInput() {
|
|||
#else // SDL1.2 doesn't support this
|
||||
in_grabKeyboard.ClearModified();
|
||||
#endif
|
||||
|
||||
joystick_polls.SetGranularity(64);
|
||||
event_overflow.SetGranularity(64);
|
||||
|
||||
memset( buttonStates, 0, sizeof( buttonStates ) );
|
||||
memset( joyAxis, 0, sizeof( joyAxis ) );
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -541,6 +639,8 @@ Sys_ShutdownInput
|
|||
void Sys_ShutdownInput() {
|
||||
kbd_polls.Clear();
|
||||
mouse_polls.Clear();
|
||||
joystick_polls.Clear();
|
||||
event_overflow.Clear();
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
SDL_iconv_close( iconvDesc ); // used by utf8ToISO8859_1()
|
||||
iconvDesc = ( SDL_iconv_t ) -1;
|
||||
|
@ -666,6 +766,18 @@ void Sys_GrabMouseCursor(bool grabIt) {
|
|||
GLimp_GrabInput(flags);
|
||||
}
|
||||
|
||||
|
||||
static void PushButton( int key, bool value ) {
|
||||
// So we don't keep sending the same SE_KEY message over and over again
|
||||
if ( buttonStates[key] != value ) {
|
||||
buttonStates[key] = value;
|
||||
sysEvent_t res = { SE_KEY, key, value ? 1 : 0, 0, NULL };
|
||||
// this is done to generate two events per controller axis event
|
||||
// one SE_JOYSTICK and one SE_KEY
|
||||
event_overflow.Append(res);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetEvent
|
||||
|
@ -678,6 +790,14 @@ sysEvent_t Sys_GetEvent() {
|
|||
|
||||
static const sysEvent_t res_none = { SE_NONE, 0, 0, 0, NULL };
|
||||
|
||||
// process any overflow.
|
||||
if (event_overflow.Num() > 0)
|
||||
{
|
||||
res = event_overflow[0];
|
||||
event_overflow.RemoveIndex(0);
|
||||
return res;
|
||||
}
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
static char s[SDL_TEXTINPUTEVENT_TEXT_SIZE] = {0};
|
||||
static size_t s_pos = 0;
|
||||
|
@ -958,6 +1078,76 @@ sysEvent_t Sys_GetEvent() {
|
|||
|
||||
return res;
|
||||
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_CONTROLLERBUTTONUP:
|
||||
{
|
||||
sys_jEvents jEvent = mapjoybutton( (SDL_GameControllerButton)ev.cbutton.button);
|
||||
joystick_polls.Append(joystick_poll_t(jEvent, ev.cbutton.state == SDL_PRESSED ? 1 : 0) );
|
||||
|
||||
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 );
|
||||
return res;
|
||||
} else if ( ( jEvent >= J_DPAD_UP ) && ( jEvent <= J_DPAD_RIGHT ) ) {
|
||||
res.evValue = K_JOY_DPAD_UP + ( jEvent - J_DPAD_UP );
|
||||
return res;
|
||||
}
|
||||
|
||||
continue; // try to get a decent event.
|
||||
}
|
||||
|
||||
case SDL_CONTROLLERAXISMOTION:
|
||||
{
|
||||
const int range = 16384;
|
||||
|
||||
sys_jEvents jEvent = mapjoyaxis( (SDL_GameControllerAxis)ev.caxis.axis);
|
||||
joystick_polls.Append(joystick_poll_t( jEvent, ev.caxis.value) );
|
||||
|
||||
if ( jEvent == J_AXIS_LEFT_X ) {
|
||||
PushButton( K_JOY_STICK1_LEFT, ( ev.caxis.value < -range ) );
|
||||
PushButton( K_JOY_STICK1_RIGHT, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_LEFT_Y ) {
|
||||
PushButton( K_JOY_STICK1_UP, ( ev.caxis.value < -range ) );
|
||||
PushButton( K_JOY_STICK1_DOWN, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_RIGHT_X ) {
|
||||
PushButton( K_JOY_STICK2_LEFT, ( ev.caxis.value < -range ) );
|
||||
PushButton( K_JOY_STICK2_RIGHT, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_RIGHT_Y ) {
|
||||
PushButton( K_JOY_STICK2_UP, ( ev.caxis.value < -range ) );
|
||||
PushButton( K_JOY_STICK2_DOWN, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_LEFT_TRIG ) {
|
||||
PushButton( K_JOY_TRIGGER1, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_RIGHT_TRIG ) {
|
||||
PushButton( K_JOY_TRIGGER2, ( ev.caxis.value > range ) );
|
||||
}
|
||||
if ( jEvent >= J_AXIS_MIN && jEvent <= J_AXIS_MAX ) {
|
||||
int axis = jEvent - J_AXIS_MIN;
|
||||
int percent = ( ev.caxis.value * 16 ) / range;
|
||||
if ( joyAxis[axis] != percent ) {
|
||||
joyAxis[axis] = percent;
|
||||
res.evType = SE_JOYSTICK;
|
||||
res.evValue = axis;
|
||||
res.evValue2 = percent;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
continue; // try to get a decent event.
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_JOYDEVICEADDED:
|
||||
SDL_GameControllerOpen( ev.jdevice.which );
|
||||
// TODO: hot swapping maybe.
|
||||
//lbOnControllerPlugIn(event.jdevice.which);
|
||||
break;
|
||||
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
// TODO: hot swapping maybe.
|
||||
//lbOnControllerUnPlug(event.jdevice.which);
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
PushConsoleEvent("quit");
|
||||
return res_none;
|
||||
|
@ -996,6 +1186,12 @@ void Sys_ClearEvents() {
|
|||
|
||||
kbd_polls.SetNum(0, false);
|
||||
mouse_polls.SetNum(0, false);
|
||||
joystick_polls.SetNum(0, false);
|
||||
|
||||
memset( buttonStates, 0, sizeof( buttonStates ) );
|
||||
memset( joyAxis, 0, sizeof( joyAxis ) );
|
||||
|
||||
event_overflow.SetNum(0, false);
|
||||
}
|
||||
|
||||
static void handleMouseGrab() {
|
||||
|
@ -1146,3 +1342,35 @@ Sys_EndMouseInputEvents
|
|||
void Sys_EndMouseInputEvents() {
|
||||
mouse_polls.SetNum(0, false);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Joystick Input Methods
|
||||
================
|
||||
*/
|
||||
void Sys_SetRumble( int device, int low, int hi ) {
|
||||
// TODO: support multiple controllers.
|
||||
assert(device == 0);
|
||||
// TODO: support rumble maybe.
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int Sys_PollJoystickInputEvents( int deviceNum ) {
|
||||
// TODO: support multiple controllers.
|
||||
assert(deviceNum == 0);
|
||||
return joystick_polls.Num();
|
||||
}
|
||||
|
||||
int Sys_ReturnJoystickInputEvent( const int n, int &action, int &value ) {
|
||||
if (n >= joystick_polls.Num())
|
||||
return 0;
|
||||
|
||||
action = joystick_polls[n].action;
|
||||
value = joystick_polls[n].value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Sys_EndJoystickInputEvents() {
|
||||
joystick_polls.SetNum(0, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,12 +44,12 @@ typedef enum {
|
|||
} cpuidSimd_t;
|
||||
|
||||
typedef enum {
|
||||
AXIS_SIDE,
|
||||
AXIS_FORWARD,
|
||||
AXIS_UP,
|
||||
AXIS_ROLL,
|
||||
AXIS_YAW,
|
||||
AXIS_PITCH,
|
||||
AXIS_LEFT_X,
|
||||
AXIS_LEFT_Y,
|
||||
AXIS_RIGHT_X,
|
||||
AXIS_RIGHT_Y,
|
||||
AXIS_LEFT_TRIG,
|
||||
AXIS_RIGHT_TRIG,
|
||||
MAX_JOYSTICK_AXIS
|
||||
} joystickAxis_t;
|
||||
|
||||
|
@ -59,7 +59,7 @@ typedef enum {
|
|||
SE_CHAR, // evValue is an ascii char
|
||||
SE_MOUSE, // evValue and evValue2 are relative signed x / y moves
|
||||
SE_MOUSE_ABS, // evValue and evValue2 are absolute x / y coordinates in the window
|
||||
SE_JOYSTICK_AXIS, // evValue is an axis number and evValue2 is the current state (-127 to 127)
|
||||
SE_JOYSTICK, // evValue is an axis number and evValue2 is the current state (-127 to 127)
|
||||
SE_CONSOLE // evPtr is a char*, from typing something at a non-game console
|
||||
} sysEventType_t;
|
||||
|
||||
|
@ -77,6 +77,59 @@ typedef enum {
|
|||
M_DELTAZ
|
||||
} 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_AXIS_MIN,
|
||||
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,
|
||||
J_AXIS_RIGHT_Y = J_AXIS_MIN + AXIS_RIGHT_Y,
|
||||
J_AXIS_LEFT_TRIG = J_AXIS_MIN + AXIS_LEFT_TRIG,
|
||||
J_AXIS_RIGHT_TRIG = J_AXIS_MIN + AXIS_RIGHT_TRIG,
|
||||
|
||||
J_AXIS_MAX = J_AXIS_MIN + MAX_JOYSTICK_AXIS - 1,
|
||||
|
||||
J_DPAD_UP,
|
||||
J_DPAD_DOWN,
|
||||
J_DPAD_LEFT,
|
||||
J_DPAD_RIGHT,
|
||||
|
||||
MAX_JOY_EVENT
|
||||
} sys_jEvents;
|
||||
|
||||
struct sysEvent_t {
|
||||
sysEventType_t evType;
|
||||
int evValue;
|
||||
|
@ -189,6 +242,12 @@ int Sys_PollMouseInputEvents( void );
|
|||
int Sys_ReturnMouseInputEvent( const int n, int &action, int &value );
|
||||
void Sys_EndMouseInputEvents( void );
|
||||
|
||||
// joystick input polling
|
||||
void Sys_SetRumble( int device, int low, int hi );
|
||||
int Sys_PollJoystickInputEvents( int deviceNum );
|
||||
int Sys_ReturnJoystickInputEvent( const int n, int &action, int &value );
|
||||
void Sys_EndJoystickInputEvents();
|
||||
|
||||
// when the console is down, or the game is about to perform a lengthy
|
||||
// operation like map loading, the system can release the mouse cursor
|
||||
// when in windowed mode
|
||||
|
|
|
@ -736,7 +736,7 @@ const char *idWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals)
|
|||
*updateVisuals = true;
|
||||
}
|
||||
|
||||
if (event->evValue == K_MOUSE1) {
|
||||
if (event->evValue == K_MOUSE1 || event->evValue == K_JOY2) {
|
||||
|
||||
if (!event->evValue2 && GetCaptureChild()) {
|
||||
GetCaptureChild()->LoseCapture();
|
||||
|
@ -785,7 +785,7 @@ const char *idWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals)
|
|||
} else if (!actionUpRun) {
|
||||
actionUpRun = RunScript( ON_ACTIONRELEASE );
|
||||
}
|
||||
} else if (event->evValue == K_MOUSE2) {
|
||||
} else if (event->evValue == K_MOUSE2 || event->evValue == K_JOY1) {
|
||||
|
||||
if (!event->evValue2 && GetCaptureChild()) {
|
||||
GetCaptureChild()->LoseCapture();
|
||||
|
|
Loading…
Reference in a new issue