mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-15 07:00:58 +00:00
* SDL joystick/gamepad support implemented and working.
* Tested in Linux with both XBox360 wireless and Logitech F710 gamepads. Should work with any XBox gamepad clone wired/wireless. * Works well using SDL 1.2 or SDL 2.0 * SDL scan values are currently hard-coded. Note sure how to implement remapping at the moment (config file, GUI, ...).
This commit is contained in:
parent
46180de310
commit
bc6cab3ab0
2 changed files with 365 additions and 22 deletions
|
@ -436,11 +436,13 @@ void idPlayerProfile::ExecConfig( bool save, bool forceDefault )
|
|||
|
||||
if( leftyFlip )
|
||||
{
|
||||
cmdSystem->AppendCommandText( "exec joy_lefty.cfg" );
|
||||
cmdSystem->AppendCommandText( "exec joy_lefty.cfg\n" );
|
||||
cmdSystem->AppendCommandText( "exec joy_360_0.cfg\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdSystem->AppendCommandText( "exec joy_righty.cfg" );
|
||||
cmdSystem->AppendCommandText( "exec joy_righty.cfg\n" );
|
||||
cmdSystem->AppendCommandText( "exec joy_360_0.cfg\n" );
|
||||
}
|
||||
|
||||
cmdSystem->ExecuteCommandBuffer();
|
||||
|
|
|
@ -116,6 +116,25 @@ struct mouse_poll_t
|
|||
static idList<kbd_poll_t> kbd_polls;
|
||||
static idList<mouse_poll_t> mouse_polls;
|
||||
|
||||
struct joystick_poll_t
|
||||
{
|
||||
int action;
|
||||
int value;
|
||||
|
||||
joystick_poll_t()
|
||||
{
|
||||
}
|
||||
|
||||
joystick_poll_t( int a, int v )
|
||||
{
|
||||
action = a;
|
||||
value = v;
|
||||
}
|
||||
};
|
||||
static idList<joystick_poll_t> joystick_polls;
|
||||
SDL_Joystick *joy = NULL;
|
||||
int SDL_joystick_has_hat = 0;
|
||||
|
||||
// RB begin
|
||||
static int SDL_KeyToDoom3Key( SDL_Keycode key, bool& isChar )
|
||||
{
|
||||
|
@ -551,6 +570,8 @@ Sys_InitInput
|
|||
*/
|
||||
void Sys_InitInput()
|
||||
{
|
||||
int numJoysticks, i;
|
||||
|
||||
kbd_polls.SetGranularity( 64 );
|
||||
mouse_polls.SetGranularity( 64 );
|
||||
|
||||
|
@ -558,8 +579,54 @@ void Sys_InitInput()
|
|||
SDL_EnableUNICODE( 1 );
|
||||
SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
|
||||
#endif
|
||||
|
||||
in_keyboard.SetModified();
|
||||
|
||||
// WM0110: Initialise SDL Joystick
|
||||
common->Printf( "Sys_InitInput: Joystick subsystem init\n" );
|
||||
if( SDL_Init(SDL_INIT_JOYSTICK) ) {
|
||||
common->Printf( "Sys_InitInput: Joystic Init ERROR!\n");
|
||||
}
|
||||
|
||||
numJoysticks = SDL_NumJoysticks();
|
||||
common->Printf( "Sys_InitInput: Joystic - Found %i joysticks\n", numJoysticks);
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
for(i=0; i<numJoysticks; i++)
|
||||
common->Printf(" Joystick %i name '%s'\n", i, SDL_JoystickName(i));
|
||||
#endif
|
||||
|
||||
// Open first available joystick and use it
|
||||
if(SDL_NumJoysticks() > 0) {
|
||||
joy = SDL_JoystickOpen(0);
|
||||
|
||||
if(joy) {
|
||||
int num_hats;
|
||||
|
||||
num_hats = SDL_JoystickNumHats(joy);
|
||||
common->Printf("Opened Joystick number 0\n");
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
common->Printf("Name: %s\n", SDL_JoystickName(joy));
|
||||
#else
|
||||
common->Printf("Name: %s\n", SDL_JoystickName(0));
|
||||
#endif
|
||||
common->Printf("Number of Axes: %d\n", SDL_JoystickNumAxes(joy));
|
||||
common->Printf("Number of Buttons: %d\n", SDL_JoystickNumButtons(joy));
|
||||
common->Printf("Number of Hats: %d\n", num_hats);
|
||||
common->Printf("Number of Balls: %d\n", SDL_JoystickNumBalls(joy));
|
||||
|
||||
SDL_joystick_has_hat = 0;
|
||||
if(num_hats) {
|
||||
SDL_joystick_has_hat = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
joy = NULL;
|
||||
common->Printf("Couldn't open Joystick 0\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
joy = NULL;
|
||||
}
|
||||
// WM0110
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -571,6 +638,15 @@ void Sys_ShutdownInput()
|
|||
{
|
||||
kbd_polls.Clear();
|
||||
mouse_polls.Clear();
|
||||
joystick_polls.Clear();
|
||||
|
||||
// Close any opened SDL Joystic
|
||||
if(joy) {
|
||||
common->Printf("Sys_ShutdownInput: closing SDL joystick.\n");
|
||||
SDL_JoystickClose(joy);
|
||||
} else {
|
||||
common->Printf("Sys_ShutdownInput: SDL joystick not initialized. Nothing to close.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -681,9 +757,11 @@ sysEvent_t Sys_GetEvent()
|
|||
SDL_Event ev;
|
||||
sysEvent_t res = { };
|
||||
int key;
|
||||
|
||||
static const sysEvent_t res_none = { SE_NONE, 0, 0, 0, NULL };
|
||||
|
||||
|
||||
// WM0110: previous state of joystick hat
|
||||
static int previous_hat_state = SDL_HAT_CENTERED;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
static char* s = NULL;
|
||||
static size_t s_pos = 0;
|
||||
|
@ -870,7 +948,7 @@ sysEvent_t Sys_GetEvent()
|
|||
// DG end
|
||||
#endif
|
||||
|
||||
// fall through
|
||||
// fall through
|
||||
case SDL_KEYUP:
|
||||
{
|
||||
bool isChar;
|
||||
|
@ -990,7 +1068,7 @@ sysEvent_t Sys_GetEvent()
|
|||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
res.evType = SE_KEY;
|
||||
|
||||
|
||||
switch( ev.button.button )
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
|
@ -1019,15 +1097,264 @@ sysEvent_t Sys_GetEvent()
|
|||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
res.evValue2 = ev.button.state == SDL_PRESSED ? 1 : 0;
|
||||
|
||||
return res;
|
||||
|
||||
|
||||
// WM0110
|
||||
// NOTE: it seems that the key bindings for the GUI and for the game are
|
||||
// totally independant. I think the event returned by this function seems to work
|
||||
// on the GUI and the event returned by Sys_ReturnJoystickInputEvent() works on
|
||||
// the game.
|
||||
// Also, remember that joystick keys must be binded to actions in order to work!
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
// sys_public.h: evValue is an axis number and evValue2 is the current state (-127 to 127)
|
||||
// WM0110: joystick ranges must be between (-32769, 32768)!
|
||||
res.evType = SE_KEY;
|
||||
switch( ev.jbutton.button )
|
||||
{
|
||||
case 0:
|
||||
res.evValue = K_JOY1;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION1, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
res.evValue = K_JOY2;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION2, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
res.evValue = K_JOY3;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION3, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
res.evValue = K_JOY4;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION4, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
res.evValue = K_JOY5;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION5, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 5:
|
||||
res.evValue = K_JOY6;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION6, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 6:
|
||||
res.evValue = K_JOY7;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION7, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 7:
|
||||
res.evValue = K_JOY8;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION8, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 8:
|
||||
res.evValue = K_JOY9;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION9, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 9:
|
||||
res.evValue = K_JOY10;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION10, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
case 10:
|
||||
res.evValue = K_JOY11;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION11, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
break;
|
||||
|
||||
// D-PAD left (XBox 360 wireless)
|
||||
case 11:
|
||||
// If joystick has a hat, then use the hat as D-PAD. If not, D-PAD is mapped
|
||||
// to buttons.
|
||||
if(SDL_joystick_has_hat) {
|
||||
res.evValue = K_JOY12;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION12, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
} else {
|
||||
res.evValue = K_JOY_DPAD_LEFT;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_LEFT, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
}
|
||||
break;
|
||||
|
||||
// D-PAD right
|
||||
case 12:
|
||||
if(SDL_joystick_has_hat) {
|
||||
res.evValue = K_JOY13;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION13, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
} else {
|
||||
res.evValue = K_JOY_DPAD_RIGHT;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_RIGHT, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
}
|
||||
break;
|
||||
|
||||
// D-PAD up
|
||||
case 13:
|
||||
if(SDL_joystick_has_hat) {
|
||||
res.evValue = K_JOY14;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION14, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
} else {
|
||||
res.evValue = K_JOY_DPAD_UP;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_UP, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
}
|
||||
break;
|
||||
|
||||
// D-PAD down
|
||||
case 14:
|
||||
if(SDL_joystick_has_hat) {
|
||||
res.evValue = K_JOY15;
|
||||
joystick_polls.Append( joystick_poll_t( J_ACTION15, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
} else {
|
||||
res.evValue = K_JOY_DPAD_DOWN;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_DOWN, ev.jbutton.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
common->Warning( "Sys_GetEvent(): Unknown joystick button number %i\n", ev.jbutton.button );
|
||||
return res_none;
|
||||
}
|
||||
res.evValue2 = ev.jbutton.state == SDL_PRESSED ? 1 : 0;
|
||||
|
||||
return res;
|
||||
|
||||
case SDL_JOYHATMOTION:
|
||||
// If this is not the first hat, ignore this event.
|
||||
if(ev.jhat.which != 0)
|
||||
return res_none;
|
||||
|
||||
res.evType = SE_KEY;
|
||||
if(ev.jhat.value & SDL_HAT_UP) {
|
||||
res.evValue = K_JOY_DPAD_UP;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_UP, 1 ) );
|
||||
res.evValue2 = 1;
|
||||
previous_hat_state = J_DPAD_UP;
|
||||
}
|
||||
else if (ev.jhat.value & SDL_HAT_DOWN) {
|
||||
res.evValue = K_JOY_DPAD_DOWN;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_DOWN, 1 ) );
|
||||
res.evValue2 = 1;
|
||||
previous_hat_state = J_DPAD_DOWN;
|
||||
}
|
||||
else if (ev.jhat.value & SDL_HAT_RIGHT) {
|
||||
res.evValue = K_JOY_DPAD_RIGHT;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_RIGHT, 1 ) );
|
||||
res.evValue2 = 1;
|
||||
previous_hat_state = J_DPAD_RIGHT;
|
||||
}
|
||||
else if (ev.jhat.value & SDL_HAT_LEFT) {
|
||||
res.evValue = K_JOY_DPAD_LEFT;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_LEFT, 1 ) );
|
||||
res.evValue2 = 1;
|
||||
previous_hat_state = J_DPAD_LEFT;
|
||||
}
|
||||
// SDL_HAT_CENTERED is defined as 0
|
||||
else if (ev.jhat.value == SDL_HAT_CENTERED) {
|
||||
// We need to know the previous state to know which event to send.
|
||||
if(previous_hat_state == J_DPAD_UP) {
|
||||
res.evValue = K_JOY_DPAD_UP;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_UP, 0 ) );
|
||||
res.evValue2 = 0;
|
||||
}
|
||||
else if(previous_hat_state == J_DPAD_DOWN) {
|
||||
res.evValue = K_JOY_DPAD_DOWN;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_DOWN, 0 ) );
|
||||
res.evValue2 = 0;
|
||||
}
|
||||
else if(previous_hat_state == J_DPAD_RIGHT) {
|
||||
res.evValue = K_JOY_DPAD_RIGHT;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_RIGHT, 0 ) );
|
||||
res.evValue2 = 0;
|
||||
}
|
||||
else if(previous_hat_state == J_DPAD_LEFT) {
|
||||
res.evValue = K_JOY_DPAD_LEFT;
|
||||
joystick_polls.Append( joystick_poll_t( J_DPAD_LEFT, 0 ) );
|
||||
res.evValue2 = 0;
|
||||
}
|
||||
else if(previous_hat_state == SDL_HAT_CENTERED) {
|
||||
common->Warning( "Sys_GetEvent(): SDL_JOYHATMOTION: previous state SDL_HAT_CENTERED repeated!\n" );
|
||||
return res_none;
|
||||
}
|
||||
else {
|
||||
common->Warning( "Sys_GetEvent(): SDL_JOYHATMOTION: unknown previous hat state %i\n", previous_hat_state );
|
||||
return res_none;
|
||||
}
|
||||
|
||||
previous_hat_state = SDL_HAT_CENTERED;
|
||||
}
|
||||
else {
|
||||
common->Warning( "Sys_GetEvent(): Unknown SDL_JOYHATMOTION value %i\n", ev.jhat.value );
|
||||
return res_none;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
case SDL_JOYAXISMOTION:
|
||||
res.evType = SE_JOYSTICK;
|
||||
// SDL joystick range is: -32768 to 32767, which is what is expected
|
||||
// in void idUsercmdGenLocal::Joystick( int deviceNum ).
|
||||
switch( ev.jaxis.axis )
|
||||
{
|
||||
int trigger_value;
|
||||
|
||||
// LEFT trigger
|
||||
case 2:
|
||||
// Convert TRIGGER value from space (-32768, 32767) to (0, 32767)
|
||||
trigger_value = (ev.jaxis.value + 32768) / 2;
|
||||
// common->Printf("Sys_GetEvent: LEFT trigger value = %i / converted value = %i\n", ev.jaxis.value, trigger_value);
|
||||
res.evValue = J_AXIS_LEFT_TRIG;
|
||||
joystick_polls.Append( joystick_poll_t( J_AXIS_LEFT_TRIG, trigger_value ) );
|
||||
break;
|
||||
|
||||
// Right trigger
|
||||
case 5:
|
||||
trigger_value = (ev.jaxis.value + 32768) / 2;
|
||||
// common->Printf("Sys_GetEvent: RIGHT trigger value = %i / converted value = %i\n", ev.jaxis.value, trigger_value);
|
||||
res.evValue = J_AXIS_RIGHT_TRIG;
|
||||
joystick_polls.Append( joystick_poll_t( J_AXIS_RIGHT_TRIG, trigger_value ) );
|
||||
break;
|
||||
|
||||
// LEFT X
|
||||
case 0:
|
||||
res.evValue = J_AXIS_LEFT_X;
|
||||
joystick_polls.Append( joystick_poll_t( J_AXIS_LEFT_X, ev.jaxis.value ) );
|
||||
break;
|
||||
|
||||
// LEFT Y
|
||||
case 1:
|
||||
res.evValue = J_AXIS_LEFT_Y;
|
||||
joystick_polls.Append( joystick_poll_t( J_AXIS_LEFT_Y, ev.jaxis.value ) );
|
||||
break;
|
||||
|
||||
// RIGHT X
|
||||
case 3:
|
||||
res.evValue = J_AXIS_RIGHT_X;
|
||||
joystick_polls.Append( joystick_poll_t( J_AXIS_RIGHT_X, ev.jaxis.value ) );
|
||||
break;
|
||||
|
||||
// RIGHT Y
|
||||
case 4:
|
||||
res.evValue = J_AXIS_RIGHT_Y;
|
||||
joystick_polls.Append( joystick_poll_t( J_AXIS_RIGHT_Y, ev.jaxis.value ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
common->Warning( "Sys_GetEvent(): Unknown joystick axis number %i\n", ev.jaxis.axis );
|
||||
return res_none;
|
||||
}
|
||||
|
||||
return res;
|
||||
// WM0110
|
||||
|
||||
case SDL_QUIT:
|
||||
PushConsoleEvent( "quit" );
|
||||
return res_none;
|
||||
|
||||
|
||||
case SDL_USEREVENT:
|
||||
switch( ev.user.code )
|
||||
{
|
||||
|
@ -1036,16 +1363,18 @@ sysEvent_t Sys_GetEvent()
|
|||
res.evPtrLength = ( intptr_t )ev.user.data1;
|
||||
res.evPtr = ev.user.data2;
|
||||
return res;
|
||||
|
||||
default:
|
||||
common->Warning( "unknown user event %u", ev.user.code );
|
||||
common->Warning( "Sys_GetEvent: unknown SDL_USEREVENT %u", ev.user.code );
|
||||
return res_none;
|
||||
}
|
||||
|
||||
default:
|
||||
common->Warning( "unknown event %u", ev.type );
|
||||
common->Warning( "Sys_GetEvent: unknown SDL event %u", ev.type );
|
||||
return res_none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return res_none;
|
||||
}
|
||||
|
||||
|
@ -1150,25 +1479,37 @@ int Sys_PollMouseInputEvents( int mouseEvents[MAX_MOUSE_EVENTS][2] )
|
|||
void Sys_SetRumble( int device, int low, int hi )
|
||||
{
|
||||
// TODO;
|
||||
// SDL 2.0 required (SDL Haptic subsystem)
|
||||
}
|
||||
|
||||
int Sys_PollJoystickInputEvents( int deviceNum )
|
||||
{
|
||||
// TODO;
|
||||
return 0;
|
||||
int numEvents = joystick_polls.Num();
|
||||
|
||||
return numEvents;
|
||||
}
|
||||
|
||||
|
||||
// This funcion called by void idUsercmdGenLocal::Joystick( int deviceNum ) in
|
||||
// file UsercmdGen.cpp
|
||||
// action - must have values belonging to enum sys_jEvents (sys_public.h)
|
||||
// value - must be 1/0 for button or DPAD pressed/released
|
||||
// for joystick axes must be in the range (-32769, 32768)
|
||||
// for joystick trigger must be in the range (0, 32768)
|
||||
int Sys_ReturnJoystickInputEvent( const int n, int& action, int& value )
|
||||
{
|
||||
// TODO;
|
||||
return 0;
|
||||
// Get last element of the list and copy into argument references
|
||||
const joystick_poll_t& mp = joystick_polls[n];
|
||||
action = mp.action;
|
||||
value = mp.value;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// This funcion called by void idUsercmdGenLocal::Joystick( int deviceNum ) in
|
||||
// file UsercmdGen.cpp
|
||||
void Sys_EndJoystickInputEvents()
|
||||
{
|
||||
// Empty the joystick event container. This is called after
|
||||
// all joystick events have been read using Sys_ReturnJoystickInputEvent()
|
||||
joystick_polls.SetNum( 0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue