diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 8dbedee403b7e57c34ce4f9b0034d60dba2e8621..c312b105bb3fd1827239043d2ac4d7b61db27808 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -312,6 +312,11 @@ HEADERS += \ src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.h \ src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h \ +AndroidBuild { +HEADERS += \ + src/Joystick/JoystickAndroid.h \ +} + DebugBuild { HEADERS += \ src/comm/MockLink.h \ @@ -344,6 +349,7 @@ HEADERS += \ src/comm/QGCHilLink.h \ src/comm/QGCJSBSimLink.h \ src/comm/QGCXPlaneLink.h \ + src/Joystick/JoystickSDL.h \ src/QGCFileDialog.h \ src/QGCMessageBox.h \ src/uas/FileManager.h \ @@ -400,8 +406,10 @@ iOSBuild { src/audio/QGCAudioWorker_iOS.mm \ src/MobileScreenMgr.mm \ } + AndroidBuild { SOURCES += src/MobileScreenMgr.cc \ + src/Joystick/JoystickAndroid.cc \ } @@ -497,6 +505,7 @@ SOURCES += \ src/comm/QGCFlightGearLink.cc \ src/comm/QGCJSBSimLink.cc \ src/comm/QGCXPlaneLink.cc \ + src/Joystick/JoystickSDL.cc \ src/ui/HILDockWidget.cc \ src/ui/linechart/ChartPlot.cc \ src/ui/linechart/IncrementalPlot.cc \ diff --git a/src/Joystick/Joystick.cc b/src/Joystick/Joystick.cc index f499e8366c4d5b6b686b4c18506904ea2bedece9..0e1abea405def84e1a2291b1f685a45618d8af15 100644 --- a/src/Joystick/Joystick.cc +++ b/src/Joystick/Joystick.cc @@ -28,15 +28,6 @@ #include -#ifndef __mobile__ - #define __sdljoystick__ - #ifdef Q_OS_MAC - #include - #else - #include - #endif -#endif - QGC_LOGGING_CATEGORY(JoystickLog, "JoystickLog") QGC_LOGGING_CATEGORY(JoystickValuesLog, "JoystickValuesLog") @@ -52,9 +43,8 @@ const char* Joystick::_rgFunctionSettingsKey[Joystick::maxFunction] = { "ThrottleAxis" }; -Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int sdlIndex, MultiVehicleManager* multiVehicleManager) - : _sdlIndex(sdlIndex) - , _exitThread(false) +Joystick::Joystick(const QString& name, int axisCount, int buttonCount, MultiVehicleManager* multiVehicleManager) + : _exitThread(false) , _name(name) , _axisCount(axisCount) , _buttonCount(buttonCount) @@ -94,6 +84,110 @@ Joystick::~Joystick() delete _rgButtonActions; } +void Joystick::run(void) +{ + open(); + + while (!_exitThread) { + update(); + + // Update axes + for (int axisIndex=0; axisIndex<_axisCount; axisIndex++) { + int newAxisValue = getAxis(axisIndex); + // Calibration code requires signal to be emitted even if value hasn't changed + _rgAxisValues[axisIndex] = newAxisValue; + emit rawAxisValueChanged(axisIndex, newAxisValue); + } + + // Update buttons + for (int buttonIndex=0; buttonIndex<_buttonCount; buttonIndex++) { + bool newButtonValue = getButton(buttonIndex); + if (newButtonValue != _rgButtonValues[buttonIndex]) { + _rgButtonValues[buttonIndex] = newButtonValue; + emit rawButtonPressedChanged(buttonIndex, newButtonValue); + } + } + + if (_calibrationMode != CalibrationModeCalibrating) { + int axis = _rgFunctionAxis[rollFunction]; + float roll = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]); + + axis = _rgFunctionAxis[pitchFunction]; + float pitch = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]); + + axis = _rgFunctionAxis[yawFunction]; + float yaw = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]); + + axis = _rgFunctionAxis[throttleFunction]; + float throttle = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]); + + float roll_limited = std::max(static_cast(-M_PI_4), std::min(roll, static_cast(M_PI_4))); + float pitch_limited = std::max(static_cast(-M_PI_4), std::min(pitch, static_cast(M_PI_4))); + float yaw_limited = std::max(static_cast(-M_PI_4), std::min(yaw, static_cast(M_PI_4))); + float throttle_limited = std::max(static_cast(-M_PI_4), std::min(throttle, static_cast(M_PI_4))); + + // Map from unit circle to linear range and limit + roll = std::max(-1.0f, std::min(tanf(asinf(roll_limited)), 1.0f)); + pitch = std::max(-1.0f, std::min(tanf(asinf(pitch_limited)), 1.0f)); + yaw = std::max(-1.0f, std::min(tanf(asinf(yaw_limited)), 1.0f)); + throttle = std::max(-1.0f, std::min(tanf(asinf(throttle_limited)), 1.0f)); + + // Adjust throttle to 0:1 range + if (_throttleMode == ThrottleModeCenterZero) { + throttle = std::max(0.0f, throttle); + } else { + throttle = (throttle + 1.0f) / 2.0f; + } + + // Set up button pressed information + + // We only send the buttons the firmwware has reserved + int reservedButtonCount = _activeVehicle->manualControlReservedButtonCount(); + if (reservedButtonCount == -1) { + reservedButtonCount = _buttonCount; + } + + quint16 newButtonBits = 0; // New set of button which are down + quint16 buttonPressedBits = 0; // Buttons pressed for manualControl signal + + for (int buttonIndex=0; buttonIndex<_buttonCount; buttonIndex++) { + quint16 buttonBit = 1 << buttonIndex; + + if (!_rgButtonValues[buttonIndex]) { + // Button up, just record it + newButtonBits |= buttonBit; + } else { + if (_lastButtonBits & buttonBit) { + // Button was up last time through, but is now down which indicates a button press + qCDebug(JoystickLog) << "button triggered" << buttonIndex; + + if (buttonIndex >= reservedButtonCount) { + // Button is above firmware reserved set + QString buttonAction =_rgButtonActions[buttonIndex]; + if (!buttonAction.isEmpty()) { + _buttonAction(buttonAction); + } + } + } + + // Mark the button as pressed as long as its pressed + buttonPressedBits |= buttonBit; + } + } + + _lastButtonBits = newButtonBits; + + //qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle" << name() << roll << -pitch << yaw << throttle; + + emit manualControl(roll, -pitch, yaw, throttle, buttonPressedBits, _activeVehicle->joystickMode()); + } + + // Sleep, update rate of joystick is approx. 25 Hz (1000 ms / 25 = 40 ms) + QGC::SLEEP::msleep(40); + } + + close(); +} void Joystick::_loadSettings(void) { @@ -245,117 +339,6 @@ float Joystick::_adjustRange(int value, Calibration_t calibration) } -void Joystick::run(void) -{ -#ifdef __sdljoystick__ - SDL_Joystick* sdlJoystick = SDL_JoystickOpen(_sdlIndex); - - if (!sdlJoystick) { - qCWarning(JoystickLog) << "SDL_JoystickOpen failed:" << SDL_GetError(); - return; - } - - while (!_exitThread) { - SDL_JoystickUpdate(); - - // Update axes - for (int axisIndex=0; axisIndex<_axisCount; axisIndex++) { - int newAxisValue = SDL_JoystickGetAxis(sdlJoystick, axisIndex); - // Calibration code requires signal to be emitted even if value hasn't changed - _rgAxisValues[axisIndex] = newAxisValue; - emit rawAxisValueChanged(axisIndex, newAxisValue); - } - - // Update buttons - for (int buttonIndex=0; buttonIndex<_buttonCount; buttonIndex++) { - bool newButtonValue = !!SDL_JoystickGetButton(sdlJoystick, buttonIndex); - if (newButtonValue != _rgButtonValues[buttonIndex]) { - _rgButtonValues[buttonIndex] = newButtonValue; - emit rawButtonPressedChanged(buttonIndex, newButtonValue); - } - } - - if (_calibrationMode != CalibrationModeCalibrating) { - int axis = _rgFunctionAxis[rollFunction]; - float roll = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]); - - axis = _rgFunctionAxis[pitchFunction]; - float pitch = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]); - - axis = _rgFunctionAxis[yawFunction]; - float yaw = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]); - - axis = _rgFunctionAxis[throttleFunction]; - float throttle = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]); - - float roll_limited = std::max(static_cast(-M_PI_4), std::min(roll, static_cast(M_PI_4))); - float pitch_limited = std::max(static_cast(-M_PI_4), std::min(pitch, static_cast(M_PI_4))); - float yaw_limited = std::max(static_cast(-M_PI_4), std::min(yaw, static_cast(M_PI_4))); - float throttle_limited = std::max(static_cast(-M_PI_4), std::min(throttle, static_cast(M_PI_4))); - - // Map from unit circle to linear range and limit - roll = std::max(-1.0f, std::min(tanf(asinf(roll_limited)), 1.0f)); - pitch = std::max(-1.0f, std::min(tanf(asinf(pitch_limited)), 1.0f)); - yaw = std::max(-1.0f, std::min(tanf(asinf(yaw_limited)), 1.0f)); - throttle = std::max(-1.0f, std::min(tanf(asinf(throttle_limited)), 1.0f)); - - // Adjust throttle to 0:1 range - if (_throttleMode == ThrottleModeCenterZero) { - throttle = std::max(0.0f, throttle); - } else { - throttle = (throttle + 1.0f) / 2.0f; - } - - // Set up button pressed information - - // We only send the buttons the firmwware has reserved - int reservedButtonCount = _activeVehicle->manualControlReservedButtonCount(); - if (reservedButtonCount == -1) { - reservedButtonCount = _buttonCount; - } - - quint16 newButtonBits = 0; // New set of button which are down - quint16 buttonPressedBits = 0; // Buttons pressed for manualControl signal - - for (int buttonIndex=0; buttonIndex<_buttonCount; buttonIndex++) { - quint16 buttonBit = 1 << buttonIndex; - - if (!_rgButtonValues[buttonIndex]) { - // Button up, just record it - newButtonBits |= buttonBit; - } else { - if (_lastButtonBits & buttonBit) { - // Button was up last time through, but is now down which indicates a button press - qCDebug(JoystickLog) << "button triggered" << buttonIndex; - - if (buttonIndex >= reservedButtonCount) { - // Button is above firmware reserved set - QString buttonAction =_rgButtonActions[buttonIndex]; - if (!buttonAction.isEmpty()) { - _buttonAction(buttonAction); - } - } - } - - // Mark the button as pressed as long as its pressed - buttonPressedBits |= buttonBit; - } - } - - _lastButtonBits = newButtonBits; - - qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle" << name() << roll << -pitch << yaw << throttle; - - emit manualControl(roll, -pitch, yaw, throttle, buttonPressedBits, _activeVehicle->joystickMode()); - } - - // Sleep, update rate of joystick is approx. 25 Hz (1000 ms / 25 = 40 ms) - QGC::SLEEP::msleep(40); - } - - SDL_JoystickClose(sdlJoystick); -#endif -} void Joystick::startPolling(Vehicle* vehicle) { diff --git a/src/Joystick/Joystick.h b/src/Joystick/Joystick.h index 6eb2d405796081cbf5e711879de3a6f0dcbedc01..389a737fd151a7ddb341e4471e0dad67342cf3c7 100644 --- a/src/Joystick/Joystick.h +++ b/src/Joystick/Joystick.h @@ -39,9 +39,9 @@ class Joystick : public QThread Q_OBJECT public: - Joystick(const QString& name, int axisCount, int buttonCount, int sdlIndex, MultiVehicleManager* multiVehicleManager); + Joystick(const QString& name, int axisCount, int buttonCount, MultiVehicleManager* multiVehicleManager); ~Joystick(); - + typedef struct { int min; int max; @@ -136,7 +136,7 @@ signals: void buttonActionTriggered(int action); -private: +protected: void _saveSettings(void); void _loadSettings(void); float _adjustRange(int value, Calibration_t calibration); @@ -144,11 +144,18 @@ private: bool _validAxis(int axis); bool _validButton(int button); +private: + virtual bool open() = 0; + virtual void close() = 0; + virtual bool update() = 0; + + virtual bool getButton(int i) = 0; + virtual int getAxis(int i) = 0; + // Override from QThread virtual void run(void); -private: - int _sdlIndex; ///< Index for SDL_JoystickOpen +protected: bool _exitThread; ///< true: signal thread to exit diff --git a/src/Joystick/JoystickAndroid.cc b/src/Joystick/JoystickAndroid.cc new file mode 100644 index 0000000000000000000000000000000000000000..3de7ce4ca6567c67840dff44d886f3b49b7a7ed3 --- /dev/null +++ b/src/Joystick/JoystickAndroid.cc @@ -0,0 +1,199 @@ +#include "JoystickAndroid.h" + +#include "QGCApplication.h" + +#include + +int JoystickAndroid::_androidBtnListCount; +int *JoystickAndroid::_androidBtnList; +QMutex JoystickAndroid::m_mutex; + +JoystickAndroid::JoystickAndroid(const QString& name, int id, MultiVehicleManager* multiVehicleManager) + : Joystick(name,0,0,multiVehicleManager) //buttonCount and axisCount is computed below + , deviceId(id) +{ + int i; + + QAndroidJniEnvironment env; + + QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", id); + + //get number of buttons + jintArray a = env->NewIntArray(_androidBtnListCount); + env->SetIntArrayRegion(a,0,_androidBtnListCount,_androidBtnList); + + QAndroidJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", a); + jbooleanArray jSupportedButtons = btns.object(); + int btn_sz = env->GetArrayLength(jSupportedButtons); + jboolean* supportedButtons = env->GetBooleanArrayElements(jSupportedButtons, nullptr); + _buttonCount=0; + for (i=0;iReleaseBooleanArrayElements(jSupportedButtons, supportedButtons, 0); + + //get number of axis + QAndroidJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;"); + _axisCount = rangeListNative.callMethod("size"); + axisValue = new int[_axisCount]; + axisCode = new int[_axisCount]; + for (i=0;i<_axisCount;i++) { + QAndroidJniObject range = rangeListNative.callObjectMethod("get", "()Landroid/view/InputDevice/MotionRange;"); + if (range.isValid()) + axisCode[i] = range.callMethod("getAxis"); + axisValue[i] = 0; + } + + qDebug() << "joystick constructor:" << _name; + + QtAndroidPrivate::registerGenericMotionEventListener(this); + QtAndroidPrivate::registerKeyEventListener(this); +} + +JoystickAndroid::~JoystickAndroid() { + qDebug() << "joystick destructor" << _name; + + delete btnCode; + delete axisCode; + delete btnValue; + delete axisValue; + + QtAndroidPrivate::unregisterGenericMotionEventListener(this); + QtAndroidPrivate::unregisterKeyEventListener(this); +} + +bool JoystickAndroid::handleKeyEvent(jobject event) { + QJNIObjectPrivate ev(event); + QMutexLocker lock(&m_mutex); + const int _deviceId = ev.callMethod("getDeviceId", "()I"); + if (_deviceId!=deviceId) return false; + + qDebug() << "handleKeyEvent!" << deviceId; + return true; +} + +bool JoystickAndroid::handleGenericMotionEvent(jobject event) { + QJNIObjectPrivate ev(event); + QMutexLocker lock(&m_mutex); + const int _deviceId = ev.callMethod("getDeviceId", "()I"); + if (_deviceId!=deviceId) return false; + + qDebug() << "handleMotionEvent!" << deviceId; + return true; +} + +QMap JoystickAndroid::discover(MultiVehicleManager* _multiVehicleManager) { + bool joystickFound = false; + static QMap ret; + + _buttonList(); //it's enough to run it once, should be in a static constructor + + QMutexLocker lock(&m_mutex); + + QAndroidJniEnvironment env; + QAndroidJniObject o = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDeviceIds"); + jintArray jarr = o.object(); + size_t sz = env->GetArrayLength(jarr); + jint *buff = env->GetIntArrayElements(jarr, nullptr); + + int SOURCE_GAMEPAD = QAndroidJniObject::getStaticField("android/view/InputDevice", "SOURCE_GAMEPAD"); + int SOURCE_JOYSTICK = QAndroidJniObject::getStaticField("android/view/InputDevice", "SOURCE_JOYSTICK"); + + for (size_t i = 0; i < sz; ++i) { + QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", buff[i]); + int sources = inputDevice.callMethod("getSources", "()I"); + if (((sources & SOURCE_GAMEPAD) != SOURCE_GAMEPAD) //check if the input device is interesting to us + && ((sources & SOURCE_JOYSTICK) != SOURCE_JOYSTICK)) continue; + + //get id and name + QString id = inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString(); + QString name = inputDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString(); + + + if (joystickFound) { //skipping { + qWarning() << "Skipping joystick:" << name; + continue; + } + + qDebug() << "\t" << name << "id:" << buff[i]; + ret[name] = new JoystickAndroid(name, buff[i], _multiVehicleManager); + joystickFound = true; + } + + env->ReleaseIntArrayElements(jarr, buff, 0); + + + return ret; +} + +bool JoystickAndroid::open(void) { + return true; +} + +void JoystickAndroid::close(void) { +} + +bool JoystickAndroid::update(void) +{ + return true; +} + +bool JoystickAndroid::getButton(int i) { + return btnValue[ btnCode[i] ]; +} + +int JoystickAndroid::getAxis(int i) { + return axisValue[ axisCode[i] ]; +} + + +//helper method +void JoystickAndroid::_buttonList() { + //this gets list of all possible buttons - this is needed to check how many buttons our gamepad supports + //instead of the whole logic below we could have just a simple array of hardcoded int values as these 'should' not change + + //int JoystickAndroid::_androidBtnListCount; + _androidBtnListCount = 31; + static int ret[31]; //there are 31 buttons in total accordingy to the API + int i; + //int *JoystickAndroid:: + _androidBtnList = ret; + + for (i=1;i<=16;i++) { + QString name = "KEYCODE_BUTTON_"+QString::number(i); + ret[i-1] = QAndroidJniObject::getStaticField("android/view/KeyEvent", name.toStdString().c_str()); + } + i--; + + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_A"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_B"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_C"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_L1"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_L2"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_R1"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_R2"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_MODE"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_SELECT"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_START"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_THUMBL"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_THUMBR"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_X"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_Y"); + ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_Z"); + + for (int j=0;j<_androidBtnListCount;j++) + qDebug() << "\tpossible button: "+QString::number(_androidBtnList[j]); + +} + diff --git a/src/Joystick/JoystickAndroid.h b/src/Joystick/JoystickAndroid.h new file mode 100644 index 0000000000000000000000000000000000000000..48f83ec294e8a4fe5057a02198a50decf008c5f3 --- /dev/null +++ b/src/Joystick/JoystickAndroid.h @@ -0,0 +1,48 @@ +#ifndef JOYSTICKANDROID_H +#define JOYSTICKANDROID_H + +#include "Joystick.h" +#include "Vehicle.h" +#include "MultiVehicleManager.h" + +#include +#include +#include +#include +#include + + +class JoystickAndroid : public Joystick, public QtAndroidPrivate::GenericMotionEventListener, public QtAndroidPrivate::KeyEventListener +{ +public: + JoystickAndroid(const QString& name, int id, MultiVehicleManager* multiVehicleManager); + ~JoystickAndroid(); + + static QMap discover(MultiVehicleManager* _multiVehicleManager); + +private: + bool handleKeyEvent(jobject event); + bool handleGenericMotionEvent(jobject event); + + virtual bool open(); + virtual void close(); + virtual bool update(); + + virtual bool getButton(int i); + virtual int getAxis(int i); + + int *btnCode; + int *axisCode; + bool *btnValue; + int *axisValue; + + static void _buttonList(); + static int * _androidBtnList; //list of all possible android buttons + static int _androidBtnListCount; + + static QMutex m_mutex; + + int deviceId; +}; + +#endif // JOYSTICKANDROID_H diff --git a/src/Joystick/JoystickManager.cc b/src/Joystick/JoystickManager.cc index 96c83e303125b6018ec5a94a37ad4b39cc3d07e7..3828c303a435454e33db6dd0e007ba52dfcbd43b 100644 --- a/src/Joystick/JoystickManager.cc +++ b/src/Joystick/JoystickManager.cc @@ -27,12 +27,12 @@ #include #ifndef __mobile__ + #include "JoystickSDL.h" #define __sdljoystick__ - #ifdef Q_OS_MAC - #include - #else - #include - #endif +#endif + +#ifdef __android__ + #include "JoystickAndroid.h" #endif QGC_LOGGING_CATEGORY(JoystickManagerLog, "JoystickManagerLog") @@ -45,7 +45,15 @@ JoystickManager::JoystickManager(QGCApplication* app) , _activeJoystick(NULL) , _multiVehicleManager(NULL) { - +} + +JoystickManager::~JoystickManager() { + QMap::iterator i; + for (i = _name2JoystickMap.begin(); i != _name2JoystickMap.end(); ++i) { + qDebug() << "Releasing joystick:" << i.key(); + delete i.value(); + } + qDebug() << "Done"; } void JoystickManager::setToolbox(QGCToolbox *toolbox) @@ -57,82 +65,9 @@ void JoystickManager::setToolbox(QGCToolbox *toolbox) QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); #ifdef __sdljoystick__ - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) < 0) { - qWarning() << "Couldn't initialize SimpleDirectMediaLayer:" << SDL_GetError(); - return; - } - - // Load available joysticks - - qCDebug(JoystickManagerLog) << "Available joysticks"; - - for (int i=0; i("android/view/InputDevice", "getDeviceIds"); - jintArray jarr = o.object(); - size_t sz = env->GetArrayLength(jarr); - jint *buff = env->GetIntArrayElements(jarr, nullptr); - - int SOURCE_GAMEPAD = QAndroidJniObject::getStaticField("android/view/InputDevice", "SOURCE_GAMEPAD"); - int SOURCE_JOYSTICK = QAndroidJniObject::getStaticField("android/view/InputDevice", "SOURCE_JOYSTICK"); - - for (size_t i = 0; i < sz; ++i) { - int axisCount, buttonCount; - QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", buff[i]); - int sources = inputDevice.callMethod("getSources", "()I"); - if (((sources & SOURCE_GAMEPAD) != SOURCE_GAMEPAD) //check if the input device is interesting to us - && ((sources & SOURCE_JOYSTICK) != SOURCE_JOYSTICK)) continue; - - //get id and name - QString id = inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString(); - QString name = inputDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString(); - - //get number of buttons - jintArray a = env->NewIntArray(31); - env->SetIntArrayRegion(a,0,31,_possibleButtons); - - //QAndroidJniObject keyMap = inputDevice.callObjectMethod("getKeyCharacterMap", "()Landroid/view/KeyCharacterMap;"); - //QAndroidJniObject btns = keyMap.callStaticObjectMethod("android/view/KeyCharacterMap","deviceHasKeys", "([I)[Z", a); - QAndroidJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", a); - jbooleanArray jSupportedButtons = btns.object(); - size_t btn_sz = env->GetArrayLength(jSupportedButtons); - jboolean* supportedButtons = env->GetBooleanArrayElements(jSupportedButtons, nullptr); - buttonCount=0; - for (size_t j=0;jReleaseBooleanArrayElements(jSupportedButtons, supportedButtons, 0); - - //get number of axis - QAndroidJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;"); - axisCount = rangeListNative.callMethod("size"); - - qCDebug(JoystickManagerLog) << "\t" << name << "axes:" << axisCount << "buttons:" << buttonCount; - _name2JoystickMap[name] = new Joystick(name, axisCount, buttonCount, buff[i], _multiVehicleManager); - } - - env->ReleaseIntArrayElements(jarr, buff, 0); + _name2JoystickMap = JoystickAndroid::discover(_multiVehicleManager); #endif if (!_name2JoystickMap.count()) { @@ -143,38 +78,6 @@ void JoystickManager::setToolbox(QGCToolbox *toolbox) _setActiveJoystickFromSettings(); } -void JoystickManager::computePossibleButtons() { - static int ret[31]; - int i; - - for (i=1;i<=16;i++) { - QString name = "KEYCODE_BUTTON_"+QString::number(i); - ret[i-1] = QAndroidJniObject::getStaticField("android/view/KeyEvent", name.toStdString().c_str()); - } - i--; - - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_A"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_B"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_C"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_L1"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_L2"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_R1"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_R2"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_MODE"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_SELECT"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_START"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_THUMBL"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_THUMBR"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_X"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_Y"); - ret[i++] = QAndroidJniObject::getStaticField("android/view/KeyEvent", "KEYCODE_BUTTON_Z"); - - for (int j=0;j -#ifdef __android__ - #include - #include - #include - #include - #include -#endif - Q_DECLARE_LOGGING_CATEGORY(JoystickManagerLog) class QGCApplicaiton; @@ -49,6 +41,7 @@ class JoystickManager : public QGCTool public: JoystickManager(QGCApplication* app); + ~JoystickManager(); /// List of available joysticks Q_PROPERTY(QVariantList joysticks READ joysticks CONSTANT) @@ -86,12 +79,6 @@ private: static const char * _settingsGroup; static const char * _settingsKeyActiveJoystick; - -#ifdef __android__ - void computePossibleButtons(); - int * _possibleButtons; - QMutex m_mutex; -#endif }; #endif diff --git a/src/Joystick/JoystickSDL.cc b/src/Joystick/JoystickSDL.cc new file mode 100644 index 0000000000000000000000000000000000000000..db90c113bb8507635a9b79a547456b1d5081eee0 --- /dev/null +++ b/src/Joystick/JoystickSDL.cc @@ -0,0 +1,73 @@ +#include "JoystickSDL.h" + +#include "QGCApplication.h" + +#include + +JoystickSDL::JoystickSDL(const QString& name, int axisCount, int buttonCount, int index, MultiVehicleManager* multiVehicleManager) + : Joystick(name,axisCount,buttonCount,multiVehicleManager) + , _index(index) +{ +} + +QMap JoystickSDL::discover(MultiVehicleManager* _multiVehicleManager) { + static QMap ret; + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) < 0) { + qWarning() << "Couldn't initialize SimpleDirectMediaLayer:" << SDL_GetError(); + return ret; + } + + // Load available joysticks + + qCDebug(JoystickLog) << "Available joysticks"; + + for (int i=0; i +#else + #include +#endif + + +class JoystickSDL : public Joystick +{ +public: + JoystickSDL(const QString& name, int axisCount, int buttonCount, int index, MultiVehicleManager* multiVehicleManager); + + static QMap discover(MultiVehicleManager* _multiVehicleManager); + +private: + virtual bool open(); + virtual void close(); + virtual bool update(); + + virtual bool getButton(int i); + virtual int getAxis(int i); + + SDL_Joystick *sdlJoystick; + int _index; ///< Index for SDL_JoystickOpen +}; + +#endif // JOYSTICKSDL_H