Supermodel/Src/OSD/SDL/SDLInputSystem.cpp
Nik Henson 8835d6fe36 Some updates to Supermodel made at beginning of the year but only now got around to checking in (better late than never...):
- hooked up the remaining controls in Supermodel (except for Magical Truck Adventure which does not work at all yet).  The new controls are:
  * InputAnalogJoyTrigger2 and InputAnalogJoyEvent2 for the additional second trigger and event buttons that were missing from Star Wars Trilogy,
  * InputRearBrake and InputMusicSelect for the rear brake and music selection buttons that were missing from Harley Davidson,
  * InputAnalogGunXXX, InputAnalogTriggerXXX, InputAnalogGunXXX2 and InputAnalogTriggerXXX2 for the analogue guns of Ocean Hunter and LA Machineguns (NOTE: these controls must be calibrated in the games' service menus otherwise they will not work properly.  Also, the alignment of the gun cursor does not line up very well with the mouse position at the moment, but at least the games are a bit more playable now, although still with numerous graphical glitches...)
  * InputSkiXXX for the controls of Ski Champ, making the game playable now.
- hooked up existing InputViewChange control to Harley Davidson's view change button
- improved the handling of InputGearShiftUp/Down inputs so that they work better with the driving games.  With Dirt Devils, ECA, Harley and LeMans this means they map directly to the game's own shift up/down controls, while with the 4-speed games such as Daytona 2, Scud Racer and Sega Rally 2, they simulate the user shifting up and down through the gears
- added defaults for the new controls to Supermodel.ini
- other small code tweaks:
  * fix small bug with handling of pos/neg inputs mapping to a control with inverted range (0XFF to 0x00) - this was needed to get Ski Champ's X-axis to work properly
  * removed Wait method from InputSystem and added to CThread as CThread::Sleep instead
  * added FrameTimings struct to hold all frame timings in a single place
No networking code yet as just haven't had a chance to work on it since initial progress at the beginning of the year - am *hoping* might have some time to pick it up again over Christmas...
2013-11-30 19:39:59 +00:00

429 lines
12 KiB
C++

/**
** 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
** the terms of the GNU General Public License as published by the Free
** 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/>.
**/
/*
* SDLInputSystem.cpp
*
* Implementation of SDL input system.
*/
#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
char *axisName = joyDetails.axisName[axisNum];
strcpy(axisName, CInputSystem::GetDefaultAxisName(axisNum)); // SDL 1.2 does not support axis names
}
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;
}
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);
}