Dynamic joystick add/remove/mapping is now working again. Or at least

it is on all my test systems with 4 different controllers.  We still
need bugtesters for this ...


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@3112 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2014-12-21 00:42:52 +00:00
parent 04b99e3503
commit 7fee57808c
5 changed files with 50 additions and 33 deletions

View File

@ -19,6 +19,9 @@
Clang 3.3, gcc 4.9, Xcode 6, etc). Eventually, this will bring more Clang 3.3, gcc 4.9, Xcode 6, etc). Eventually, this will bring more
bug-free and (hopefully) faster code. bug-free and (hopefully) faster code.
* Fixed major bug with joysticks, where mapping was being lost on reset,
the app would crash when plugging/unplugging certain sticks, etc.
* The minimum supported version for the OSX port is now OSX 10.7. * The minimum supported version for the OSX port is now OSX 10.7.
Because of this, the 32-bit version is also discontinued, as 10.7 Because of this, the 32-bit version is also discontinued, as 10.7
is 64-bit Intel only. is 64-bit Intel only.

View File

@ -207,7 +207,16 @@ EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
myStick = SDL_JoystickOpen(idx); myStick = SDL_JoystickOpen(idx);
if(myStick) if(myStick)
{ {
initialize(idx, SDL_JoystickName(myStick), // There still seems to be some issue with certain controllers not being
// recognized. In this case, SDL names the controller as "XInput Controller".
// This would be fine except it also appends " #x", where x seems to vary.
// Obviously this wreaks havoc with the idea that a joystick will always
// have the same name. So we truncate the number.
const char* sdlname = SDL_JoystickName(myStick);
const string& desc = BSPF_startsWithIgnoreCase(sdlname, "XInput Controller")
? "XInput Controller" : sdlname;
initialize(SDL_JoystickInstanceID(myStick), desc,
SDL_JoystickNumAxes(myStick), SDL_JoystickNumButtons(myStick), SDL_JoystickNumAxes(myStick), SDL_JoystickNumButtons(myStick),
SDL_JoystickNumHats(myStick), SDL_JoystickNumBalls(myStick)); SDL_JoystickNumHats(myStick), SDL_JoystickNumBalls(myStick));
} }
@ -218,5 +227,4 @@ EventHandlerSDL2::JoystickSDL2::~JoystickSDL2()
{ {
if(myStick) if(myStick)
SDL_JoystickClose(myStick); SDL_JoystickClose(myStick);
myStick = nullptr;
} }

View File

