2011-09-14 19:08:43 +00:00
/**
* * Supermodel
* * A Sega Model 3 Arcade Emulator .
* * Copyright 2011 Bart Trzynadlowski , Nik Henson
* *
* * This file is part of Supermodel .
* *
* * Supermodel is free software : you can redistribute it and / or modify it under
2020-04-19 08:34:58 +00:00
* * the terms of the GNU General Public License as published by the Free
2011-09-14 19:08:43 +00:00
* * Software Foundation , either version 3 of the License , or ( at your option )
* * any later version .
* *
* * Supermodel is distributed in the hope that it will be useful , but WITHOUT
* * ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* * FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* * more details .
* *
* * You should have received a copy of the GNU General Public License along
* * with Supermodel . If not , see < http : //www.gnu.org/licenses/>.
* */
2020-04-19 08:34:58 +00:00
2011-09-14 19:08:43 +00:00
/*
* SDLInputSystem . cpp
2020-04-19 08:34:58 +00:00
*
2011-09-14 19:08:43 +00:00
* Implementation of SDL input system .
2020-04-19 08:34:58 +00:00
*
* TODO :
* - - - - -
* - Implement multiple keyboard and mouse support .
2011-09-14 19:08:43 +00:00
*/
2020-07-27 10:28:48 +00:00
# include "SDLInputSystem.h"
2011-04-24 01:14:00 +00:00
2021-11-22 17:15:06 +00:00
# include "Supermodel.h"
# include "Inputs/Input.h"
2011-04-24 01:14:00 +00:00
# include <vector>
using namespace std ;
SDLKeyMapStruct CSDLInputSystem : : s_keyMap [ ] =
{
2020-04-19 08:34:58 +00:00
// General keys
{ " BACKSPACE " , SDL_SCANCODE_BACKSPACE } ,
{ " TAB " , SDL_SCANCODE_TAB } ,
{ " CLEAR " , SDL_SCANCODE_CLEAR } ,
{ " RETURN " , SDL_SCANCODE_RETURN } ,
{ " PAUSE " , SDL_SCANCODE_PAUSE } ,
{ " ESCAPE " , SDL_SCANCODE_ESCAPE } ,
{ " SPACE " , SDL_SCANCODE_SPACE } ,
{ " QUOTE " , SDL_SCANCODE_APOSTROPHE } ,
{ " LEFTPAREN " , SDL_SCANCODE_KP_LEFTPAREN } ,
{ " RIGHTPAREN " , SDL_SCANCODE_KP_RIGHTPAREN } ,
{ " COMMA " , SDL_SCANCODE_COMMA } ,
{ " MINUS " , SDL_SCANCODE_MINUS } ,
{ " PERIOD " , SDL_SCANCODE_PERIOD } ,
{ " SLASH " , SDL_SCANCODE_SLASH } ,
{ " 0 " , SDL_SCANCODE_0 } ,
{ " 1 " , SDL_SCANCODE_1 } ,
{ " 2 " , SDL_SCANCODE_2 } ,
{ " 3 " , SDL_SCANCODE_3 } ,
{ " 4 " , SDL_SCANCODE_4 } ,
{ " 5 " , SDL_SCANCODE_5 } ,
{ " 6 " , SDL_SCANCODE_6 } ,
{ " 7 " , SDL_SCANCODE_7 } ,
{ " 8 " , SDL_SCANCODE_8 } ,
{ " 9 " , SDL_SCANCODE_9 } ,
{ " SEMICOLON " , SDL_SCANCODE_SEMICOLON } ,
{ " EQUALS " , SDL_SCANCODE_EQUALS } ,
{ " LEFTBRACKET " , SDL_SCANCODE_LEFTBRACKET } ,
{ " BACKSLASH " , SDL_SCANCODE_BACKSLASH } ,
{ " RIGHTBRACKET " , SDL_SCANCODE_RIGHTBRACKET } ,
{ " BACKQUOTE " , SDL_SCANCODE_GRAVE } ,
{ " A " , SDL_SCANCODE_A } ,
{ " B " , SDL_SCANCODE_B } ,
{ " C " , SDL_SCANCODE_C } ,
{ " D " , SDL_SCANCODE_D } ,
{ " E " , SDL_SCANCODE_E } ,
{ " F " , SDL_SCANCODE_F } ,
{ " G " , SDL_SCANCODE_G } ,
{ " H " , SDL_SCANCODE_H } ,
{ " I " , SDL_SCANCODE_I } ,
{ " J " , SDL_SCANCODE_J } ,
{ " K " , SDL_SCANCODE_K } ,
{ " L " , SDL_SCANCODE_L } ,
{ " M " , SDL_SCANCODE_M } ,
{ " N " , SDL_SCANCODE_N } ,
{ " O " , SDL_SCANCODE_O } ,
{ " P " , SDL_SCANCODE_P } ,
{ " Q " , SDL_SCANCODE_Q } ,
{ " R " , SDL_SCANCODE_R } ,
{ " S " , SDL_SCANCODE_S } ,
{ " T " , SDL_SCANCODE_T } ,
{ " U " , SDL_SCANCODE_U } ,
{ " V " , SDL_SCANCODE_V } ,
{ " W " , SDL_SCANCODE_W } ,
{ " X " , SDL_SCANCODE_X } ,
{ " Y " , SDL_SCANCODE_Y } ,
{ " Z " , SDL_SCANCODE_Z } ,
{ " DEL " , SDL_SCANCODE_DELETE } ,
// Keypad
{ " KEYPAD0 " , SDL_SCANCODE_KP_0 } ,
{ " KEYPAD1 " , SDL_SCANCODE_KP_1 } ,
{ " KEYPAD2 " , SDL_SCANCODE_KP_2 } ,
{ " KEYPAD3 " , SDL_SCANCODE_KP_3 } ,
{ " KEYPAD4 " , SDL_SCANCODE_KP_4 } ,
{ " KEYPAD5 " , SDL_SCANCODE_KP_5 } ,
{ " KEYPAD6 " , SDL_SCANCODE_KP_6 } ,
{ " KEYPAD7 " , SDL_SCANCODE_KP_7 } ,
{ " KEYPAD8 " , SDL_SCANCODE_KP_8 } ,
{ " KEYPAD9 " , SDL_SCANCODE_KP_9 } ,
{ " KEYPADPERIOD " , SDL_SCANCODE_KP_PERIOD } ,
{ " KEYPADDIVIDE " , SDL_SCANCODE_KP_DIVIDE } ,
{ " KEYPADMULTIPLY " , SDL_SCANCODE_KP_MULTIPLY } ,
{ " KEYPADMINUS " , SDL_SCANCODE_KP_MINUS } ,
{ " KEYPADPLUS " , SDL_SCANCODE_KP_PLUS } ,
{ " KEYPADENTER " , SDL_SCANCODE_KP_ENTER } ,
{ " KEYPADEQUALS " , SDL_SCANCODE_KP_EQUALS } ,
// Arrows + Home/End Pad
{ " UP " , SDL_SCANCODE_UP } ,
{ " DOWN " , SDL_SCANCODE_DOWN } ,
{ " RIGHT " , SDL_SCANCODE_RIGHT } ,
{ " LEFT " , SDL_SCANCODE_LEFT } ,
{ " INSERT " , SDL_SCANCODE_INSERT } ,
{ " HOME " , SDL_SCANCODE_HOME } ,
{ " END " , SDL_SCANCODE_END } ,
{ " PGUP " , SDL_SCANCODE_PAGEUP } ,
{ " PGDN " , SDL_SCANCODE_PAGEDOWN } ,
// Function Key
{ " F1 " , SDL_SCANCODE_F1 } ,
{ " F2 " , SDL_SCANCODE_F2 } ,
{ " F3 " , SDL_SCANCODE_F3 } ,
{ " F4 " , SDL_SCANCODE_F4 } ,
{ " F5 " , SDL_SCANCODE_F5 } ,
{ " F6 " , SDL_SCANCODE_F6 } ,
{ " F7 " , SDL_SCANCODE_F7 } ,
{ " F8 " , SDL_SCANCODE_F8 } ,
{ " F9 " , SDL_SCANCODE_F9 } ,
{ " F10 " , SDL_SCANCODE_F10 } ,
{ " F11 " , SDL_SCANCODE_F11 } ,
{ " F12 " , SDL_SCANCODE_F12 } ,
{ " F13 " , SDL_SCANCODE_F13 } ,
{ " F14 " , SDL_SCANCODE_F14 } ,
{ " F15 " , SDL_SCANCODE_F15 } ,
// Modifier Keys
// Removed Numlock, Capslock and Scrollock as don't seem to be handled well by SDL
//{ "NUMLOCK", SDLK_NUMLOCK },
//{ "CAPSLOCK", SDL_SCANCODE_CAPSLOCK },
//{ "SCROLLLOCK", SDLK_SCROLLOCK },
{ " RIGHTSHIFT " , SDL_SCANCODE_RSHIFT } ,
{ " LEFTSHIFT " , SDL_SCANCODE_LSHIFT } ,
{ " RIGHTCTRL " , SDL_SCANCODE_RCTRL } ,
{ " LEFTCTRL " , SDL_SCANCODE_LCTRL } ,
{ " RIGHTALT " , SDL_SCANCODE_RALT } ,
{ " LEFTALT " , SDL_SCANCODE_LALT } ,
{ " RIGHTMETA " , SDL_SCANCODE_RGUI } ,
{ " LEFTMETA " , SDL_SCANCODE_LGUI } ,
{ " ALTGR " , SDL_SCANCODE_MODE } ,
// Other
{ " HELP " , SDL_SCANCODE_HELP } ,
{ " SYSREQ " , SDL_SCANCODE_SYSREQ } ,
{ " MENU " , SDL_SCANCODE_MENU } ,
{ " POWER " , SDL_SCANCODE_POWER } ,
{ " UNDO " , SDL_SCANCODE_UNDO }
2011-04-24 01:14:00 +00:00
} ;
2020-10-21 08:19:51 +00:00
CSDLInputSystem : : CSDLInputSystem ( const Util : : Config : : Node & config )
2017-03-27 03:19:15 +00:00
: CInputSystem ( " SDL " ) ,
2020-04-19 08:34:58 +00:00
m_keyState ( nullptr ) ,
2017-03-27 03:19:15 +00:00
m_mouseX ( 0 ) ,
m_mouseY ( 0 ) ,
m_mouseZ ( 0 ) ,
2020-10-21 08:19:51 +00:00
m_mouseButtons ( 0 ) ,
m_config ( config )
2011-04-24 01:14:00 +00:00
{
2020-04-19 08:34:58 +00:00
//
2011-04-24 01:14:00 +00:00
}
CSDLInputSystem : : ~ CSDLInputSystem ( )
{
2020-04-19 08:34:58 +00:00
CloseJoysticks ( ) ;
2011-04-24 01:14:00 +00:00
}
void CSDLInputSystem : : OpenJoysticks ( )
{
2020-04-19 08:34:58 +00:00
// Open all available joysticks
int numJoys = SDL_NumJoysticks ( ) ;
2020-10-21 08:19:51 +00:00
int numHapticAxes = 0 ;
int possibleEffect = 0 ;
2020-04-19 08:34:58 +00:00
for ( int joyNum = 0 ; joyNum < numJoys ; joyNum + + )
{
2020-10-21 08:19:51 +00:00
numHapticAxes = 0 ;
2020-04-19 08:34:58 +00:00
SDL_Joystick * joystick = SDL_JoystickOpen ( joyNum ) ;
if ( joystick = = nullptr )
{
ErrorLog ( " Unable to open joystick device %d with SDL - skipping joystick. \n " , joyNum + 1 ) ;
continue ;
}
// Gather joystick details (name, num POVs & buttons and which axes are available)
JoyDetails joyDetails ;
2020-10-21 08:19:51 +00:00
hapticInfo hapticDatas ;
2020-04-19 08:34:58 +00:00
const char * pName = SDL_JoystickName ( joystick ) ;
strncpy ( joyDetails . name , pName , MAX_NAME_LENGTH ) ;
joyDetails . name [ MAX_NAME_LENGTH ] = ' \0 ' ;
joyDetails . numAxes = SDL_JoystickNumAxes ( joystick ) ;
2020-10-21 08:19:51 +00:00
if ( SDL_JoystickIsHaptic ( joystick ) )
joyDetails . hasFFeedback = true ;
else
joyDetails . hasFFeedback = false ;
if ( joyDetails . hasFFeedback )
{
hapticDatas . SDLhaptic = SDL_HapticOpenFromJoystick ( joystick ) ;
if ( hapticDatas . SDLhaptic = = NULL )
{
ErrorLog ( " Unable to obtain haptic interface for joystick %s. Force feedback will be disabled for this joystick. " , joyDetails . name ) ;
joyDetails . hasFFeedback = false ;
numHapticAxes = 0 ;
}
else
{
numHapticAxes = SDL_HapticNumAxes ( hapticDatas . SDLhaptic ) ;
// depending device, SDL_HapticNumAxes return wrong number of ffb axes (bug on device driver on windows or other ?)
// ie : saitek cyborg evo force joystick returns 3 ffb axes instead of 2 ffb axes, this leads to unable to create effects on this device
// generally, none of commercial ffb products have more than 2 ffb axes
// in this case, we need to force the correct number of ffb axes by adding manually a new sdl2 function
// see https://forums.libsdl.org/viewtopic.php?t=5195
// enabled this code if you have a saitek cyborg evo force or if you find another device that return wrong number of ffb axis
// don't forget to edit sdl2 source code in Supermodel project
//#define HAPTIC_MOD
# if (defined _WIN32 && defined HAPTIC_MOD)
if ( numHapticAxes > 2 )
{
DebugLog ( " Joystick : %s return more than 2 ffb axes, need sdl2 addon SDL_HapticSetAxes() to bypass \n " , SDL_HapticName ( joyNum ) ) ;
if ( strcmp ( joyDetails . name , " Saitek Cyborg Evo Force " ) = = 0 ) // remove if any other particular case
SDL_HapticSetAxes ( hapticDatas . SDLhaptic , 2 ) ; // /!\ function manually added to SDL2 project
}
# endif
// sdl2 bug on linux only ?
// SDL_HapticNumAxes() : on win it reports good number of haptic axe, on linux 18.04 it reports always 2 haptic axes (bad) whatever the device
// file : SDL2-2.0.10\src\haptic\linux\SDL_syshaptic.c
// function : static int SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd)
// haptic->naxes = 2; // Hardcoded for now, not sure if it's possible to find out. <- note from the sdl2 devs
# ifndef _WIN32
if ( ! HasBasicForce ( hapticDatas . SDLhaptic ) ) numHapticAxes = 0 ;
# endif
DebugLog ( " joy num %d haptic num axe %d name : %s \n " , joyNum , numHapticAxes , SDL_HapticName ( joyNum ) ) ;
}
}
2020-04-19 08:34:58 +00:00
for ( int axisNum = 0 ; axisNum < NUM_JOY_AXES ; axisNum + + )
{
joyDetails . hasAxis [ axisNum ] = joyDetails . numAxes > axisNum ;
2020-10-21 08:19:51 +00:00
if ( numHapticAxes > 0 & & joyDetails . hasAxis [ axisNum ] ) // unable to know which axes have ffb
joyDetails . axisHasFF [ axisNum ] = true ;
else
joyDetails . axisHasFF [ axisNum ] = false ;
2020-04-19 08:34:58 +00:00
char * axisName = joyDetails . axisName [ axisNum ] ;
2020-10-21 08:19:51 +00:00
strcpy ( axisName , CInputSystem : : GetDefaultAxisName ( axisNum ) ) ;
2020-04-19 08:34:58 +00:00
}
joyDetails . numPOVs = SDL_JoystickNumHats ( joystick ) ;
joyDetails . numButtons = SDL_JoystickNumButtons ( joystick ) ;
2020-10-21 08:19:51 +00:00
if ( joyDetails . hasFFeedback & & hapticDatas . SDLhaptic ! = NULL & & numHapticAxes > 0 ) // not a pad but wheel or joystick
{
SDL_HapticSetAutocenter ( hapticDatas . SDLhaptic , 0 ) ;
SDL_HapticSetGain ( hapticDatas . SDLhaptic , 100 ) ;
possibleEffect = SDL_HapticQuery ( hapticDatas . SDLhaptic ) ;
// constant effect
if ( possibleEffect & SDL_HAPTIC_CONSTANT )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_CONSTANT ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . constant . direction . dir [ 0 ] = 0 ;
eff . constant . length = 30 ;
eff . constant . delay = 0 ;
eff . constant . level = 0 ;
hapticDatas . effectConstantForceID = SDL_HapticNewEffect ( hapticDatas . SDLhaptic , & eff ) ; ;
if ( hapticDatas . effectConstantForceID < 0 )
ErrorLog ( " Unable to create constant force effect for joystick %s (joy id=%d). Constant force will not be applied. " , joyDetails . name , joyNum + 1 ) ;
}
// vibration effect
if ( possibleEffect & SDL_HAPTIC_SINE )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_SINE ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . constant . length = 500 ;
eff . constant . delay = 0 ;
eff . periodic . period = 50 ;
eff . periodic . magnitude = 0 ;
hapticDatas . effectVibrationID = SDL_HapticNewEffect ( hapticDatas . SDLhaptic , & eff ) ;
if ( hapticDatas . effectVibrationID < 0 )
ErrorLog ( " Unable to create vibration effect for joystick %s (joy id=%d). Vibration will not be applied. " , joyDetails . name , joyNum + 1 ) ;
}
// spring effect
if ( possibleEffect & SDL_HAPTIC_SPRING )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_SPRING ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . condition . delay = 0 ;
eff . condition . length = SDL_HAPTIC_INFINITY ;
eff . condition . left_sat [ 0 ] = 0xFFFF ;
eff . condition . right_sat [ 0 ] = 0xFFFF ;
eff . condition . left_coeff [ 0 ] = 0 ;
eff . condition . right_coeff [ 0 ] = 0 ;
hapticDatas . effectSpringForceID = SDL_HapticNewEffect ( hapticDatas . SDLhaptic , & eff ) ;
if ( hapticDatas . effectSpringForceID < 0 )
ErrorLog ( " Unable to create spring force effect for joystick %s (joy id=%d). Spring force will not be applied. " , joyDetails . name , joyNum + 1 ) ;
}
// friction effect
if ( possibleEffect & SDL_HAPTIC_FRICTION )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_FRICTION ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . condition . delay = 0 ;
eff . condition . length = SDL_HAPTIC_INFINITY ;
eff . condition . left_sat [ 0 ] = 0xFFFF ;
eff . condition . right_sat [ 0 ] = 0xFFFF ;
eff . condition . left_coeff [ 0 ] = 0 ;
eff . condition . right_coeff [ 0 ] = 0 ;
hapticDatas . effectFrictionForceID = SDL_HapticNewEffect ( hapticDatas . SDLhaptic , & eff ) ;
if ( hapticDatas . effectFrictionForceID < 0 )
ErrorLog ( " Unable to create friction force effect for joystick %s (joy id=%d). Friction force will not be applied. " , joyDetails . name , joyNum + 1 ) ;
}
}
if ( joyDetails . hasFFeedback & & hapticDatas . SDLhaptic ! = NULL & & numHapticAxes = = 0 ) // pad with rumble. Note : SDL_HapticRumbleSupported() is not enough to detect rumble pad only because joystick or wheel may have also rumble
{
if ( SDL_HapticRumbleInit ( hapticDatas . SDLhaptic ) < 0 )
{
ErrorLog ( " Unable to create rumble effect for pad %s (pad id=%d). Rumble will not be applied.SDL_HapticRumbleInit failed : %s " , joyDetails . name , joyNum + 1 , SDL_GetError ( ) ) ;
joyDetails . axisHasFF [ AXIS_X ] = false ;
joyDetails . axisHasFF [ AXIS_Y ] = false ;
}
else
{
joyDetails . axisHasFF [ AXIS_X ] = true ; // Force feedback simulated on X axis sticks (fake)
joyDetails . axisHasFF [ AXIS_Y ] = true ; // Force feedback simulated on Y axis sticks (fake)
}
}
2020-04-19 08:34:58 +00:00
m_joysticks . push_back ( joystick ) ;
m_joyDetails . push_back ( joyDetails ) ;
2020-10-21 08:19:51 +00:00
m_SDLHapticDatas . push_back ( hapticDatas ) ;
2020-04-19 08:34:58 +00:00
}
2011-04-24 01:14:00 +00:00
}
void CSDLInputSystem : : CloseJoysticks ( )
{
2020-04-19 08:34:58 +00:00
// Close all previously opened joysticks
for ( size_t i = 0 ; i < m_joysticks . size ( ) ; i + + )
{
2020-10-21 08:19:51 +00:00
JoyDetails joyDetails = m_joyDetails [ i ] ;
if ( joyDetails . hasFFeedback )
{
if ( m_SDLHapticDatas [ i ] . effectConstantForceID > = 0 )
SDL_HapticDestroyEffect ( m_SDLHapticDatas [ i ] . SDLhaptic , m_SDLHapticDatas [ i ] . effectConstantForceID ) ;
if ( m_SDLHapticDatas [ i ] . effectVibrationID > = 0 )
SDL_HapticDestroyEffect ( m_SDLHapticDatas [ i ] . SDLhaptic , m_SDLHapticDatas [ i ] . effectVibrationID ) ;
if ( m_SDLHapticDatas [ i ] . effectSpringForceID > = 0 )
SDL_HapticDestroyEffect ( m_SDLHapticDatas [ i ] . SDLhaptic , m_SDLHapticDatas [ i ] . effectSpringForceID ) ;
if ( m_SDLHapticDatas [ i ] . effectFrictionForceID > = 0 )
SDL_HapticDestroyEffect ( m_SDLHapticDatas [ i ] . SDLhaptic , m_SDLHapticDatas [ i ] . effectFrictionForceID ) ;
SDL_HapticClose ( m_SDLHapticDatas [ i ] . SDLhaptic ) ;
}
2020-04-19 08:34:58 +00:00
SDL_Joystick * joystick = m_joysticks [ i ] ;
SDL_JoystickClose ( joystick ) ;
}
m_joysticks . clear ( ) ;
m_joyDetails . clear ( ) ;
2020-10-21 08:19:51 +00:00
m_SDLHapticDatas . clear ( ) ;
2011-04-24 01:14:00 +00:00
}
bool CSDLInputSystem : : InitializeSystem ( )
{
2020-04-19 08:34:58 +00:00
// Make sure joystick subsystem is initialized and joystick events are enabled
2020-10-21 08:19:51 +00:00
if ( SDL_InitSubSystem ( SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC ) ! = 0 )
2020-04-19 08:34:58 +00:00
{
ErrorLog ( " Unable to initialize SDL joystick subsystem (%s). \n " , SDL_GetError ( ) ) ;
return false ;
}
SDL_JoystickEventState ( SDL_ENABLE ) ;
// Open attached joysticks
OpenJoysticks ( ) ;
return true ;
2011-04-24 01:14:00 +00:00
}
int CSDLInputSystem : : GetKeyIndex ( const char * keyName )
{
2020-04-19 08:34:58 +00:00
for ( int i = 0 ; i < NUM_SDL_KEYS ; i + + )
{
if ( stricmp ( keyName , s_keyMap [ i ] . keyName ) = = 0 )
return i ;
}
return - 1 ;
2011-04-24 01:14:00 +00:00
}
const char * CSDLInputSystem : : GetKeyName ( int keyIndex )
{
2020-04-19 08:34:58 +00:00
if ( keyIndex < 0 | | keyIndex > = NUM_SDL_KEYS )
return nullptr ;
return s_keyMap [ keyIndex ] . keyName ;
2011-04-24 01:14:00 +00:00
}
bool CSDLInputSystem : : IsKeyPressed ( int kbdNum , int keyIndex )
{
2020-04-19 08:34:58 +00:00
// Get SDL key for given index and check if currently pressed
SDL_Keycode sdlKey = s_keyMap [ keyIndex ] . sdlKey ;
return ! ! m_keyState [ sdlKey ] ;
2011-04-24 01:14:00 +00:00
}
int CSDLInputSystem : : GetMouseAxisValue ( int mseNum , int axisNum )
{
2020-04-19 08:34:58 +00:00
// Return value for given mouse axis
switch ( axisNum )
{
case AXIS_X : return m_mouseX ;
case AXIS_Y : return m_mouseY ;
case AXIS_Z : return m_mouseZ ;
default : return 0 ;
}
2011-04-24 01:14:00 +00:00
}
int CSDLInputSystem : : GetMouseWheelDir ( int mseNum )
{
2020-04-19 08:34:58 +00:00
// Return wheel value
return m_mouseWheelDir ;
2011-04-24 01:14:00 +00:00
}
bool CSDLInputSystem : : IsMouseButPressed ( int mseNum , int butNum )
{
2020-04-19 08:34:58 +00:00
// Return value for given mouse button
switch ( butNum )
{
case 0 : return ! ! ( m_mouseButtons & SDL_BUTTON_LMASK ) ;
case 1 : return ! ! ( m_mouseButtons & SDL_BUTTON_MMASK ) ;
case 2 : return ! ! ( m_mouseButtons & SDL_BUTTON_RMASK ) ;
case 3 : return ! ! ( m_mouseButtons & SDL_BUTTON_X1MASK ) ;
case 4 : return ! ! ( m_mouseButtons & SDL_BUTTON_X2MASK ) ;
default : return false ;
}
2011-04-24 01:14:00 +00:00
}
int CSDLInputSystem : : GetJoyAxisValue ( int joyNum , int axisNum )
{
2020-04-19 08:34:58 +00:00
// Get raw joystick axis value for given joystick from SDL (values range from -32768 to 32767)
SDL_Joystick * joystick = m_joysticks [ joyNum ] ;
return SDL_JoystickGetAxis ( joystick , axisNum ) ;
2011-04-24 01:14:00 +00:00
}
bool CSDLInputSystem : : IsJoyPOVInDir ( int joyNum , int povNum , int povDir )
{
2020-04-19 08:34:58 +00:00
// Get current joystick POV-hat value for given joystick and POV number from SDL and check if pointing in required direction
SDL_Joystick * joystick = m_joysticks [ joyNum ] ;
int hatVal = SDL_JoystickGetHat ( joystick , povNum ) ;
switch ( povDir )
{
case POV_UP : return ! ! ( hatVal & SDL_HAT_UP ) ;
case POV_DOWN : return ! ! ( hatVal & SDL_HAT_DOWN ) ;
case POV_LEFT : return ! ! ( hatVal & SDL_HAT_LEFT ) ;
case POV_RIGHT : return ! ! ( hatVal & SDL_HAT_RIGHT ) ;
default : return false ;
}
return false ;
2011-04-24 01:14:00 +00:00
}
bool CSDLInputSystem : : IsJoyButPressed ( int joyNum , int butNum )
{
2020-04-19 08:34:58 +00:00
// Get current joystick button state for given joystick and button number from SDL
SDL_Joystick * joystick = m_joysticks [ joyNum ] ;
return ! ! SDL_JoystickGetButton ( joystick , butNum ) ;
2011-04-24 01:14:00 +00:00
}
2011-06-22 13:06:52 +00:00
bool CSDLInputSystem : : ProcessForceFeedbackCmd ( int joyNum , int axisNum , ForceFeedbackCmd ffCmd )
2011-06-05 20:53:39 +00:00
{
2020-10-21 08:19:51 +00:00
switch ( ffCmd . id )
{
case FFStop :
StopAllEffect ( joyNum ) ;
break ;
case FFConstantForce :
sdlConstForceMax = m_config [ " SDLConstForceMax " ] . ValueAs < unsigned > ( ) ;
if ( sdlConstForceMax = = 0 )
return false ;
// note sr2 centering val=0.047244 and val=0.062992 alternatively (const value)
// max val between -1 to 1 (left right)
if ( ffCmd . force = = 0.0f )
StopConstanteforce ( joyNum ) ;
else if ( ffCmd . force > 0.0f )
2020-12-01 07:35:52 +00:00
ConstantForceEffect ( ffCmd . force * ( float ) ( sdlConstForceMax / 100.0f ) , - 1 , SDL_HAPTIC_INFINITY , joyNum ) ;
2020-10-21 08:19:51 +00:00
else if ( ffCmd . force < 0.0f )
2020-12-01 07:35:52 +00:00
ConstantForceEffect ( - ffCmd . force * ( float ) ( sdlConstForceMax / 100.0f ) , 1 , SDL_HAPTIC_INFINITY , joyNum ) ;
2020-10-21 08:19:51 +00:00
break ;
case FFSelfCenter :
sdlSelfCenterMax = m_config [ " SDLSelfCenterMax " ] . ValueAs < unsigned > ( ) ;
if ( sdlSelfCenterMax = = 0 )
return false ;
SpringForceEffect ( ffCmd . force * ( float ) ( sdlSelfCenterMax / 100.0f ) , joyNum ) ;
break ;
case FFFriction :
sdlFrictionMax = m_config [ " SDLFrictionMax " ] . ValueAs < unsigned > ( ) ;
if ( sdlFrictionMax = = 0 )
return false ;
FrictionForceEffect ( ffCmd . force * ( float ) ( sdlFrictionMax / 100.0f ) , joyNum ) ;
break ;
case FFVibrate :
sdlVibrateMax = m_config [ " SDLVibrateMax " ] . ValueAs < unsigned > ( ) ;
if ( sdlVibrateMax = = 0 )
return false ;
VibrationEffect ( ffCmd . force * ( float ) ( sdlVibrateMax / 100.0f ) , joyNum ) ;
break ;
}
return true ;
2011-06-05 20:53:39 +00:00
}
int CSDLInputSystem : : GetNumKeyboards ( )
2011-04-24 01:14:00 +00:00
{
2020-04-19 08:34:58 +00:00
// Return ANY_KEYBOARD as SDL 1.2 cannot handle multiple keyboards
return ANY_KEYBOARD ;
2011-06-05 20:53:39 +00:00
}
2020-04-19 08:34:58 +00:00
2011-06-05 20:53:39 +00:00
int CSDLInputSystem : : GetNumMice ( )
{
2020-04-19 08:34:58 +00:00
// Return ANY_MOUSE as SDL 1.2 cannot handle multiple mice
return ANY_MOUSE ;
2011-06-05 20:53:39 +00:00
}
2020-04-19 08:34:58 +00:00
2011-06-05 20:53:39 +00:00
int CSDLInputSystem : : GetNumJoysticks ( )
{
2020-04-19 08:34:58 +00:00
// Return number of joysticks found
return ( int ) m_joysticks . size ( ) ;
2011-06-05 20:53:39 +00:00
}
const KeyDetails * CSDLInputSystem : : GetKeyDetails ( int kbdNum )
{
2020-04-19 08:34:58 +00:00
// Return nullptr as SDL 1.2 cannot handle multiple keyboards
return nullptr ;
2011-06-05 20:53:39 +00:00
}
const MouseDetails * CSDLInputSystem : : GetMouseDetails ( int mseNum )
{
2020-04-19 08:34:58 +00:00
// Return nullptr as SDL 1.2 cannot handle multiple mice
return nullptr ;
2011-06-05 20:53:39 +00:00
}
const JoyDetails * CSDLInputSystem : : GetJoyDetails ( int joyNum )
{
2020-04-19 08:34:58 +00:00
return & m_joyDetails [ joyNum ] ;
2011-04-24 01:14:00 +00:00
}
bool CSDLInputSystem : : Poll ( )
{
2020-04-19 08:34:58 +00:00
// Reset mouse wheel direction
m_mouseWheelDir = 0 ;
// Poll for event from SDL
SDL_Event e ;
while ( SDL_PollEvent ( & e ) )
{
switch ( e . type )
2011-04-24 01:14:00 +00:00
{
2020-04-19 08:34:58 +00:00
default :
break ;
case SDL_QUIT :
2020-07-27 10:28:48 +00:00
return false ;
2020-04-19 08:34:58 +00:00
case SDL_MOUSEWHEEL :
if ( e . button . y > 0 )
2011-04-24 01:14:00 +00:00
{
m_mouseZ + = 5 ;
m_mouseWheelDir = 1 ;
}
2020-04-19 08:34:58 +00:00
else if ( e . button . y < 0 )
2011-04-24 01:14:00 +00:00
{
m_mouseZ - = 5 ;
m_mouseWheelDir = - 1 ;
}
2020-04-19 08:34:58 +00:00
break ;
2011-04-24 01:14:00 +00:00
}
2020-04-19 08:34:58 +00:00
}
2011-04-24 01:14:00 +00:00
2020-04-19 08:34:58 +00:00
// Get key state from SDL
m_keyState = SDL_GetKeyboardState ( nullptr ) ;
2011-04-24 01:14:00 +00:00
2020-04-19 08:34:58 +00:00
// Get mouse state from SDL (except mouse wheel which was handled earlier)
m_mouseButtons = SDL_GetMouseState ( & m_mouseX , & m_mouseY ) ;
2011-04-24 01:14:00 +00:00
2020-04-19 08:34:58 +00:00
// Update joystick state (not required as called implicitly by SDL_PollEvent above)
//SDL_JoystickUpdate();
return true ;
2011-06-05 20:53:39 +00:00
}
void CSDLInputSystem : : SetMouseVisibility ( bool visible )
{
2020-04-19 08:34:58 +00:00
SDL_ShowCursor ( visible ? SDL_ENABLE : SDL_DISABLE ) ;
}
2020-10-21 08:19:51 +00:00
void CSDLInputSystem : : StopAllEffect ( int joyNum )
{
StopConstanteforce ( joyNum ) ;
StopVibrationforce ( joyNum ) ;
StopSpringforce ( joyNum ) ;
StopFrictionforce ( joyNum ) ;
}
void CSDLInputSystem : : StopConstanteforce ( int joyNum )
{
// stop constante effect or rumble constant effect
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_CONSTANT ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . constant . direction . dir [ 0 ] = 0 ;
eff . constant . length = 30 ;
eff . constant . delay = 0 ;
eff . constant . level = 0 ;
if ( SDL_HapticEffectSupported ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , & eff ) )
{
SDL_HapticUpdateEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectConstantForceID , & eff ) ;
}
else
{
SDL_HapticRumbleStop ( m_SDLHapticDatas [ joyNum ] . SDLhaptic ) ;
}
}
void CSDLInputSystem : : StopVibrationforce ( int joyNum )
{
// stop vibration-rumble effect
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_SINE ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . constant . length = 500 ;
eff . constant . delay = 0 ;
eff . periodic . period = 50 ;
eff . periodic . magnitude = 0 ;
if ( SDL_HapticEffectSupported ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , & eff ) )
{
SDL_HapticUpdateEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectVibrationID , & eff ) ;
}
else
{
SDL_HapticRumbleStop ( m_SDLHapticDatas [ joyNum ] . SDLhaptic ) ;
}
}
void CSDLInputSystem : : StopSpringforce ( int joyNum )
{
// stop spring effect
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_SPRING ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . condition . delay = 0 ;
eff . condition . length = SDL_HAPTIC_INFINITY ;
eff . condition . left_sat [ 0 ] = 0xFFFF ;
eff . condition . right_sat [ 0 ] = 0xFFFF ;
eff . condition . left_coeff [ 0 ] = 0 ;
eff . condition . right_coeff [ 0 ] = 0 ;
if ( SDL_HapticEffectSupported ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , & eff ) )
{
SDL_HapticUpdateEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectSpringForceID , & eff ) ;
}
}
void CSDLInputSystem : : StopFrictionforce ( int joyNum )
{
// stop friction effect
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_FRICTION ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . condition . delay = 0 ;
eff . condition . length = SDL_HAPTIC_INFINITY ;
eff . condition . left_sat [ 0 ] = 0xFFFF ;
eff . condition . right_sat [ 0 ] = 0xFFFF ;
eff . condition . left_coeff [ 0 ] = 0 ;
eff . condition . right_coeff [ 0 ] = 0 ;
if ( SDL_HapticEffectSupported ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , & eff ) )
{
SDL_HapticUpdateEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectFrictionForceID , & eff ) ;
}
}
void CSDLInputSystem : : VibrationEffect ( float strength , int joyNum )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_SINE ;
eff . constant . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . periodic . delay = 0 ;
eff . periodic . length = SDL_HAPTIC_INFINITY ;
eff . periodic . period = 50 ;
eff . periodic . magnitude = ( int ) ( strength * INT16_MAX ) ;
if ( SDL_HapticEffectSupported ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , & eff ) )
{
SDL_HapticUpdateEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectVibrationID , & eff ) ;
SDL_HapticRunEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectVibrationID , 1 ) ;
}
else
{
if ( strength ! = 0.0f )
SDL_HapticRumblePlay ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , strength , 0 ) ;
else
SDL_HapticRumbleStop ( m_SDLHapticDatas [ joyNum ] . SDLhaptic ) ;
}
}
void CSDLInputSystem : : ConstantForceEffect ( float force , int dir , int length , int joyNum )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_CONSTANT ;
eff . constant . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . constant . direction . dir [ 0 ] = 0 ; // in cartesian mode dir on x set 0 on y set 1
eff . constant . length = length ;
eff . constant . level = ( int ) ( dir * ( force * INT16_MAX ) ) ;
if ( SDL_HapticEffectSupported ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , & eff ) )
{
SDL_HapticUpdateEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectConstantForceID , & eff ) ;
SDL_HapticRunEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectConstantForceID , 1 ) ;
}
else
{
2021-01-30 09:54:03 +00:00
float threshold = ( float ) m_config [ " SDLConstForceThreshold " ] . ValueAs < unsigned > ( ) / 100.0f ;
if ( force ! = 0.0f & & force > threshold )
2020-10-21 08:19:51 +00:00
SDL_HapticRumblePlay ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , force , 200 ) ;
else
SDL_HapticRumbleStop ( m_SDLHapticDatas [ joyNum ] . SDLhaptic ) ;
}
}
void CSDLInputSystem : : SpringForceEffect ( float force , int joyNum )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_SPRING ;
eff . constant . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . condition . delay = 0 ;
eff . condition . length = SDL_HAPTIC_INFINITY ;
eff . condition . left_sat [ 0 ] = 0xffff ;
eff . condition . right_sat [ 0 ] = 0xffff ;
eff . condition . left_coeff [ 0 ] = ( int ) ( force * INT16_MAX ) ;
eff . condition . right_coeff [ 0 ] = ( int ) ( force * INT16_MAX ) ;
if ( SDL_HapticEffectSupported ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , & eff ) )
{
SDL_HapticUpdateEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectSpringForceID , & eff ) ;
SDL_HapticRunEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectSpringForceID , 1 ) ;
}
}
void CSDLInputSystem : : FrictionForceEffect ( float force , int joyNum )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_FRICTION ;
eff . constant . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . condition . delay = 0 ;
eff . condition . length = SDL_HAPTIC_INFINITY ;
eff . condition . left_sat [ 0 ] = 0xffff ;
eff . condition . right_sat [ 0 ] = 0xffff ;
eff . condition . left_coeff [ 0 ] = ( int ) ( force * INT16_MAX ) ;
eff . condition . right_coeff [ 0 ] = ( int ) ( force * INT16_MAX ) ;
if ( SDL_HapticEffectSupported ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , & eff ) )
{
SDL_HapticUpdateEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectFrictionForceID , & eff ) ;
SDL_HapticRunEffect ( m_SDLHapticDatas [ joyNum ] . SDLhaptic , m_SDLHapticDatas [ joyNum ] . effectFrictionForceID , 1 ) ;
}
}
// due to the sdl2 SDL_HapticNumAxes() bug in linux (always return 2 in linux)
// test if haptic controller has the most basic constant force effect
// if it has -> ffb wheel or ffb joystick
// if it hasn't -> pad
bool CSDLInputSystem : : HasBasicForce ( SDL_Haptic * hap )
{
SDL_memset ( & eff , 0 , sizeof ( SDL_HapticEffect ) ) ;
eff . type = SDL_HAPTIC_CONSTANT ;
eff . periodic . direction . type = SDL_HAPTIC_CARTESIAN ;
eff . constant . direction . dir [ 0 ] = 0 ;
eff . constant . length = 30 ;
eff . constant . delay = 0 ;
eff . constant . level = 0 ;
if ( SDL_HapticEffectSupported ( hap , & eff ) )
return true ;
else
return false ;
}