mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-23 14:15:40 +00:00
e8782b98fa
- Added ability to configure axis min, centre and max values in INI file. This allows some types of steering wheel pedals that use an inverted value range to work properly with the emulator. - Modified CINIFile to read and write signed numbers (needed for above change). - Added check at configuration start for "bad" input sources such as axes that are wrongly calibrated or buttons that are always triggering a value. Otherwise they cause the configuration loop to wait indefinitely for the axis or button to be released. - Removed superfluous check for XInput devices when XInput is not enabled in CDirectInputSystem. - Improved force beedback code in CDirectInputSystem and also added the extra feedback effects needed so far for drive board emulation.
404 lines
11 KiB
C++
404 lines
11 KiB
C++
#include "SDLInputSystem.h"
|
|
#include "Supermodel.h"
|
|
|
|
#include <vector>
|
|
using namespace std;
|
|
|
|
SDLKeyMapStruct CSDLInputSystem::s_keyMap[] =
|
|
{
|
|
// General keys
|
|
{ "BACKSPACE", SDLK_BACKSPACE },
|
|
{ "TAB", SDLK_TAB },
|
|
{ "CLEAR", SDLK_CLEAR },
|
|
{ "RETURN", SDLK_RETURN },
|
|
{ "PAUSE", SDLK_PAUSE },
|
|
{ "ESCAPE", SDLK_ESCAPE },
|
|
{ "SPACE", SDLK_SPACE },
|
|
{ "EXCLAIM", SDLK_EXCLAIM },
|
|
{ "DBLQUOTE", SDLK_QUOTEDBL },
|
|
{ "HASH", SDLK_HASH },
|
|
{ "DOLLAR", SDLK_DOLLAR },
|
|
{ "AMPERSAND", SDLK_AMPERSAND },
|
|
{ "QUOTE", SDLK_QUOTE },
|
|
{ "LEFTPAREN", SDLK_LEFTPAREN },
|
|
{ "RIGHTPAREN", SDLK_RIGHTPAREN },
|
|
{ "ASTERISK", SDLK_ASTERISK },
|
|
{ "PLUS", SDLK_PLUS },
|
|
{ "COMMA", SDLK_COMMA },
|
|
{ "MINUS", SDLK_MINUS },
|
|
{ "PERIOD", SDLK_PERIOD },
|
|
{ "SLASH", SDLK_SLASH },
|
|
{ "0", SDLK_0 },
|
|
{ "1", SDLK_1 },
|
|
{ "2", SDLK_2 },
|
|
{ "3", SDLK_3 },
|
|
{ "4", SDLK_4 },
|
|
{ "5", SDLK_5 },
|
|
{ "6", SDLK_6 },
|
|
{ "7", SDLK_7 },
|
|
{ "8", SDLK_8 },
|
|
{ "9", SDLK_9 },
|
|
{ "COLON", SDLK_COLON },
|
|
{ "SEMICOLON", SDLK_SEMICOLON },
|
|
{ "LESS", SDLK_LESS },
|
|
{ "EQUALS", SDLK_EQUALS },
|
|
{ "GREATER", SDLK_GREATER },
|
|
{ "QUESTION", SDLK_QUESTION },
|
|
{ "AT", SDLK_AT },
|
|
{ "LEFTBRACKET", SDLK_LEFTBRACKET },
|
|
{ "BACKSLASH", SDLK_BACKSLASH },
|
|
{ "RIGHTBRACKET", SDLK_RIGHTBRACKET },
|
|
{ "CARET", SDLK_CARET },
|
|
{ "UNDERSCORE", SDLK_UNDERSCORE },
|
|
{ "BACKQUOTE", SDLK_BACKQUOTE },
|
|
{ "A", SDLK_a },
|
|
{ "B", SDLK_b },
|
|
{ "C", SDLK_c },
|
|
{ "D", SDLK_d },
|
|
{ "E", SDLK_e },
|
|
{ "F", SDLK_f },
|
|
{ "G", SDLK_g },
|
|
{ "H", SDLK_h },
|
|
{ "I", SDLK_i },
|
|
{ "J", SDLK_j },
|
|
{ "K", SDLK_k },
|
|
{ "L", SDLK_l },
|
|
{ "M", SDLK_m },
|
|
{ "N", SDLK_n },
|
|
{ "O", SDLK_o },
|
|
{ "P", SDLK_p },
|
|
{ "Q", SDLK_q },
|
|
{ "R", SDLK_r },
|
|
{ "S", SDLK_s },
|
|
{ "T", SDLK_t },
|
|
{ "U", SDLK_u },
|
|
{ "V", SDLK_v },
|
|
{ "W", SDLK_w },
|
|
{ "X", SDLK_x },
|
|
{ "Y", SDLK_y },
|
|
{ "Z", SDLK_z },
|
|
{ "DEL", SDLK_DELETE },
|
|
|
|
// Keypad
|
|
{ "KEYPAD0", SDLK_KP0 },
|
|
{ "KEYPAD1", SDLK_KP1 },
|
|
{ "KEYPAD2", SDLK_KP2 },
|
|
{ "KEYPAD3", SDLK_KP3 },
|
|
{ "KEYPAD4", SDLK_KP4 },
|
|
{ "KEYPAD5", SDLK_KP5 },
|
|
{ "KEYPAD6", SDLK_KP6 },
|
|
{ "KEYPAD7", SDLK_KP7 },
|
|
{ "KEYPAD8", SDLK_KP8 },
|
|
{ "KEYPAD9", SDLK_KP9 },
|
|
{ "KEYPADPERIOD", SDLK_KP_PERIOD },
|
|
{ "KEYPADDIVIDE", SDLK_KP_DIVIDE },
|
|
{ "KEYPADMULTIPLY", SDLK_KP_MULTIPLY },
|
|
{ "KEYPADMINUS", SDLK_KP_MINUS },
|
|
{ "KEYPADPLUS", SDLK_KP_PLUS },
|
|
{ "KEYPADENTER", SDLK_KP_ENTER },
|
|
{ "KEYPADEQUALS", SDLK_KP_EQUALS },
|
|
|
|
// Arrows + Home/End Pad
|
|
{ "UP", SDLK_UP },
|
|
{ "DOWN", SDLK_DOWN },
|
|
{ "RIGHT", SDLK_RIGHT },
|
|
{ "LEFT", SDLK_LEFT },
|
|
{ "INSERT", SDLK_INSERT },
|
|
{ "HOME", SDLK_HOME },
|
|
{ "END", SDLK_END },
|
|
{ "PGUP", SDLK_PAGEUP },
|
|
{ "PGDN", SDLK_PAGEDOWN },
|
|
|
|
// Function Key
|
|
{ "F1", SDLK_F1 },
|
|
{ "F2", SDLK_F2 },
|
|
{ "F3", SDLK_F3 },
|
|
{ "F4", SDLK_F4 },
|
|
{ "F5", SDLK_F5 },
|
|
{ "F6", SDLK_F6 },
|
|
{ "F7", SDLK_F7 },
|
|
{ "F8", SDLK_F8 },
|
|
{ "F9", SDLK_F9 },
|
|
{ "F10", SDLK_F10 },
|
|
{ "F11", SDLK_F11 },
|
|
{ "F12", SDLK_F12 },
|
|
{ "F13", SDLK_F13 },
|
|
{ "F14", SDLK_F14 },
|
|
{ "F15", SDLK_F15 },
|
|
|
|
// Modifier Keys
|
|
// Removed Numlock, Capslock and Scrollock as don't seem to be handled well by SDL
|
|
//{ "NUMLOCK", SDLK_NUMLOCK },
|
|
//{ "CAPSLOCK", SDLK_CAPSLOCK },
|
|
//{ "SCROLLLOCK", SDLK_SCROLLOCK },
|
|
{ "RIGHTSHIFT", SDLK_RSHIFT },
|
|
{ "LEFTSHIFT", SDLK_LSHIFT },
|
|
{ "RIGHTCTRL", SDLK_RCTRL },
|
|
{ "LEFTCTRL", SDLK_LCTRL },
|
|
{ "RIGHTALT", SDLK_RALT },
|
|
{ "LEFTALT", SDLK_LALT },
|
|
{ "RIGHTMETA", SDLK_RMETA },
|
|
{ "LEFTMETA", SDLK_LMETA },
|
|
{ "RIGHTWINDOWS", SDLK_RSUPER },
|
|
{ "LEFTWINDOWS", SDLK_LSUPER },
|
|
{ "ALTGR", SDLK_MODE },
|
|
{ "COMPOSE", SDLK_COMPOSE },
|
|
|
|
// Other
|
|
{ "HELP", SDLK_HELP },
|
|
{ "PRINT", SDLK_PRINT },
|
|
{ "SYSREQ", SDLK_SYSREQ },
|
|
{ "BREAK", SDLK_BREAK },
|
|
{ "MENU", SDLK_MENU },
|
|
{ "POWER", SDLK_POWER },
|
|
{ "EURO", SDLK_EURO },
|
|
{ "UNDO", SDLK_UNDO }
|
|
};
|
|
|
|
CSDLInputSystem::CSDLInputSystem() : CInputSystem("SDL"), m_keyState(NULL), m_mouseX(0), m_mouseY(0), m_mouseZ(0), m_mouseButtons(0)
|
|
{
|
|
//
|
|
}
|
|
|
|
CSDLInputSystem::~CSDLInputSystem()
|
|
{
|
|
CloseJoysticks();
|
|
}
|
|
|
|
void CSDLInputSystem::OpenJoysticks()
|
|
{
|
|
// Open all available joysticks
|
|
int numJoys = SDL_NumJoysticks();
|
|
for (int joyNum = 0; joyNum < numJoys; joyNum++)
|
|
{
|
|
SDL_Joystick *joystick = SDL_JoystickOpen(joyNum);
|
|
if (joystick == NULL)
|
|
{
|
|
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;
|
|
const char *pName = SDL_JoystickName(joyNum);
|
|
strncpy(joyDetails.name, pName, MAX_NAME_LENGTH);
|
|
joyDetails.name[MAX_NAME_LENGTH] = '\0';
|
|
joyDetails.numAxes = SDL_JoystickNumAxes(joystick);
|
|
for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++)
|
|
{
|
|
joyDetails.hasAxis[axisNum] = joyDetails.numAxes > axisNum;
|
|
joyDetails.axisHasFF[axisNum] = false; // SDL 1.2 does not support force feedback
|
|
}
|
|
joyDetails.numPOVs = SDL_JoystickNumHats(joystick);
|
|
joyDetails.numButtons = SDL_JoystickNumButtons(joystick);
|
|
joyDetails.hasFFeedback = false; // SDL 1.2 does not support force feedback
|
|
|
|
m_joysticks.push_back(joystick);
|
|
m_joyDetails.push_back(joyDetails);
|
|
}
|
|
}
|
|
|
|
void CSDLInputSystem::CloseJoysticks()
|
|
{
|
|
// Close all previously opened joysticks
|
|
for (size_t i = 0; i < m_joysticks.size(); i++)
|
|
{
|
|
SDL_Joystick *joystick = m_joysticks[i];
|
|
SDL_JoystickClose(joystick);
|
|
}
|
|
|
|
m_joysticks.clear();
|
|
m_joyDetails.clear();
|
|
}
|
|
|
|
bool CSDLInputSystem::InitializeSystem()
|
|
{
|
|
// Make sure joystick subsystem is initialized and joystick events are enabled
|
|
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0)
|
|
{
|
|
ErrorLog("Unable to initialize SDL joystick subsystem (%s).\n", SDL_GetError());
|
|
|
|
return false;
|
|
}
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
// Open attached joysticks
|
|
OpenJoysticks();
|
|
return true;
|
|
}
|
|
|
|
int CSDLInputSystem::GetKeyIndex(const char *keyName)
|
|
{
|
|
for (int i = 0; i < NUM_SDL_KEYS; i++)
|
|
{
|
|
if (stricmp(keyName, s_keyMap[i].keyName) == 0)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
const char *CSDLInputSystem::GetKeyName(int keyIndex)
|
|
{
|
|
if (keyIndex < 0 || keyIndex >= NUM_SDL_KEYS)
|
|
return NULL;
|
|
return s_keyMap[keyIndex].keyName;
|
|
}
|
|
|
|
bool CSDLInputSystem::IsKeyPressed(int kbdNum, int keyIndex)
|
|
{
|
|
// Get SDL key for given index and check if currently pressed
|
|
SDLKey sdlKey = s_keyMap[keyIndex].sdlKey;
|
|
return !!m_keyState[sdlKey];
|
|
}
|
|
|
|
int CSDLInputSystem::GetMouseAxisValue(int mseNum, int axisNum)
|
|
{
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
int CSDLInputSystem::GetMouseWheelDir(int mseNum)
|
|
{
|
|
// Return wheel value
|
|
return m_mouseWheelDir;
|
|
}
|
|
|
|
bool CSDLInputSystem::IsMouseButPressed(int mseNum, int butNum)
|
|
{
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
int CSDLInputSystem::GetJoyAxisValue(int joyNum, int axisNum)
|
|
{
|
|
// 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);
|
|
}
|
|
|
|
bool CSDLInputSystem::IsJoyPOVInDir(int joyNum, int povNum, int povDir)
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
bool CSDLInputSystem::IsJoyButPressed(int joyNum, int butNum)
|
|
{
|
|
// Get current joystick button state for given joystick and button number from SDL
|
|
SDL_Joystick *joystick = m_joysticks[joyNum];
|
|
return !!SDL_JoystickGetButton(joystick, butNum);
|
|
}
|
|
|
|
bool CSDLInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceFeedbackCmd ffCmd)
|
|
{
|
|
// SDL 1.2 does not support force feedback
|
|
return false;
|
|
}
|
|
|
|
void CSDLInputSystem::Wait(int ms)
|
|
{
|
|
SDL_Delay(ms);
|
|
}
|
|
|
|
int CSDLInputSystem::GetNumKeyboards()
|
|
{
|
|
// Return ANY_KEYBOARD as SDL 1.2 cannot handle multiple keyboards
|
|
return ANY_KEYBOARD;
|
|
}
|
|
|
|
int CSDLInputSystem::GetNumMice()
|
|
{
|
|
// Return ANY_MOUSE as SDL 1.2 cannot handle multiple mice
|
|
return ANY_MOUSE;
|
|
}
|
|
|
|
int CSDLInputSystem::GetNumJoysticks()
|
|
{
|
|
// Return number of joysticks found
|
|
return m_joysticks.size();
|
|
}
|
|
|
|
const KeyDetails *CSDLInputSystem::GetKeyDetails(int kbdNum)
|
|
{
|
|
// Return NULL as SDL 1.2 cannot handle multiple keyboards
|
|
return NULL;
|
|
}
|
|
|
|
const MouseDetails *CSDLInputSystem::GetMouseDetails(int mseNum)
|
|
{
|
|
// Return NULL as SDL 1.2 cannot handle multiple mice
|
|
return NULL;
|
|
}
|
|
|
|
const JoyDetails *CSDLInputSystem::GetJoyDetails(int joyNum)
|
|
{
|
|
return &m_joyDetails[joyNum];
|
|
}
|
|
|
|
bool CSDLInputSystem::Poll()
|
|
{
|
|
// Reset mouse wheel direction
|
|
m_mouseWheelDir = 0;
|
|
|
|
// Poll for event from SDL
|
|
SDL_Event e;
|
|
while (SDL_PollEvent(&e))
|
|
{
|
|
if (e.type == SDL_QUIT)
|
|
return false;
|
|
else if (e.type == SDL_MOUSEBUTTONDOWN)
|
|
{
|
|
// Mouse wheel movements are not returned by SDL_GetMouseState below, so they are handled here instead
|
|
// The mouse absolute Z-axis value and mouse wheel direction value are updated appropriately
|
|
if (e.button.button == SDL_BUTTON_WHEELUP)
|
|
{
|
|
m_mouseZ += 5;
|
|
m_mouseWheelDir = 1;
|
|
}
|
|
else if (e.button.button == SDL_BUTTON_WHEELDOWN)
|
|
{
|
|
m_mouseZ -= 5;
|
|
m_mouseWheelDir = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get key state from SDL
|
|
m_keyState = SDL_GetKeyState(NULL);
|
|
|
|
// Get mouse state from SDL (except mouse wheel which was handled earlier)
|
|
m_mouseButtons = SDL_GetMouseState(&m_mouseX, &m_mouseY);
|
|
|
|
// Update joystick state (not required as called implicitly by SDL_PollEvent above)
|
|
//SDL_JoystickUpdate();
|
|
return true;
|
|
}
|
|
|
|
void CSDLInputSystem::SetMouseVisibility(bool visible)
|
|
{
|
|
SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
|
|
} |