From 34862267989b38754c1804b91bcf65bbc528668d Mon Sep 17 00:00:00 2001 From: Pieter Hulshoff Date: Fri, 14 Jul 2017 13:09:16 +0200 Subject: [PATCH] Added hot-pluggability for controllers. Fixed loss of controller after a game has been run when unloadSDL = true. --- RetroFE/Source/Control/JoyAxisHandler.cpp | 2 +- RetroFE/Source/Control/JoyButtonHandler.cpp | 2 +- RetroFE/Source/Control/JoyHatHandler.cpp | 2 +- RetroFE/Source/Control/UserInput.cpp | 106 +++++++++++++++----- RetroFE/Source/Control/UserInput.h | 5 +- RetroFE/Source/RetroFE.cpp | 11 +- RetroFE/Source/Version.cpp | 2 +- 7 files changed, 96 insertions(+), 34 deletions(-) diff --git a/RetroFE/Source/Control/JoyAxisHandler.cpp b/RetroFE/Source/Control/JoyAxisHandler.cpp index 5f2677b..533fbe7 100644 --- a/RetroFE/Source/Control/JoyAxisHandler.cpp +++ b/RetroFE/Source/Control/JoyAxisHandler.cpp @@ -16,7 +16,7 @@ void JoyAxisHandler::reset() bool JoyAxisHandler::update(SDL_Event &e) { - if(e.type != SDL_JOYAXISMOTION || e.jaxis.which != joyid_ || e.jaxis.axis != axis_) return false; + if(e.type != SDL_JOYAXISMOTION || (joyid_ != -1 && e.jaxis.which != joyid_) || e.jaxis.axis != axis_) return false; pressed_ = (min_ <= e.jaxis.value && e.jaxis.value <= max_); return true; diff --git a/RetroFE/Source/Control/JoyButtonHandler.cpp b/RetroFE/Source/Control/JoyButtonHandler.cpp index ff3e3ed..370d461 100644 --- a/RetroFE/Source/Control/JoyButtonHandler.cpp +++ b/RetroFE/Source/Control/JoyButtonHandler.cpp @@ -16,7 +16,7 @@ bool JoyButtonHandler::update(SDL_Event &e) { if(e.type != SDL_JOYBUTTONUP && e.type != SDL_JOYBUTTONDOWN) return false; - if(e.jbutton.which == joynum_ && e.jbutton.button == button_) + if((joynum_ == -1 || e.jbutton.which == joynum_) && e.jbutton.button == button_) { pressed_ = (e.type == SDL_JOYBUTTONDOWN) ? true : false; return true; diff --git a/RetroFE/Source/Control/JoyHatHandler.cpp b/RetroFE/Source/Control/JoyHatHandler.cpp index 5b8c3c8..be38df4 100644 --- a/RetroFE/Source/Control/JoyHatHandler.cpp +++ b/RetroFE/Source/Control/JoyHatHandler.cpp @@ -15,7 +15,7 @@ void JoyHatHandler::reset() bool JoyHatHandler::update(SDL_Event &e) { - if(e.type != SDL_JOYHATMOTION || e.jhat.which != joynum_ || e.jhat.hat != hatnum_) return false; + if(e.type != SDL_JOYHATMOTION || (joynum_ != -1 && e.jhat.which != joynum_) || e.jhat.hat != hatnum_) return false; pressed_ = (e.jhat.value == direction_); return true; diff --git a/RetroFE/Source/Control/UserInput.cpp b/RetroFE/Source/Control/UserInput.cpp index 0919247..5fdf80d 100644 --- a/RetroFE/Source/Control/UserInput.cpp +++ b/RetroFE/Source/Control/UserInput.cpp @@ -32,6 +32,10 @@ UserInput::UserInput(Configuration &c) currentKeyState_[i] = false; lastKeyState_[i] = false; } + for ( unsigned int i = 0; i < cMaxJoy; i++ ) + { + joysticks_[i] = -1; + } } UserInput::~UserInput() @@ -43,15 +47,6 @@ UserInput::~UserInput() delete keyHandlers_[i].first; } } - -// This code causes an exception when a controller is attached; it's disabled to prevent crashes on exit. -// for(std::vector::iterator it = joysticks_.begin(); it != joysticks_.end(); it++) -// { -// if(*it) -// { -// SDL_JoystickClose(*it); -// } -// } } bool UserInput::initialize() @@ -93,12 +88,6 @@ bool UserInput::initialize() // retVal = MapKey("admin", KeyCodeAdminMode) && retVal; // retVal = MapKey("remove", KeyCodeHideItem) && retVal; - for(int i = 0; i < SDL_NumJoysticks(); ++i) - { - joysticks_.push_back(SDL_JoystickOpen(i)); - } - - return retVal; } @@ -167,12 +156,18 @@ bool UserInput::MapKey(std::string keyDescription, KeyCode_E key, bool required) else if (token.find("joy") == 0) { std::string joydesc = Utils::replace(Utils::toLower(token), "joy", ""); - std::stringstream ssjoy; - ssjoy << joydesc.at(0); int joynum; - ssjoy >> joynum; - joydesc = joydesc.erase(0, 1); - + if ( std::isdigit( joydesc.at( 0 ) ) ) + { + std::stringstream ssjoy; + ssjoy << joydesc.at(0); + ssjoy >> joynum; + joydesc = joydesc.erase(0, 1); + } + else + { + joynum = -1; + } if (joydesc.find("button") == 0) { @@ -271,27 +266,76 @@ void UserInput::resetStates() } } -bool UserInput::update(SDL_Event &e) + +bool UserInput::update( SDL_Event &e ) { bool updated = false; - memcpy(lastKeyState_, currentKeyState_, sizeof(lastKeyState_)); - memset(currentKeyState_, 0, sizeof(currentKeyState_)); + memcpy( lastKeyState_, currentKeyState_, sizeof( lastKeyState_ ) ); + memset( currentKeyState_, 0, sizeof( currentKeyState_ ) ); - for (unsigned int i = 0; i < keyHandlers_.size(); ++i) + // Handle adding a joystick + if ( e.type == SDL_JOYDEVICEADDED ) + { + SDL_JoystickID id = SDL_JoystickInstanceID( SDL_JoystickOpen( e.jdevice.which ) ); + for ( unsigned int i = 0; i < cMaxJoy; i++ ) + { + if ( joysticks_[i] == -1 ) + { + joysticks_[i] = id; + break; + } + } + } + + // Handle removing a joystick + if ( e.type == SDL_JOYDEVICEREMOVED ) + { + for ( unsigned int i = 0; i < cMaxJoy; i++ ) + { + if ( joysticks_[i] == e.jdevice.which ) + { + joysticks_[i] = -1; + break; + } + } + SDL_JoystickClose( SDL_JoystickFromInstanceID( e.jdevice.which ) ); + } + + // Remap joystick events + if ( e.type == SDL_JOYAXISMOTION || + e.type == SDL_JOYBUTTONUP || + e.type == SDL_JOYBUTTONDOWN || + e.type == SDL_JOYHATMOTION ) + { + for ( unsigned int i = 0; i < cMaxJoy; i++ ) + { + if ( joysticks_[i] == e.jdevice.which ) + { + e.jdevice.which = i; + e.jaxis.which = i; + e.jbutton.which = i; + e.jhat.which = i; + break; + } + } + } + + for ( unsigned int i = 0; i < keyHandlers_.size( ); ++i ) { InputHandler *h = keyHandlers_[i].first; - if(h) + if ( h ) { - if(h->update(e)) updated = true; + if ( h->update( e ) ) updated = true; - currentKeyState_[keyHandlers_[i].second] |= h->pressed(); + currentKeyState_[keyHandlers_[i].second] |= h->pressed( ); } } return updated; } + bool UserInput::keystate(KeyCode_E code) { return currentKeyState_[code]; @@ -302,3 +346,11 @@ bool UserInput::newKeyPressed(KeyCode_E code) return currentKeyState_[code] && !lastKeyState_[code]; } + +void UserInput::clearJoysticks( ) +{ + for ( unsigned int i = 0; i < cMaxJoy; i++ ) + { + joysticks_[i] = -1; + } +} \ No newline at end of file diff --git a/RetroFE/Source/Control/UserInput.h b/RetroFE/Source/Control/UserInput.h index 25bec1d..10ebd4c 100644 --- a/RetroFE/Source/Control/UserInput.h +++ b/RetroFE/Source/Control/UserInput.h @@ -20,6 +20,8 @@ #include #include +const int cMaxJoy = 4; + class Configuration; class InputHandler; @@ -58,12 +60,13 @@ public: bool update(SDL_Event &e); bool keystate(KeyCode_E); bool newKeyPressed(KeyCode_E code); + void clearJoysticks( ); private: bool MapKey(std::string keyDescription, KeyCode_E key); bool MapKey(std::string keyDescription, KeyCode_E key, bool required); Configuration &config_; - std::vector joysticks_; + SDL_JoystickID joysticks_[cMaxJoy]; std::vector > keyHandlers_; bool lastKeyState_[KeyCodeMax]; bool currentKeyState_[KeyCodeMax]; diff --git a/RetroFE/Source/RetroFE.cpp b/RetroFE/Source/RetroFE.cpp index 2884c8c..7ae7351 100644 --- a/RetroFE/Source/RetroFE.cpp +++ b/RetroFE/Source/RetroFE.cpp @@ -159,9 +159,15 @@ void RetroFE::launchExit( ) SDL_RaiseWindow( SDL::getWindow( ) ); SDL_SetWindowGrab( SDL::getWindow( ), SDL_TRUE ); - // Empty event queue + // Empty event queue, but handle joystick add/remove events SDL_Event e; - while ( SDL_PollEvent( &e ) ); + while ( SDL_PollEvent( &e ) ) + { + if ( e.type == SDL_JOYDEVICEADDED || e.type == SDL_JOYDEVICEREMOVED ) + { + input_.update( e ); + } + } input_.resetStates( ); attract_.reset( ); @@ -189,6 +195,7 @@ void RetroFE::freeGraphicsMemory( ) { currentPage_->deInitializeFonts( ); SDL::deInitialize( ); + input_.clearJoysticks( ); } } diff --git a/RetroFE/Source/Version.cpp b/RetroFE/Source/Version.cpp index 54e3263..c23eba3 100644 --- a/RetroFE/Source/Version.cpp +++ b/RetroFE/Source/Version.cpp @@ -21,7 +21,7 @@ std::string retrofe_version_major = "0"; std::string retrofe_version_minor = "8"; -std::string retrofe_version_build = "12"; +std::string retrofe_version_build = "13"; std::string Version::getString( )