Huge restructuring of the joystick handling code. Event mapping is now

saved per device, so that unplugging and replugging a joystick won't cause
the previous mappings to be lost.

All attributes of a joystick (ie, number of sticks, number of axes, buttons,
hats on each stick) are dynamic, meaning that hardcoded values are no
longer used, making the handling more robust.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2285 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2011-11-29 22:12:13 +00:00
parent 90fbe26b7d
commit d35c220953
8 changed files with 633 additions and 674 deletions

View File

@ -14,10 +14,24 @@
3.4.1 to 3.5: (December xx, 2011)
FIXME (will I have time for this?)
* Replaced NTSC TV filtering with Blargg NTSC filters. These filters
work in OpenGL mode only, but in contrast to the old filters, they
now work with OpenGL 1.x / OpenGL ES.
* Added several improvements to the joystick management code. Joystick
event mapping is now saved per device, meaning that if you map events
to a certain joystick device, remove the device and then later insert
it again, Stella will remember the original mapping.
* The total number of joysticks present and their associated properties
(number of axes, buttons, hats, etc) is now dynamic. That is, there's
no longer a hard-coded limit on number of joysticks that Stella can
use, or the number of buttons, etc that it contains. This fixes a
serious bug with PS3 controllers with 27 buttons, whereby adding a
mapping for joystick 0 would inadvertantly change settings for
joystick 1, and could potentially lead to a segfault.
* Huge restructuring of the OpenGL code, making it compatible with
OpenGL 2.x+ features (such as vertex buffer objects), while at the
same time keeping compatibility with OpenGL 1.5 / OpenGL ES.
@ -45,11 +59,12 @@
find. For most systems, it now defaults to the users 'Desktop.
Note that the commandline argument has changed to 'snapdir'.
* The debugger 'print' command now indicates "special" addresses if they
are read-only (R), write-only (W) or read-write (R/W).
* The debugger 'print' command now indicates "special" addresses if
they are read-only (R), write-only (W) or read-write (R/W).
* Fixed a bug in scrolling the mouse-wheel in certain debugger UI items
would cause the program to crash; scrolling now works as expected.
* Fixed a bug where scrolling the mouse-wheel in certain debugger UI
items would cause the program to crash; scrolling now works as
expected.
* Fixed compile issues in the latest versions of Ubuntu and Debian, and
fixed UNIX desktop file so that Stella will launch with a ROM when

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#ifndef EVENTHANDLER_HXX
#define EVENTHANDLER_HXX
#include <map>
#include <SDL.h>
class Console;
@ -130,41 +131,6 @@ class EventHandler
*/
void poll(uInt64 time);
/**
Set the default action for a joystick button to the given event
@param event The event we are assigning
@param mode The mode where this event is active
@param stick The joystick number
@param button The joystick button
*/
void setDefaultJoyMapping(Event::Type event, EventMode mode,
int stick, int button);
/**
Set the default for a joystick axis to the given event
@param event The event we are assigning
@param mode The mode where this event is active
@param stick The joystick number
@param axis The joystick axis
@param value The value on the given axis
*/
void setDefaultJoyAxisMapping(Event::Type event, EventMode mode,
int stick, int axis, int value);
/**
Set the default for a joystick hat to the given event
@param event The event we are assigning
@param mode The mode where this event is active
@param stick The joystick number
@param axis The joystick axis
@param value The value on the given axis
*/
void setDefaultJoyHatMapping(Event::Type event, EventMode mode,
int stick, int hat, int value);
/**
Returns the current state of the EventHandler
@ -237,8 +203,6 @@ class EventHandler
bool frying() const { return myFryingFlag; }
SDL_Joystick* getJoystick(int i) const { return ourJoysticks[i].stick; }
void getActionList(EventMode mode, StringList& list) const;
void getComboList(EventMode mode, StringMap& map) const;
@ -248,12 +212,12 @@ class EventHandler
Event::Type eventForKey(int key, EventMode mode) const
{ return myKeyTable[key][mode]; }
Event::Type eventForJoyButton(int stick, int button, EventMode mode) const
{ return myJoyTable[stick][button][mode]; }
Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) const
{ return myJoyAxisTable[stick][axis][(value > 0)][mode]; }
{ return myJoysticks[stick].axisTable[axis][(value > 0)][mode]; }
Event::Type eventForJoyButton(int stick, int button, EventMode mode) const
{ return myJoysticks[stick].btnTable[button][mode]; }
Event::Type eventForJoyHat(int stick, int hat, int value, EventMode mode) const
{ return myJoyHatTable[stick][hat][value][mode]; }
{ return myJoysticks[stick].hatTable[hat][value][mode]; }
Event::Type eventAtIndex(int idx, EventMode mode) const;
string actionAtIndex(int idx, EventMode mode) const;
@ -268,17 +232,6 @@ class EventHandler
*/
bool addKeyMapping(Event::Type event, EventMode mode, int key);
/**
Bind a joystick button to an event/action and regenerate the
mapping array(s)
@param event The event we are remapping
@param mode The mode where this event is active
@param stick The joystick number
@param button The joystick button
*/
bool addJoyMapping(Event::Type event, EventMode mode, int stick, int button);
/**
Bind a joystick axis direction to an event/action and regenerate
the mapping array(s)
@ -288,9 +241,28 @@ class EventHandler
@param stick The joystick number
@param axis The joystick axis
@param value The value on the given axis
@param updateMenus Whether to update the action mappings (normally
we want to do this, unless there are a batch of
'adds', in which case it's delayed until the end
*/
bool addJoyAxisMapping(Event::Type event, EventMode mode,
int stick, int axis, int value);
int stick, int axis, int value,
bool updateMenus = true);
/**
Bind a joystick button to an event/action and regenerate the
mapping array(s)
@param event The event we are remapping
@param mode The mode where this event is active
@param stick The joystick number
@param button The joystick button
@param updateMenus Whether to update the action mappings (normally
we want to do this, unless there are a batch of
'adds', in which case it's delayed until the end
*/
bool addJoyButtonMapping(Event::Type event, EventMode mode, int stick, int button,
bool updateMenus = true);
/**
Bind a joystick hat direction to an event/action and regenerate
@ -301,9 +273,13 @@ class EventHandler
@param stick The joystick number
@param axis The joystick hat
@param value The value on the given hat
@param updateMenus Whether to update the action mappings (normally
we want to do this, unless there are a batch of
'adds', in which case it's delayed until the end
*/
bool addJoyHatMapping(Event::Type event, EventMode mode,
int stick, int hat, int value);
int stick, int hat, int value,
bool updateMenus = true);
/**
Erase the specified mapping
@ -335,6 +311,13 @@ class EventHandler
void allowAllDirections(bool allow) { myAllowAllDirectionsFlag = allow; }
private:
enum {
kComboSize = 16,
kEventsPerCombo = 8,
kEmulActionListSize = 75 + kComboSize,
kMenuActionListSize = 14
};
/**
Detects and changes the eventhandler state
@ -350,29 +333,12 @@ class EventHandler
void setSDLMappings();
void setKeymap();
void setJoymap();
void setJoyAxisMap();
void setJoyHatMap();
void setDefaultKeymap(Event::Type, EventMode mode);
void setDefaultJoymap(Event::Type, EventMode mode);
void setDefaultJoyAxisMap(Event::Type, EventMode mode);
void setDefaultJoyHatMap(Event::Type, EventMode mode);
void saveKeyMapping();
void saveJoyMapping();
void saveJoyAxisMapping();
void saveJoyHatMapping();
void saveComboMapping();
/**
Tests if a mapping list is valid, both by length and by event count.
@param list The string containing the mappings, separated by ':'
@param map The result of parsing the string for int mappings
@param length The number of items that should be in the list
@return True if valid list, else false
*/
bool isValidList(string& list, IntArray& map, uInt32 length) const;
/**
Tests if a given event should use continuous/analog values.
@ -384,13 +350,6 @@ class EventHandler
void setEventState(State state);
private:
enum {
kComboSize = 16,
kEventsPerCombo = 8,
kEmulActionListSize = 75 + kComboSize,
kMenuActionListSize = 14
};
// Structure used for action menu items
struct ActionList {
Event::Type event;
@ -399,26 +358,6 @@ class EventHandler
bool allow_combo;
};
// Joystick related items
enum {
kNumJoysticks = 8,
kNumJoyButtons = 24,
kNumJoyAxis = 16,
kNumJoyHats = 16
};
enum JoyType {
JT_NONE = 0,
JT_REGULAR = 1,
JT_STELLADAPTOR_LEFT = 2,
JT_STELLADAPTOR_RIGHT = 3,
JT_2600DAPTOR_LEFT = 4,
JT_2600DAPTOR_RIGHT = 5
};
struct Stella_Joystick {
SDL_Joystick* stick;
JoyType type;
string name;
};
struct JoyMouse { // Used for joystick to mouse emulation
bool active;
int x, y, x_amt, y_amt, amt, val, old_val;
@ -436,17 +375,6 @@ class EventHandler
// Array of key events, indexed by SDLKey
Event::Type myKeyTable[SDLK_LAST][kNumModes];
// Array of joystick button events
Event::Type myJoyTable[kNumJoysticks][kNumJoyButtons][kNumModes];
// Array of joystick axis events
Event::Type myJoyAxisTable[kNumJoysticks][kNumJoyAxis][2][kNumModes];
// Array of joystick hat events (we don't record diagonals)
// Note that the array contains 4 directions, as defined in the JoyHat enum
// (the center isn't considered a direction)
Event::Type myJoyHatTable[kNumJoysticks][kNumJoyHats][4][kNumModes];
// The event(s) assigned to each combination event
Event::Type myComboTable[kComboSize][kEventsPerCombo];
@ -456,9 +384,6 @@ class EventHandler
// Array of strings which correspond to the given SDL key
string ourSDLMapping[SDLK_LAST];
// Array of joysticks available to Stella
Stella_Joystick ourJoysticks[kNumJoysticks];
// Indicates the current state of the system (ie, which mode is current)
State myState;
@ -489,10 +414,6 @@ class EventHandler
// Indicates which paddle the mouse currently emulates
Int8 myPaddleMode;
// Keeps track of last axis values (used to emulate digital state
// for analog sticks)
int myAxisLastValue[kNumJoysticks][kNumJoyAxis];
// Holds static strings for the remap menu (emulation and menu events)
static ActionList ourEmulActionList[kEmulActionListSize];
static ActionList ourMenuActionList[kMenuActionListSize];
@ -500,6 +421,50 @@ class EventHandler
// Static lookup tables for Stelladaptor axis/button support
static const Event::Type SA_Axis[2][2];
static const Event::Type SA_Button[2][2];
// Thin wrapper holding all information about an SDL joystick in Stella.
// A StellaJoystick holds its own event mapping information, space for
// which is dynamically allocated based on the actual number of buttons,
// axes, etc that the device contains.
class StellaJoystick
{
public:
StellaJoystick();
virtual ~StellaJoystick();
string setStick(int i);
string getMap() const;
bool setMap(const string& map);
void eraseMap(EventMode mode);
void eraseEvent(Event::Type event, EventMode mode);
string about() const;
public:
enum JoyType {
JT_NONE = 0,
JT_REGULAR = 1,
JT_STELLADAPTOR_LEFT = 2,
JT_STELLADAPTOR_RIGHT = 3,
JT_2600DAPTOR_LEFT = 4,
JT_2600DAPTOR_RIGHT = 5
};
JoyType type;
string name;
int numAxes, numButtons, numHats;
Event::Type (*axisTable)[2][kNumModes];
Event::Type (*btnTable)[kNumModes];
Event::Type (*hatTable)[4][kNumModes];
int* axisLastValue;
private:
void getValues(string& list, IntArray& map);
private:
SDL_Joystick* stick;
};
StellaJoystick* myJoysticks;
uInt32 myNumJoysticks;
map<string,string> myJoystickMap;
};
#endif

View File

@ -887,38 +887,17 @@ void OSystem::validatePath(string& path, const string& setting,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::setDefaultJoymap(Event::Type event, EventMode mode)
{
#define SET_DEFAULT_BTN(sdb_event, sdb_mode, sdb_stick, sdb_button, sdb_cmp_event) \
if(eraseAll || sdb_cmp_event == sdb_event) \
myEventHandler->setDefaultJoyMapping(sdb_event, sdb_mode, sdb_stick, sdb_button);
bool eraseAll = (event == Event::NoType);
switch(mode)
{
case kEmulationMode: // Default emulation events
// Left joystick (assume joystick zero, button zero)
SET_DEFAULT_BTN(Event::JoystickZeroFire1, mode, 0, 0, event);
// Right joystick (assume joystick one, button zero)
SET_DEFAULT_BTN(Event::JoystickOneFire1, mode, 1, 0, event);
break;
case kMenuMode: // Default menu/UI events
// Left joystick (assume joystick zero, button zero)
SET_DEFAULT_BTN(Event::UISelect, mode, 0, 0, event);
// Right joystick (assume joystick one, button zero)
SET_DEFAULT_BTN(Event::UISelect, mode, 1, 0, event);
break;
default:
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::setDefaultJoyAxisMap(Event::Type event, EventMode mode)
{
#define SET_DEFAULT_AXIS(sda_event, sda_mode, sda_stick, sda_axis, sda_val, sda_cmp_event) \
if(eraseAll || sda_cmp_event == sda_event) \
myEventHandler->setDefaultJoyAxisMapping(sda_event, sda_mode, sda_stick, sda_axis, sda_val);
myEventHandler->addJoyAxisMapping(sda_event, sda_mode, sda_stick, sda_axis, sda_val, false);
#define SET_DEFAULT_BTN(sdb_event, sdb_mode, sdb_stick, sdb_button, sdb_cmp_event) \
if(eraseAll || sdb_cmp_event == sdb_event) \
myEventHandler->addJoyButtonMapping(sdb_event, sdb_mode, sdb_stick, sdb_button, false);
#define SET_DEFAULT_HAT(sdh_event, sdh_mode, sdh_stick, sdh_hat, sdh_dir, sdh_cmp_event) \
if(eraseAll || sdh_cmp_event == sdh_event) \
myEventHandler->addJoyHatMapping(sdh_event, sdh_mode, sdh_stick, sdh_hat, sdh_dir, false);
bool eraseAll = (event == Event::NoType);
switch(mode)
@ -936,6 +915,19 @@ void OSystem::setDefaultJoyAxisMap(Event::Type event, EventMode mode)
// Right joystick left/right directions (assume joystick one)
SET_DEFAULT_AXIS(Event::JoystickOneUp, mode, 1, 1, 0, event);
SET_DEFAULT_AXIS(Event::JoystickOneDown, mode, 1, 1, 1, event);
// Left joystick (assume joystick zero, button zero)
SET_DEFAULT_BTN(Event::JoystickZeroFire1, mode, 0, 0, event);
// Right joystick (assume joystick one, button zero)
SET_DEFAULT_BTN(Event::JoystickOneFire1, mode, 1, 0, event);
// Left joystick left/right directions (assume joystick zero and hat 0)
SET_DEFAULT_HAT(Event::JoystickZeroLeft, mode, 0, 0, EVENT_HATLEFT, event);
SET_DEFAULT_HAT(Event::JoystickZeroRight, mode, 0, 0, EVENT_HATRIGHT, event);
// Left joystick up/down directions (assume joystick zero and hat 0)
SET_DEFAULT_HAT(Event::JoystickZeroUp, mode, 0, 0, EVENT_HATUP, event);
SET_DEFAULT_HAT(Event::JoystickZeroDown, mode, 0, 0, EVENT_HATDOWN, event);
break;
case kMenuMode: // Default menu/UI events
@ -943,37 +935,17 @@ void OSystem::setDefaultJoyAxisMap(Event::Type event, EventMode mode)
SET_DEFAULT_AXIS(Event::UIRight, mode, 0, 0, 1, event);
SET_DEFAULT_AXIS(Event::UIUp, mode, 0, 1, 0, event);
SET_DEFAULT_AXIS(Event::UIDown, mode, 0, 1, 1, event);
break;
default:
break;
}
}
// Left joystick (assume joystick zero, button zero)
SET_DEFAULT_BTN(Event::UISelect, mode, 0, 0, event);
// Right joystick (assume joystick one, button zero)
SET_DEFAULT_BTN(Event::UISelect, mode, 1, 0, event);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::setDefaultJoyHatMap(Event::Type event, EventMode mode)
{
#define SET_DEFAULT_HAT(sdh_event, sdh_mode, sdh_stick, sdh_hat, sdh_dir, sdh_cmp_event) \
if(eraseAll || sdh_cmp_event == sdh_event) \
myEventHandler->setDefaultJoyHatMapping(sdh_event, sdh_mode, sdh_stick, sdh_hat, sdh_dir);
bool eraseAll = (event == Event::NoType);
switch(mode)
{
case kEmulationMode: // Default emulation events
// Left joystick left/right directions (assume joystick zero and hat 0)
SET_DEFAULT_HAT(Event::JoystickZeroLeft, mode, 0, 0, EVENT_HATLEFT, event);
SET_DEFAULT_HAT(Event::JoystickZeroRight, mode, 0, 0, EVENT_HATRIGHT, event);
// Left joystick up/down directions (assume joystick zero and hat 0)
SET_DEFAULT_HAT(Event::JoystickZeroUp, mode, 0, 0, EVENT_HATUP, event);
SET_DEFAULT_HAT(Event::JoystickZeroDown, mode, 0, 0, EVENT_HATDOWN, event);
break;
case kMenuMode: // Default menu/UI events
SET_DEFAULT_HAT(Event::UILeft, mode, 0, 0, EVENT_HATLEFT, event);
SET_DEFAULT_HAT(Event::UIRight, mode, 0, 0, EVENT_HATRIGHT, event);
SET_DEFAULT_HAT(Event::UIUp, mode, 0, 0, EVENT_HATUP, event);
SET_DEFAULT_HAT(Event::UIDown, mode, 0, 0, EVENT_HATDOWN, event);
break;
default:
@ -986,14 +958,6 @@ void OSystem::pollEvent()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool OSystem::joyButtonHandled(int button)
{
// Since we don't do any platform-specific event polling,
// no button is ever handled at this level
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::stateChanged(EventHandler::State state)
{

View File

@ -419,7 +419,7 @@ class OSystem
virtual void mainLoop();
/**
This method determines the default mapping of joystick buttons to
This method determines the default mapping of joystick actions to
Stella events for a specific system/platform.
@param event The event which to (re)set (Event::NoType resets all)
@ -427,36 +427,11 @@ class OSystem
*/
virtual void setDefaultJoymap(Event::Type event, EventMode mode);
/**
This method determines the default mapping of joystick axis to
Stella events for a specific system/platform.
@param event The event which to (re)set (Event::NoType resets all)
@param mode The mode for which the defaults are set
*/
virtual void setDefaultJoyAxisMap(Event::Type event, EventMode mode);
/**
This method determines the default mapping of joystick hats to
Stella events for a specific system/platform.
@param event The event which to (re)set (Event::NoType resets all)
@param mode The mode for which the defaults are set
*/
virtual void setDefaultJoyHatMap(Event::Type event, EventMode mode);
/**
This method creates events from platform-specific hardware.
*/
virtual void pollEvent();
/**
This method answers whether the given button as already been
handled by the pollEvent() method, and as such should be ignored
in the main event handler.
*/
virtual bool joyButtonHandled(int button);
/**
Informs the OSystem of a change in EventHandler state.
*/