@ -1073,9 +1073,10 @@ void EventHandler::setActionMappings(EventMode mode)
} }
#ifdef JOYSTICK_SUPPORT #ifdef JOYSTICK_SUPPORT
for(uInt32 stick = 0; stick < myJoyHandler->numSticks(); ++stick) for(const auto& i: myJoyHandler->sticks())
{ {
const StellaJoystick* joy = myJoyHandler->joy(stick); uInt32 stick = i.first;
const StellaJoystick* joy = i.second;
if(!joy) continue; if(!joy) continue;
// Joystick button mapping/labeling // Joystick button mapping/labeling

View File

@ -424,21 +424,23 @@ class EventHandler
class JoystickHandler class JoystickHandler
{ {
using StickList = map<int, StellaJoystick*>;
public: public:
JoystickHandler(OSystem& system); JoystickHandler(OSystem& system);
~JoystickHandler(); ~JoystickHandler();
int add(StellaJoystick* stick); int add(StellaJoystick* stick);
int remove(int id); int remove(int id);
uInt32 numSticks() const { return (uInt32)mySticks.size(); }
void mapStelladaptors(const string& saport); void mapStelladaptors(const string& saport);
void setDefaultMapping(Event::Type type, EventMode mode); void setDefaultMapping(Event::Type type, EventMode mode);
void eraseMapping(Event::Type event, EventMode mode); void eraseMapping(Event::Type event, EventMode mode);
void saveMapping(); void saveMapping();
const StellaJoystick* joy(int id) const { const StellaJoystick* joy(int id) const {
return id < (int)mySticks.size() ? mySticks[id] : nullptr; const auto& i = mySticks.find(id);
return i != mySticks.cend() ? i->second : nullptr;
} }
const StickList& sticks() const { return mySticks; }
private: private:
OSystem& myOSystem; OSystem& myOSystem;
@ -460,7 +462,7 @@ class EventHandler
map<string,StickInfo> myDatabase; map<string,StickInfo> myDatabase;
// Contains only joysticks that are currently available, indexed by id // Contains only joysticks that are currently available, indexed by id
vector<StellaJoystick*> mySticks; StickList mySticks;
void setStickDefaultMapping(int stick, Event::Type type, EventMode mode); void setStickDefaultMapping(int stick, Event::Type type, EventMode mode);
void printDatabase() const; void printDatabase() const;

View File

@ -273,11 +273,11 @@ void EventHandler::JoystickHandler::printDatabase() const
for(const auto& i: myDatabase) for(const auto& i: myDatabase)
cerr << i.first << endl << i.second << endl << endl; cerr << i.first << endl << i.second << endl << endl;
cerr << "---------------------------------------------------------" << endl cerr << "---------------------" << endl
<< "joy active:" << endl; << "joy active:" << endl;
for(const auto& i: mySticks) for(const auto& i: mySticks)
cerr << i << endl; cerr << i.first << ": " << *i.second << endl;
cerr << endl; cerr << "---------------------------------------------------------" << endl << endl << endl;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -326,7 +326,8 @@ int EventHandler::JoystickHandler::add(StellaJoystick* stick)
} }
stick->type = StellaJoystick::JT_REGULAR; stick->type = StellaJoystick::JT_REGULAR;
} }
Vec::insertAt(mySticks, stick->ID, stick); // The stick *must* be inserted here, since it may be used below
mySticks[stick->ID] = stick;
// Map the stelladaptors we've found according to the specified ports // Map the stelladaptors we've found according to the specified ports
if(specialAdaptor) if(specialAdaptor)
@ -358,9 +359,9 @@ int EventHandler::JoystickHandler::remove(int index)
// Sticks that are removed must have initially been added // Sticks that are removed must have initially been added
// So we use the 'active' joystick list to access them // So we use the 'active' joystick list to access them
if(index >= 0 && index < (int)mySticks.size() && mySticks[index] != nullptr) try
{ {
StellaJoystick* stick = mySticks[index]; StellaJoystick* stick = mySticks.at(index);
auto it = myDatabase.find(stick->name); auto it = myDatabase.find(stick->name);
if(it != myDatabase.end() && it->second.joy == stick) if(it != myDatabase.end() && it->second.joy == stick)
@ -373,11 +374,15 @@ int EventHandler::JoystickHandler::remove(int index)
// Remove joystick, but remember mapping // Remove joystick, but remember mapping
it->second.mapping = stick->getMap(); it->second.mapping = stick->getMap();
delete it->second.joy; it->second.joy = nullptr; delete it->second.joy; it->second.joy = nullptr;
mySticks[index] = nullptr; mySticks.erase(index);
return index; return index;
} }
} }
catch(std::out_of_range)
{
}
return -1; return -1;
} }
@ -396,33 +401,33 @@ void EventHandler::JoystickHandler::mapStelladaptors(const string& saport)
saOrder[0] = 2; saOrder[1] = 1; saOrder[0] = 2; saOrder[1] = 1;
} }
for(auto stick: mySticks) for(auto& stick: mySticks)
{ {
if(BSPF_startsWithIgnoreCase(stick->name, "Stelladaptor")) if(BSPF_startsWithIgnoreCase(stick.second->name, "Stelladaptor"))
{ {
if(saOrder[saCount] == 1) if(saOrder[saCount] == 1)
{ {
stick->name += " (emulates left joystick port)"; stick.second->name += " (emulates left joystick port)";
stick->type = StellaJoystick::JT_STELLADAPTOR_LEFT; stick.second->type = StellaJoystick::JT_STELLADAPTOR_LEFT;
} }
else if(saOrder[saCount] == 2) else if(saOrder[saCount] == 2)
{ {
stick->name += " (emulates right joystick port)"; stick.second->name += " (emulates right joystick port)";
stick->type = StellaJoystick::JT_STELLADAPTOR_RIGHT; stick.second->type = StellaJoystick::JT_STELLADAPTOR_RIGHT;
} }
saCount++; saCount++;
} }
else if(BSPF_startsWithIgnoreCase(stick->name, "2600-daptor")) else if(BSPF_startsWithIgnoreCase(stick.second->name, "2600-daptor"))
{ {
if(saOrder[saCount] == 1) if(saOrder[saCount] == 1)
{ {
stick->name += " (emulates left joystick port)"; stick.second->name += " (emulates left joystick port)";
stick->type = StellaJoystick::JT_2600DAPTOR_LEFT; stick.second->type = StellaJoystick::JT_2600DAPTOR_LEFT;
} }
else if(saOrder[saCount] == 2) else if(saOrder[saCount] == 2)
{ {
stick->name += " (emulates right joystick port)"; stick.second->name += " (emulates right joystick port)";
stick->type = StellaJoystick::JT_2600DAPTOR_RIGHT; stick.second->type = StellaJoystick::JT_2600DAPTOR_RIGHT;
} }
saCount++; saCount++;
} }
@ -434,8 +439,8 @@ void EventHandler::JoystickHandler::mapStelladaptors(const string& saport)
void EventHandler::JoystickHandler::setDefaultMapping(Event::Type event, EventMode mode) void EventHandler::JoystickHandler::setDefaultMapping(Event::Type event, EventMode mode)
{ {
eraseMapping(event, mode); eraseMapping(event, mode);
setStickDefaultMapping(0, event, mode); for(auto& i: mySticks)
setStickDefaultMapping(1, event, mode); setStickDefaultMapping(i.first, event, mode);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -510,8 +515,6 @@ void EventHandler::JoystickHandler::setStickDefaultMapping(int stick,
// Left joystick (assume joystick zero, button zero) // Left joystick (assume joystick zero, button zero)
setDefaultBtn( 0, 0, Event::UISelect ); setDefaultBtn( 0, 0, Event::UISelect );
// Right joystick (assume joystick one, button zero)
setDefaultBtn( 1, 0, Event::UISelect );
setDefaultHat( 0, 0, EVENT_HATLEFT, Event::UILeft ); setDefaultHat( 0, 0, EVENT_HATLEFT, Event::UILeft );
setDefaultHat( 0, 0, EVENT_HATRIGHT, Event::UIRight ); setDefaultHat( 0, 0, EVENT_HATRIGHT, Event::UIRight );
@ -533,13 +536,13 @@ void EventHandler::JoystickHandler::eraseMapping(Event::Type event, EventMode mo
// Otherwise, only reset the given event // Otherwise, only reset the given event
if(event == Event::NoType) if(event == Event::NoType)
{ {
for(auto stick: mySticks) for(auto& stick: mySticks)
stick->eraseMap(mode); // erase all events stick.second->eraseMap(mode); // erase all events
} }
else else
{ {
for(auto stick: mySticks) for(auto& stick: mySticks)
stick->eraseEvent(event, mode); // only reset the specific event stick.second->eraseEvent(event, mode); // only reset the specific event
} }
} }