mirror of
https://github.com/dhewm/dhewm3.git
synced 2025-03-22 02:31:03 +00:00
Make PDA work with gamepad, incl. making Pad A emulate leftclick
this is a bit hacky and ugly, and doesn't work properly in multiplayer mode yet, see FIXME in idUserInterfaceLocal::Activate()
This commit is contained in:
parent
e0bb01ef52
commit
03ec74fd6f
4 changed files with 90 additions and 11 deletions
|
@ -353,6 +353,7 @@ private:
|
|||
void CircleToSquare( float & axis_x, float & axis_y ) const;
|
||||
void HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive );
|
||||
void JoystickMove( void );
|
||||
void JoystickFakeMouse(float axis_x, float axis_y, float deadzone);
|
||||
void MouseMove( void );
|
||||
void CmdButtons( void );
|
||||
|
||||
|
@ -429,7 +430,7 @@ idCVar idUsercmdGenLocal::m_strafeSmooth( "m_strafeSmooth", "4", CVAR_SYSTEM | C
|
|||
idCVar idUsercmdGenLocal::m_showMouseRate( "m_showMouseRate", "0", CVAR_SYSTEM | CVAR_BOOL, "shows mouse movement" );
|
||||
|
||||
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_deadZone( "joy_deadZone", "0.25", 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" );
|
||||
|
@ -870,6 +871,33 @@ void idUsercmdGenLocal::HandleJoystickAxis( int keyNum, float unclampedValue, fl
|
|||
}
|
||||
}
|
||||
|
||||
static float joyAxisToMouseDelta(float axis, float deadzone)
|
||||
{
|
||||
float ret = 0.0f;
|
||||
float val = fabsf(axis); // calculations below require a positive value
|
||||
if(val > deadzone) {
|
||||
// from deadzone .. 1 to 0 .. 1-deadzone
|
||||
val -= deadzone;
|
||||
// and then to 0..1
|
||||
val = val * (1.0f / (1.0f - deadzone));
|
||||
|
||||
// make it exponential curve - exp(val*3) should return sth between 1 and 20;
|
||||
// then turning that into 0.5 .. 10
|
||||
ret = expf( val * 3.0f ) * 0.5f;
|
||||
if(axis < 0.0f) // restore sign
|
||||
ret = -ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void idUsercmdGenLocal::JoystickFakeMouse(float axis_x, float axis_y, float deadzone)
|
||||
{
|
||||
float x = joyAxisToMouseDelta(axis_x, deadzone);
|
||||
float y = joyAxisToMouseDelta(axis_y, deadzone);
|
||||
continuousMouseX += x;
|
||||
continuousMouseY += y;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idUsercmdGenLocal::JoystickMove
|
||||
|
@ -888,6 +916,8 @@ void idUsercmdGenLocal::JoystickMove() {
|
|||
HandleJoystickAxis( K_JOY_STICK1_LEFT, axis_x, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK1_RIGHT, axis_x, threshold, true );
|
||||
|
||||
JoystickFakeMouse( axis_x, axis_y, threshold );
|
||||
|
||||
axis_y = joystickAxis[ AXIS_RIGHT_Y ];
|
||||
axis_x = joystickAxis[ AXIS_RIGHT_X ];
|
||||
CircleToSquare( axis_x, axis_y );
|
||||
|
@ -897,6 +927,8 @@ void idUsercmdGenLocal::JoystickMove() {
|
|||
HandleJoystickAxis( K_JOY_STICK2_LEFT, axis_x, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK2_RIGHT, axis_x, threshold, true );
|
||||
|
||||
JoystickFakeMouse( axis_x, axis_y, threshold );
|
||||
|
||||
HandleJoystickAxis( K_JOY_TRIGGER1, joystickAxis[ AXIS_LEFT_TRIG ], triggerThreshold, true );
|
||||
HandleJoystickAxis( K_JOY_TRIGGER2, joystickAxis[ AXIS_RIGHT_TRIG ], triggerThreshold, true );
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#endif
|
||||
|
||||
extern idCVar in_useGamepad; // from UsercmdGen.cpp
|
||||
extern idCVar joy_deadZone; // ditto
|
||||
|
||||
// NOTE: g++-4.7 doesn't like when this is static (for idCmdSystem::ArgCompletion_String<kbdNames>)
|
||||
const char *_in_kbdNames[] = {
|
||||
|
@ -898,6 +899,25 @@ void Sys_GrabMouseCursor(bool grabIt) {
|
|||
GLimp_GrabInput(flags);
|
||||
}
|
||||
|
||||
static bool interactiveGuiActive = false;
|
||||
/*
|
||||
===============
|
||||
Sys_SetInteractiveIngameGuiActive
|
||||
Tell the input system that currently an interactive *ingame* UI has focus,
|
||||
so there is an active cursor.
|
||||
Used for an ungodly hack to make gamepad button south (A) behave like
|
||||
left mouse button in that case, so "clicking" with gamepad in the PDA
|
||||
(and ingame GUIs) works as expected.
|
||||
Not set for proper menus like main menu etc - the gamepad hacks for that
|
||||
are in idUserInterfaceLocal::HandleEvent().
|
||||
I hope this won't explode in my face :-p
|
||||
===============
|
||||
*/
|
||||
void Sys_SetInteractiveIngameGuiActive(bool active)
|
||||
{
|
||||
interactiveGuiActive = active;
|
||||
}
|
||||
|
||||
|
||||
static void PushButton( int key, bool value ) {
|
||||
// So we don't keep sending the same SE_KEY message over and over again
|
||||
|
@ -1218,20 +1238,27 @@ sysEvent_t Sys_GetEvent() {
|
|||
common->Warning( "Gamepad support is disabled! Set the in_useGamepad CVar to 1 to enable it!\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
res.evType = SE_KEY;
|
||||
res.evValue2 = ev.cbutton.state == SDL_PRESSED ? 1 : 0;
|
||||
|
||||
// special case: always treat the start button as escape so it opens/closes the menu
|
||||
// (also makes that button non-bindable)
|
||||
if ( ev.cbutton.button == SDL_CONTROLLER_BUTTON_START ) {
|
||||
res.evType = SE_KEY;
|
||||
res.evValue = K_ESCAPE;
|
||||
res.evValue2 = ev.cbutton.state == SDL_PRESSED ? 1 : 0;
|
||||
return res;
|
||||
} else if( ev.cbutton.button == SDL_CONTROLLER_BUTTON_A && interactiveGuiActive && sessLocal.GetActiveMenu() == NULL ) {
|
||||
// ugly hack: currently an interactive ingame GUI (with a cursor) is active/focused
|
||||
// so pretend that the gamepads A (south) button is the left mouse button
|
||||
// so it can be used for "clicking"..
|
||||
mouse_polls.Append( mouse_poll_t(M_ACTION1, res.evValue2) );
|
||||
res.evValue = K_MOUSE1;
|
||||
return res;
|
||||
}
|
||||
|
||||
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_ACTION_FIRST ) && ( jEvent <= J_ACTION_MAX ) ) {
|
||||
res.evValue = K_FIRST_JOY + ( jEvent - J_ACTION_FIRST );
|
||||
return res;
|
||||
|
@ -1274,18 +1301,28 @@ sysEvent_t Sys_GetEvent() {
|
|||
// NOTE: the stuff set here is only used to move the cursor in menus
|
||||
// ingame movement is done via joystick_polls
|
||||
int axis = jEvent - J_AXIS_MIN;
|
||||
float val = ev.caxis.value * (1.25f / 32767.0f);
|
||||
// 25% deadzone
|
||||
if( val < 0.0f ) {
|
||||
val = fminf(val + 0.25f, 0.0f);
|
||||
float dz = joy_deadZone.GetFloat();
|
||||
|
||||
float val = fabsf(ev.caxis.value * (1.0f / 32767.0f));
|
||||
if(val < dz) {
|
||||
val = 0.0f;
|
||||
} else {
|
||||
val = fmaxf(val - 0.25f, 0.0f);
|
||||
// from deadzone .. 1 to 0 .. 1-deadzone
|
||||
val -= dz;
|
||||
// and then to 0..1
|
||||
val = val * (1.0f / (1.0f - dz));
|
||||
|
||||
if( ev.caxis.value < 0 ) {
|
||||
val = -val;
|
||||
}
|
||||
}
|
||||
|
||||
joyAxis[axis] = val;
|
||||
}
|
||||
|
||||
continue; // try to get a decent event.
|
||||
// handle next event; joy axis events are generated below,
|
||||
// when there are no further SDL events
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -248,6 +248,11 @@ void Sys_EndJoystickInputEvents();
|
|||
// when in windowed mode
|
||||
void Sys_GrabMouseCursor( bool grabIt );
|
||||
|
||||
// DG: added this for an ungodly hack for gamepad support
|
||||
// active = true means "currently a GUI with a cursor is active/focused"
|
||||
// active = false means "that GUI is not active anymore"
|
||||
void Sys_SetInteractiveIngameGuiActive(bool active);
|
||||
|
||||
void Sys_ShowWindow( bool show );
|
||||
bool Sys_IsWindowVisible( void );
|
||||
void Sys_ShowConsole( int visLevel, bool quitOnClose );
|
||||
|
|
|
@ -582,6 +582,11 @@ const char *idUserInterfaceLocal::Activate(bool activate, int _time) {
|
|||
time = _time;
|
||||
active = activate;
|
||||
if ( desktop ) {
|
||||
// FIXME: this works ok, mostly, except in multiplayer, where this function
|
||||
// is called twice with activate=true, and the first time GetActiveMenu() returns NULL, the second time not
|
||||
if(interactive && sessLocal.GetActiveMenu() == NULL) {
|
||||
Sys_SetInteractiveIngameGuiActive(activate);
|
||||
}
|
||||
activateStr = "";
|
||||
desktop->Activate( activate, activateStr );
|
||||
return activateStr;
|
||||
|
|
Loading…
Reference in a new issue