#include "JoystickSDL.h" #include "QGCApplication.h" #include #include JoystickSDL::JoystickSDL(const QString& name, int axisCount, int buttonCount, int hatCount, int index, bool isGameController, MultiVehicleManager* multiVehicleManager) : Joystick(name,axisCount,buttonCount,hatCount,multiVehicleManager) , _isGameController(isGameController) , _index(index) { if(_isGameController) _setDefaultCalibration(); } bool JoystickSDL::init(void) { if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) < 0) { SDL_JoystickEventState(SDL_ENABLE); qWarning() << "Couldn't initialize SimpleDirectMediaLayer:" << SDL_GetError(); return false; } _loadGameControllerMappings(); return true; } QMap JoystickSDL::discover(MultiVehicleManager* _multiVehicleManager) { static QMap ret; QMap newRet; // Load available joysticks qCDebug(JoystickLog) << "Available joysticks"; for (int i=0; i(newRet[name]); if (j->index() != i) { j->setIndex(i); // This joystick index has been remapped by SDL } // Anything left in ret after we exit the loop has been removed (unplugged) and needs to be cleaned up. // We will handle that in JoystickManager in case the removed joystick was in use. ret.remove(name); qCDebug(JoystickLog) << "\tSkipping duplicate" << name; } } if (!newRet.count()) { qCDebug(JoystickLog) << "\tnone found"; } ret = newRet; return ret; } void JoystickSDL::_loadGameControllerMappings(void) { QFile file(":/db/mapping/joystick/gamecontrollerdb.txt"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Couldn't load GameController mapping database."; return; } QTextStream s(&file); while (!s.atEnd()) { SDL_GameControllerAddMapping(s.readLine().toStdString().c_str()); } } bool JoystickSDL::_open(void) { if ( _isGameController ) { sdlController = SDL_GameControllerOpen(_index); sdlJoystick = SDL_GameControllerGetJoystick(sdlController); } else { sdlJoystick = SDL_JoystickOpen(_index); } if (!sdlJoystick) { qCWarning(JoystickLog) << "SDL_JoystickOpen failed:" << SDL_GetError(); return false; } qCDebug(JoystickLog) << "Opened joystick at" << sdlJoystick; return true; } void JoystickSDL::_close(void) { if (sdlJoystick == nullptr) { qCDebug(JoystickLog) << "Attempt to close null joystick!"; return; } qCDebug(JoystickLog) << "Closing" << SDL_JoystickName(sdlJoystick) << "at" << sdlJoystick; // We get a segfault if we try to close a joystick that has been detached if (SDL_JoystickGetAttached(sdlJoystick) == SDL_FALSE) { qCDebug(JoystickLog) << "\tJoystick is not attached!"; } else { if (SDL_JoystickInstanceID(sdlJoystick) != -1) { qCDebug(JoystickLog) << "\tID:" << SDL_JoystickInstanceID(sdlJoystick); // This segfaults so often, and I've spent so much time trying to find the cause and fix it // I think this might be an SDL bug // We are much more stable just commenting this out //SDL_JoystickClose(sdlJoystick); } } sdlJoystick = nullptr; sdlController = nullptr; } bool JoystickSDL::_update(void) { SDL_JoystickUpdate(); SDL_GameControllerUpdate(); return true; } bool JoystickSDL::_getButton(int i) { if (_isGameController) { return SDL_GameControllerGetButton(sdlController, SDL_GameControllerButton(i)) == 1; } else { return SDL_JoystickGetButton(sdlJoystick, i) == 1; } } int JoystickSDL::_getAxis(int i) { if (_isGameController) { return SDL_GameControllerGetAxis(sdlController, SDL_GameControllerAxis(i)); } else { return SDL_JoystickGetAxis(sdlJoystick, i); } } bool JoystickSDL::_getHat(int hat, int i) { uint8_t hatButtons[] = {SDL_HAT_UP,SDL_HAT_DOWN,SDL_HAT_LEFT,SDL_HAT_RIGHT}; if (i < int(sizeof(hatButtons))) { return (SDL_JoystickGetHat(sdlJoystick, hat) & hatButtons[i]) != 0; } return false; }