View File

@ -35,8 +35,7 @@ PropertiesSet::PropertiesSet(OSystem* osystem)
: myOSystem(osystem),
mySize(0)
{
const string& props = myOSystem->propertiesFile();
load(props);
load(myOSystem->propertiesFile());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -128,7 +127,7 @@ bool PropertiesSet::getMD5(const string& md5, Properties& properties,
while(low <= high)
{
int i = (low + high) / 2;
int cmp = strncmp(md5.c_str(), DefProps[i][Cartridge_MD5], 32);
int cmp = BSPF_strncasecmp(md5.c_str(), DefProps[i][Cartridge_MD5], 32);
if(cmp == 0) // found it
{

View File

@ -79,8 +79,6 @@ Settings::Settings(OSystem* osystem)
// Input event options
setInternal("keymap", "");
setInternal("joymap", "");
setInternal("joyaxismap", "");
setInternal("joyhatmap", "");
setInternal("combomap", "");
setInternal("joydeadzone", "13");
setInternal("joyallow4", "false");

View File

@ -272,7 +272,7 @@ void EventMappingWidget::handleJoyDown(int stick, int button)
{
Event::Type event =
instance().eventHandler().eventAtIndex(myActionSelected, myEventMode);
if(instance().eventHandler().addJoyMapping(event, myEventMode, stick, button))
if(instance().eventHandler().addJoyButtonMapping(event, myEventMode, stick, button))
stopRemapping();
}
}