- added best-effort algorithm to detect a formerly used joystick

- added stick config entities to configuration which includes a deadzone value
 - added methods to read and save this new entities
 - make StickInfo a part of the SDLDriver class
 - some spelling fixes
 - save config when leaving options menu through escape key (GA_LEAVE)



git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1679 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
thebohemian
2008-03-31 23:15:33 +00:00
parent 59e5960df4
commit f9a1798bc5
6 changed files with 287 additions and 38 deletions

View File

@@ -116,3 +116,12 @@ void Options::select()
break;
} // switch
}
void Options::handle(GameAction action, int value)
{
// Save config on leave.
if (!value && action == GA_LEAVE)
user_config->saveConfig();
BaseGUI::handle(action, value);
}

View File

@@ -29,6 +29,8 @@ public:
~Options();
void select();
void handle(GameAction, int);
};
#endif

View File

@@ -45,10 +45,12 @@
#define DEADZONE_MOUSE 150
#define DEADZONE_MOUSE_SENSE 200
#define DEADZONE_JOYSTICK 1000
#define DEADZONE_JOYSTICK (1000)
#define MULTIPLIER_MOUSE 750
using namespace std;
SDLDriver *inputDriver;
//-----------------------------------------------------------------------------
@@ -105,10 +107,7 @@ SDLDriver::SDLDriver()
SDL_JoystickEventState(SDL_ENABLE);
const int numSticks = SDL_NumJoysticks();
stickInfos = new StickInfo *[numSticks];
for (int i = 0; i < numSticks; i++)
stickInfos[i] = new StickInfo(i);
initStickInfos();
SDL_WM_SetCaption("SuperTuxKart", NULL);
@@ -116,6 +115,87 @@ SDLDriver::SDLDriver()
setMode(MENU);
}
void
SDLDriver::initStickInfos()
{
int nextIndex = 0;
// Prepare a list of connected joysticks.
const int numSticks = SDL_NumJoysticks();
stickInfos = new StickInfo *[numSticks];
vector<StickInfo *> *si = new vector<StickInfo *>;
for (int i = 0; i < numSticks; i++)
si->push_back(stickInfos[i] = new StickInfo(i));
// Get the list of known configs and make a copy of it.
vector<UserConfig::StickConfig *> *sc
= new vector<UserConfig::StickConfig *>(*user_config->getStickConfigs());
bool match;
vector<StickInfo *>::iterator si_ite = si->begin();
while (si_ite != si->end())
{
match = false;
vector<UserConfig::StickConfig *>::iterator sc_ite = sc->begin();
while (sc_ite != sc->end())
{
if (nextIndex <= (*sc_ite)->preferredIndex)
nextIndex = (*sc_ite)->preferredIndex + 1;
if (!(*si_ite)->id->compare((*sc_ite)->id))
{
// Connected stick matches a stored one.
// Copy important properties.
// Deadzone is taken only if its not null.
if ((*sc_ite)->deadzone)
(*si_ite)->deadzone = (*sc_ite)->deadzone;
// Restore former used index and other properties.
(*si_ite)->index = (*sc_ite)->preferredIndex;
// Remove matching entries from the list to prevent double
// allocation.
sc->erase(sc_ite);
si->erase(si_ite);
match = true;
break;
}
sc_ite++;
}
if (!match)
si_ite++;
}
delete sc;
// si now contains all those stick infos which have no stick config yet
// and nextIndex is set to the next free index.
// Now add all those new sticks and generate a config for them.
si_ite = si->begin();
while (si_ite != si->end())
{
(*si_ite)->index = nextIndex;
UserConfig::StickConfig *sc = new UserConfig::StickConfig(*(*si_ite)->id);
sc->preferredIndex = nextIndex;
sc->deadzone = DEADZONE_JOYSTICK;
user_config->addStickConfig(sc);
nextIndex++;
si_ite++;
}
delete si;
}
//-----------------------------------------------------------------------------
void
SDLDriver::showPointer()
@@ -208,9 +288,9 @@ SDLDriver::setVideoMode(bool resetTextures)
SDLDriver::~SDLDriver()
{
const int NUM_STICKS = SDL_NumJoysticks();
for (int i=0;i<NUM_STICKS;i++)
delete stickInfos[i];
for (int i = 0; i < NUM_STICKS; i++)
delete stickInfos[i];
delete [] stickInfos;
SDL_FreeSurface(mainSurface);
@@ -271,7 +351,7 @@ SDLDriver::input(InputType type, int id0, int id1, int id2, int value)
//-----------------------------------------------------------------------------
/** Reads the SDL event loop, does some tricks with certain values and calls
* input() is appropriate.
* input() if appropriate.
*
* Digital inputs get the value of 32768 when pressed (key/button press,
* digital axis) because this is what SDL provides. Relative mouse inputs
@@ -291,6 +371,10 @@ void
SDLDriver::input()
{
SDL_Event ev;
/* Logical joystick index that is reported to the higher game APIs which
* may not be equal to SDL's joystick index.
*/
int stickIndex;
while(SDL_PollEvent(&ev))
{
@@ -365,20 +449,21 @@ SDLDriver::input()
break;
case SDL_JOYAXISMOTION:
stickIndex = stickInfos[ev.jaxis.which]->index;
// If the joystick axis exceeds the deadzone report the input.
// In menu mode (mode = MENU = 0) the joystick number is reported
// to be zero in all cases. This has the neat effect that all
// joysticks can be used to control the menu.
if(ev.jaxis.value <= -DEADZONE_JOYSTICK)
if(ev.jaxis.value <= -stickInfos[ev.jaxis.which]->deadzone)
{
input(IT_STICKMOTION, !mode ? 0 : ev.jaxis.which,
input(IT_STICKMOTION, !mode ? 0 : stickIndex,
ev.jaxis.axis, AD_NEGATIVE, -ev.jaxis.value);
stickInfos[ev.jaxis.which]->prevAxisDirections[ev.jaxis.axis]
= AD_NEGATIVE;
}
else if(ev.jaxis.value >= DEADZONE_JOYSTICK)
else if(ev.jaxis.value >= stickInfos[ev.jaxis.which]->deadzone)
{
input(IT_STICKMOTION, !mode ? 0 : ev.jaxis.which,
input(IT_STICKMOTION, !mode ? 0 : stickIndex,
ev.jaxis.axis, AD_POSITIVE, ev.jaxis.value);
stickInfos[ev.jaxis.which]->prevAxisDirections[ev.jaxis.axis]
= AD_POSITIVE;
@@ -394,11 +479,11 @@ SDLDriver::input()
// two buttons).
if (stickInfos[ev.jaxis.which]
->prevAxisDirections[ev.jaxis.axis] == AD_NEGATIVE)
input(IT_STICKMOTION, !mode ? 0 : ev.jaxis.which,
input(IT_STICKMOTION, !mode ? 0 : stickIndex,
ev.jaxis.axis, AD_NEGATIVE, 0);
else if (stickInfos[ev.jaxis.which]
->prevAxisDirections[ev.jaxis.axis] == AD_POSITIVE)
input(IT_STICKMOTION, !mode ? 0 : ev.jaxis.which,
input(IT_STICKMOTION, !mode ? 0 : stickIndex,
ev.jaxis.axis, AD_POSITIVE, 0);
stickInfos[ev.jaxis.which]->prevAxisDirections[ev.jaxis.axis]
@@ -407,13 +492,17 @@ SDLDriver::input()
break;
case SDL_JOYBUTTONUP:
stickIndex = stickInfos[ev.jbutton.which]->index;
// See the SDL_JOYAXISMOTION case label because of !mode thingie.
input(IT_STICKBUTTON, !mode ? 0 : ev.jbutton.which, ev.jbutton.button, 0,
input(IT_STICKBUTTON, !mode ? 0 : stickIndex, ev.jbutton.button, 0,
0);
break;
case SDL_JOYBUTTONDOWN:
stickIndex = stickInfos[ev.jbutton.which]->index;
// See the SDL_JOYAXISMOTION case label because of !mode thingie.
input(IT_STICKBUTTON, !mode ? 0 : ev.jbutton.which, ev.jbutton.button, 0,
input(IT_STICKBUTTON, !mode ? 0 : stickIndex, ev.jbutton.button, 0,
32768);
break;
case SDL_USEREVENT:
@@ -616,18 +705,27 @@ SDLDriver::setMode(InputDriverMode newMode)
}
}
StickInfo::StickInfo(int index)
SDLDriver::StickInfo::StickInfo(int sdlIndex)
{
sdlJoystick = SDL_JoystickOpen(index);
sdlJoystick = SDL_JoystickOpen(sdlIndex);
id = new string(SDL_JoystickName(sdlIndex));
const int count = SDL_JoystickNumAxes(sdlJoystick);
prevAxisDirections = new AxisDirection[count];
for (int i = 0; i < count; i++)
prevAxisDirections[i] = AD_NEUTRAL;
deadzone = DEADZONE_JOYSTICK;
index = -1;
}
StickInfo::~StickInfo()
SDLDriver::StickInfo::~StickInfo()
{
delete id;
delete prevAxisDirections;
SDL_JoystickClose(sdlJoystick);

View File

@@ -20,6 +20,9 @@
#ifndef HEADER_SDLDRV_H
#define HEADER_SDLDRV_H
#include <string>
#include <vector>
#include <SDL/SDL.h>
#include "input.hpp"
@@ -36,25 +39,33 @@ enum InputDriverMode {
BOOTSTRAP
};
struct StickInfo {
SDL_Joystick *sdlJoystick;
AxisDirection *prevAxisDirections;
StickInfo(int);
~StickInfo();
};
class SDLDriver
{
class StickInfo {
public:
SDL_Joystick *sdlJoystick;
std::string *id;
int deadzone;
int index;
AxisDirection *prevAxisDirections;
StickInfo(int);
~StickInfo();
};
Input *sensedInput;
ActionMap *actionMap;
SDL_Surface *mainSurface;
long flags;
StickInfo **stickInfos;
InputDriverMode mode;
/* Helper values to store and track the relative mouse movements. If these
@@ -73,6 +84,8 @@ class SDLDriver
public:
SDLDriver();
~SDLDriver();
void initStickInfos();
void toggleFullscreen(bool resetTextures=1);

View File

@@ -68,7 +68,8 @@ UserConfig::UserConfig(const std::string& filename)
// -----------------------------------------------------------------------------
UserConfig::~UserConfig()
{}
{
}
// -----------------------------------------------------------------------------
/**
@@ -333,7 +334,7 @@ void UserConfig::loadConfig(const std::string& filename)
{
std::string temp;
const lisp::Lisp* root = 0;
int i;
int i = 0;
int dirExist = CheckAndCreateDir();
// Check if the config directory exists. If not, exit without an error
// message, an appropriate message was printed by CheckAndCreateDir
@@ -430,6 +431,9 @@ void UserConfig::loadConfig(const std::string& filename)
//get whether to log errors to file
lisp->get("log-errors", m_log_errors);
// Handle loading the stick config in it own method.
readStickConfigs(lisp);
// Unlock information:
const lisp::Lisp* unlock_info = lisp->getLisp("unlock-info");
@@ -501,6 +505,43 @@ void UserConfig::loadConfig(const std::string& filename)
delete root;
} // loadConfig
// -----------------------------------------------------------------------------
void
UserConfig::readStickConfigs(const lisp::Lisp *r)
{
string temp;
int count = 0;
const lisp::Lisp *scsreader = r->getLisp("stick-configs");
if (scsreader)
{
scsreader->get("count", count);
for (int i = 0; i < count; i++)
{
temp = "stick-";
temp += (i + '1');
const lisp::Lisp *screader = scsreader->getLisp(temp);
if (screader)
{
string *id = new string();
screader->get("id", *id);
StickConfig *sc = new StickConfig(*id);
screader->get("preferredIndex", sc->preferredIndex);
screader->get("deadzone", sc->deadzone);
m_stickconfigs.push_back(sc);
}
}
}
}
// -----------------------------------------------------------------------------
void
UserConfig::readPlayerInput(const lisp::Lisp *r, const char *node,
@@ -632,6 +673,8 @@ void UserConfig::saveConfig(const std::string& filename)
writer->writeComment("error logging to log (true) or stderr (false)");
writer->write("log-errors\t", m_log_errors);
writeStickConfigs(writer);
// Write unlock information back
writer->beginList("unlock-info");
@@ -679,6 +722,38 @@ void UserConfig::saveConfig(const std::string& filename)
delete writer;
} // saveConfig
// -----------------------------------------------------------------------------
void
UserConfig::writeStickConfigs(lisp::Writer *writer)
{
int count = 0;
string temp;
writer->beginList("stick-configs");
count = m_stickconfigs.size();
writer->write("count", count);
for (int i = 0; i < count; i++)
{
StickConfig *sc = m_stickconfigs[i];
temp = "stick-";
temp += i + '1';
writer->beginList(temp);
writer->write("id", sc->id);
writer->write("preferredIndex", sc->preferredIndex);
writer->writeComment("0 means that the default deadzone value is used.");
writer->write("deadzone", sc->deadzone);
writer->endList(temp);
}
writer->endList("stick-configs");
}
// -----------------------------------------------------------------------------
void
UserConfig::writePlayerInput(lisp::Writer *writer, const char *node,
@@ -976,4 +1051,25 @@ UserConfig::isFixedInput(InputType type, int id0, int id1, int id2)
return false;
}
// -----------------------------------------------------------------------------
void
UserConfig::addStickConfig(StickConfig *sc)
{
m_stickconfigs.push_back(sc);
}
// -----------------------------------------------------------------------------
const std::vector<UserConfig::StickConfig *> *
UserConfig::getStickConfigs() const
{
return &m_stickconfigs;
}
UserConfig::StickConfig::StickConfig(string &newId)
: id(newId)
{
// Nothing else to do.
}
/*EOF*/

View File

@@ -38,8 +38,9 @@
--> if a kart control for (say) player 2 uses the same key as
jump for player 1, this problem is not noticed in 0.3, but will
cause an undefined game action now
6: Added stick configurations.
*/
#define CURRENT_CONFIG_VERSION 5
#define CURRENT_CONFIG_VERSION 6
#include <string>
#include <vector>
@@ -54,7 +55,25 @@ class ActionMap;
/*class for managing general tuxkart configuration data*/
class UserConfig
{
public:
class StickConfig
{
public:
std::string &id;
int preferredIndex;
int deadzone;
StickConfig(std::string &);
};
private:
std::vector <StickConfig *> m_stickconfigs;
typedef struct
{
int count;
@@ -80,11 +99,21 @@ private:
int m_music;
std::string m_warning;
void readStickConfigs(const lisp::Lisp *);
void writeStickConfigs(lisp::Writer *);
void readPlayerInput(const lisp::Lisp *,
const char *,
KartAction ka,
int);
void writePlayerInput(lisp::Writer *,
const char *,
KartAction,
int);
void readInput(const lisp::Lisp *,
const char *,
GameAction);
@@ -93,10 +122,6 @@ private:
const char *,
GameAction);
void writePlayerInput(lisp::Writer *,
const char *,
KartAction,
int);
/** Iterates through the input mapping and unsets all
* where the given input occurs.
@@ -172,7 +197,12 @@ public:
void loadConfig(const std::string& filename);
void saveConfig();
void saveConfig(const std::string& filename);
void addStickConfig(UserConfig::StickConfig *);
const std::vector<StickConfig *> *getStickConfigs() const;
/** Retrieves a human readable string of the mapping for a GameAction */
std::string getMappingAsString(GameAction);
/** Retrieves a human readable string of the mapping for the given
@@ -199,6 +229,7 @@ public:
/** Creates ActionMap for use in ingame mode. */
ActionMap *newIngameActionMap();
};