diff --git a/.gitmodules b/.gitmodules
index e37ef969513..070f66973bf 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -20,5 +20,5 @@
path = libs/qmdnsengine
url = https://github.com/nitroshare/qmdnsengine.git
[submodule "resources/SDL_GameControllerDB"]
- path = resources/SDL_GameControllerDB
+ path = libs/SDL_GameControllerDB
url = https://github.com/mdqinc/SDL_GameControllerDB.git
diff --git a/resources/SDL_GameControllerDB b/libs/SDL_GameControllerDB
similarity index 100%
rename from resources/SDL_GameControllerDB
rename to libs/SDL_GameControllerDB
diff --git a/qgcresources.qrc b/qgcresources.qrc
index 4c545fa8df6..06dfc6bfc2b 100644
--- a/qgcresources.qrc
+++ b/qgcresources.qrc
@@ -100,9 +100,6 @@
resources/calibration/mode2/radioYawLeft.png
resources/calibration/mode2/radioYawRight.png
-
- resources/SDL_GameControllerDB/gamecontrollerdb.txt
-
resources/audio/alert.wav
diff --git a/src/Joystick/CMakeLists.txt b/src/Joystick/CMakeLists.txt
index d77517ee7e4..bdb8d863094 100644
--- a/src/Joystick/CMakeLists.txt
+++ b/src/Joystick/CMakeLists.txt
@@ -40,7 +40,7 @@ target_sources(Joystick
JoystickSDL.h
)
-target_compile_definitions(Joystick PRIVATE QGC_SDL_JOYSTICK)
+target_compile_definitions(Joystick PRIVATE QGC_SDL_JOYSTICK SDL_MAIN_HANDLED)
FetchContent_Declare(SDL_GameControllerDB
GIT_REPOSITORY https://github.com/mdqinc/SDL_GameControllerDB.git
@@ -62,14 +62,10 @@ qt_add_resources(Joystick "gamecontrollerdb.txt"
qt_add_qml_module(Joystick
URI QGroundControl.JoystickManager
VERSION 1.0
- OUTPUT_TARGETS Joystick_targets
IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY}
)
-cmake_print_variables(Joystick_targets)
-
-set(MINIMUM_SDL2_VERSION 2.30.0)
-
+set(MINIMUM_SDL2_VERSION 2.24.0)
if(NOT QGC_BUILD_DEPENDENCIES)
find_package(SDL2 ${MINIMUM_SDL2_VERSION})
if(TARGET SDL2::SDL2)
@@ -93,7 +89,7 @@ message(STATUS "Building JoystickSDL")
include(FetchContent)
FetchContent_Declare(SDL
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
- GIT_TAG release-2.30.7
+ GIT_TAG release-2.30.10
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
diff --git a/src/Joystick/Joystick.cc b/src/Joystick/Joystick.cc
index 7aa744d7d9d..316be685bfe 100644
--- a/src/Joystick/Joystick.cc
+++ b/src/Joystick/Joystick.cc
@@ -23,7 +23,7 @@
#include
#include
-// JoystickLog Category declaration moved to QGCLoggingCategory.cc to allow access in Vehicle
+QGC_LOGGING_CATEGORY(JoystickLog, "Joystick")
QGC_LOGGING_CATEGORY(JoystickValuesLog, "JoystickValuesLog")
int Joystick::_transmitterMode = 2;
@@ -41,8 +41,9 @@ AssignableButtonAction::AssignableButtonAction(QObject* parent, QString action_,
{
}
-Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatCount)
- : _name (name)
+Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, QObject *parent)
+ : QThread(parent)
+ , _name (name)
, _axisCount (axisCount)
, _buttonCount (buttonCount)
, _hatCount (hatCount)
diff --git a/src/Joystick/Joystick.h b/src/Joystick/Joystick.h
index e1665ca2a21..b3937f4b33f 100644
--- a/src/Joystick/Joystick.h
+++ b/src/Joystick/Joystick.h
@@ -22,7 +22,7 @@
#include
#include
-// JoystickLog Category declaration moved to QGCLoggingCategory.cc to allow access in Vehicle
+Q_DECLARE_LOGGING_CATEGORY(JoystickLog)
Q_DECLARE_LOGGING_CATEGORY(JoystickValuesLog)
Q_DECLARE_METATYPE(GRIPPER_ACTIONS)
@@ -62,7 +62,7 @@ class Joystick : public QThread
Q_MOC_INCLUDE("QmlObjectListModel.h")
Q_MOC_INCLUDE("Vehicle.h")
public:
- Joystick(const QString& name, int axisCount, int buttonCount, int hatCount);
+ Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, QObject *parent = nullptr);
virtual ~Joystick();
diff --git a/src/Joystick/JoystickAndroid.cc b/src/Joystick/JoystickAndroid.cc
index 539c90006d6..9797469878c 100644
--- a/src/Joystick/JoystickAndroid.cc
+++ b/src/Joystick/JoystickAndroid.cc
@@ -9,49 +9,39 @@
#include "JoystickAndroid.h"
#include "JoystickManager.h"
+#include "AndroidInterface.h"
#include "QGCLoggingCategory.h"
#include
#include
-int JoystickAndroid::_androidBtnListCount;
-int *JoystickAndroid::_androidBtnList;
-int JoystickAndroid::ACTION_DOWN;
-int JoystickAndroid::ACTION_UP;
-int JoystickAndroid::AXIS_HAT_X;
-int JoystickAndroid::AXIS_HAT_Y;
-QMutex JoystickAndroid::m_mutex;
+QGC_LOGGING_CATEGORY(JoystickAndroidLog, "qgc.joystick.joystickandroid")
-static void clear_jni_exception()
-{
- QJniEnvironment jniEnv;
- if (jniEnv->ExceptionCheck()) {
- jniEnv->ExceptionDescribe();
- jniEnv->ExceptionClear();
- }
-}
+QList JoystickAndroid::_androidBtnList(_androidBtnListCount);
+int JoystickAndroid::ACTION_DOWN = 0;
+int JoystickAndroid::ACTION_UP = 0;
+int JoystickAndroid::AXIS_HAT_X = 0;
+int JoystickAndroid::AXIS_HAT_Y = 0;
+QMutex JoystickAndroid::_mutex;
-JoystickAndroid::JoystickAndroid(const QString& name, int axisCount, int buttonCount, int id)
- : Joystick(name,axisCount,buttonCount,0)
+JoystickAndroid::JoystickAndroid(const QString &name, int axisCount, int buttonCount, int id, QObject *parent)
+ : Joystick(name, axisCount, buttonCount, 0, parent)
, deviceId(id)
{
- int i;
-
+ btnCode.resize(_buttonCount);
+ axisCode.resize(_axisCount);
+ btnValue.resize(_buttonCount);
+ axisValue.resize(_axisCount);
+
QJniEnvironment env;
- QJniObject inputDevice = QJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", id);
-
- //set button mapping (number->code)
- jintArray b = env->NewIntArray(_androidBtnListCount);
- env->SetIntArrayRegion(b,0,_androidBtnListCount,_androidBtnList);
-
- QJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", b);
- jbooleanArray jSupportedButtons = btns.object();
- jboolean* supportedButtons = env->GetBooleanArrayElements(jSupportedButtons, nullptr);
- //create a mapping table (btnCode) that maps button number with button code
- btnValue = new bool[_buttonCount];
- btnCode = new int[_buttonCount];
+ const jintArray btnArr = env->NewIntArray(_androidBtnListCount);
+ env->SetIntArrayRegion(btnArr, 0, _androidBtnListCount, _androidBtnList.constData());
+ const QJniObject inputDevice = QJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", id);
+ const QJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", btnArr);
+ const jbooleanArray jSupportedButtons = btns.object();
+ jboolean *const supportedButtons = env->GetBooleanArrayElements(jSupportedButtons, nullptr);
int c = 0;
- for (i = 0; i < _androidBtnListCount; i++) {
+ for (int i = 0; i < _androidBtnListCount; i++) {
if (supportedButtons[i]) {
btnValue[c] = false;
btnCode[c] = _androidBtnList[i];
@@ -61,14 +51,10 @@ JoystickAndroid::JoystickAndroid(const QString& name, int axisCount, int buttonC
env->ReleaseBooleanArrayElements(jSupportedButtons, supportedButtons, 0);
- // set axis mapping (number->code)
- axisValue = new int[_axisCount];
- axisCode = new int[_axisCount];
- QJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;");
- for (i = 0; i < _axisCount; i++) {
- QJniObject range = rangeListNative.callObjectMethod("get", "(I)Ljava/lang/Object;",i);
+ const QJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;");
+ for (int i = 0; i < _axisCount; i++) {
+ const QJniObject range = rangeListNative.callObjectMethod("get", "(I)Ljava/lang/Object;", i);
axisCode[i] = range.callMethod("getAxis");
- // Don't allow two axis with the same code
for (int j = 0; j < i; j++) {
if (axisCode[i] == axisCode[j]) {
axisCode[i] = -1;
@@ -77,48 +63,44 @@ JoystickAndroid::JoystickAndroid(const QString& name, int axisCount, int buttonC
}
axisValue[i] = 0;
}
+ qCDebug(JoystickAndroidLog) << "axis:" << _axisCount << "buttons:" << _buttonCount;
- qCDebug(JoystickLog) << "axis:" <<_axisCount << "buttons:" <<_buttonCount;
QtAndroidPrivate::registerGenericMotionEventListener(this);
QtAndroidPrivate::registerKeyEventListener(this);
}
-JoystickAndroid::~JoystickAndroid() {
- delete btnCode;
- delete axisCode;
- delete btnValue;
- delete axisValue;
-
+JoystickAndroid::~JoystickAndroid()
+{
QtAndroidPrivate::unregisterGenericMotionEventListener(this);
QtAndroidPrivate::unregisterKeyEventListener(this);
}
-
-QMap JoystickAndroid::discover() {
+QMap JoystickAndroid::discover()
+{
static QMap ret;
- QMutexLocker lock(&m_mutex);
+ QMutexLocker lock(&_mutex);
+
+ const QJniObject object = QJniObject::callStaticObjectMethod("android/view/InputDevice", "getDeviceIds");
+ jintArray jarr = object.object();
QJniEnvironment env;
- QJniObject o = QJniObject::callStaticObjectMethod("android/view/InputDevice", "getDeviceIds");
- jintArray jarr = o.object();
- int sz = env->GetArrayLength(jarr);
- jint *buff = env->GetIntArrayElements(jarr, nullptr);
+ const int len = env->GetArrayLength(jarr);
+ jint *const buff = env->GetIntArrayElements(jarr, nullptr);
- int SOURCE_GAMEPAD = QJniObject::getStaticField("android/view/InputDevice", "SOURCE_GAMEPAD");
- int SOURCE_JOYSTICK = QJniObject::getStaticField("android/view/InputDevice", "SOURCE_JOYSTICK");
+ const int SOURCE_GAMEPAD = QJniObject::getStaticField("android/view/InputDevice", "SOURCE_GAMEPAD");
+ const int SOURCE_JOYSTICK = QJniObject::getStaticField("android/view/InputDevice", "SOURCE_JOYSTICK");
QList names;
+ for (int i = 0; i < len; ++i) {
+ const QJniObject inputDevice = QJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", buff[i]);
+ const int sources = inputDevice.callMethod("getSources", "()I");
+ if (((sources & SOURCE_GAMEPAD) != SOURCE_GAMEPAD) && ((sources & SOURCE_JOYSTICK) != SOURCE_JOYSTICK)) {
+ continue;
+ }
- for (int i = 0; i < sz; ++i) {
- QJniObject inputDevice = QJniObject::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();
+ const QString id = inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString();
+ const QString name = inputDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString();
names.push_back(name);
@@ -126,22 +108,23 @@ QMap JoystickAndroid::discover() {
continue;
}
- // get number of axis
- QJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;");
- int axisCount = rangeListNative.callMethod("size");
+ const QJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;");
+ const int axisCount = rangeListNative.callMethod("size");
- // get number of buttons
- jintArray a = env->NewIntArray(_androidBtnListCount);
- env->SetIntArrayRegion(a,0,_androidBtnListCount,_androidBtnList);
- QJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", a);
- jbooleanArray jSupportedButtons = btns.object();
- jboolean* supportedButtons = env->GetBooleanArrayElements(jSupportedButtons, nullptr);
+ jintArray arr = env->NewIntArray(_androidBtnListCount);
+ env->SetIntArrayRegion(arr, 0, _androidBtnListCount, _androidBtnList.constData());
+ const QJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", arr);
+ const jbooleanArray jSupportedButtons = btns.object();
+ jboolean *const supportedButtons = env->GetBooleanArrayElements(jSupportedButtons, nullptr);
int buttonCount = 0;
- for (int j=0;j<_androidBtnListCount;j++)
- if (supportedButtons[j]) buttonCount++;
+ for (int j = 0; j < _androidBtnListCount; j++) {
+ if (supportedButtons[j]) {
+ buttonCount++;
+ }
+ }
env->ReleaseBooleanArrayElements(jSupportedButtons, supportedButtons, 0);
- qCDebug(JoystickLog) << "\t" << name << "id:" << buff[i] << "axes:" << axisCount << "buttons:" << buttonCount;
+ qCDebug(JoystickAndroidLog) << name << "id:" << buff[i] << "axes:" << axisCount << "buttons:" << buttonCount;
ret[name] = new JoystickAndroid(name, axisCount, buttonCount, buff[i]);
}
@@ -159,104 +142,98 @@ QMap JoystickAndroid::discover() {
return ret;
}
+bool JoystickAndroid::handleKeyEvent(jobject event)
+{
+ QMutexLocker lock(&_mutex);
-bool JoystickAndroid::handleKeyEvent(jobject event) {
QJniObject ev(event);
- QMutexLocker lock(&m_mutex);
const int _deviceId = ev.callMethod("getDeviceId", "()I");
- if (_deviceId!=deviceId) return false;
-
+ if (_deviceId != deviceId) {
+ return false;
+ }
+
const int action = ev.callMethod("getAction", "()I");
const int keyCode = ev.callMethod("getKeyCode", "()I");
- for (int i = 0; i <_buttonCount; i++) {
- if (btnCode[i] == keyCode) {
- if (action == ACTION_DOWN) btnValue[i] = true;
- if (action == ACTION_UP) btnValue[i] = false;
- return true;
+ for (int i = 0; i < _buttonCount; i++) {
+ if (btnCode[i] != keyCode) {
+ continue;
}
+
+ if (action == ACTION_DOWN) {
+ btnValue[i] = true;
+ } else if (action == ACTION_UP) {
+ btnValue[i] = false;
+ }
+
+ return true;
}
+
return false;
}
-bool JoystickAndroid::handleGenericMotionEvent(jobject event) {
+bool JoystickAndroid::handleGenericMotionEvent(jobject event)
+{
+ QMutexLocker lock(&_mutex);
+
QJniObject ev(event);
- QMutexLocker lock(&m_mutex);
const int _deviceId = ev.callMethod("getDeviceId", "()I");
- if (_deviceId!=deviceId) return false;
-
- for (int i = 0; i <_axisCount; i++) {
- const float v = ev.callMethod("getAxisValue", "(I)F",axisCode[i]);
- axisValue[i] = static_cast((v*32767.f));
+ if (_deviceId != deviceId) {
+ return false;
}
- return true;
-}
-bool JoystickAndroid::_open(void) {
- return true;
-}
-
-void JoystickAndroid::_close(void) {
-}
+ for (int i = 0; i < _axisCount; i++) {
+ const float v = ev.callMethod("getAxisValue", "(I)F", axisCode[i]);
+ axisValue[i] = static_cast(v * 32767.f);
+ }
-bool JoystickAndroid::_update(void)
-{
return true;
}
-bool JoystickAndroid::_getButton(int i) {
- return btnValue[ i ];
-}
-
-int JoystickAndroid::_getAxis(int i) {
- return axisValue[ i ];
-}
-
-int JoystickAndroid::_getAndroidHatAxis(int axisHatCode) {
- for(int i = 0; i < _axisCount; i++) {
+int JoystickAndroid::_getAndroidHatAxis(int axisHatCode)
+{
+ for (int i = 0; i < _axisCount; i++) {
if (axisCode[i] == axisHatCode) {
return _getAxis(i);
}
}
+
return 0;
}
-bool JoystickAndroid::_getHat(int hat,int i) {
+bool JoystickAndroid::_getHat(int hat, int i)
+{
// Android supports only one hat button
if (hat != 0) {
return false;
}
switch (i) {
- case 0:
- return _getAndroidHatAxis(AXIS_HAT_Y) < 0;
- case 1:
- return _getAndroidHatAxis(AXIS_HAT_Y) > 0;
- case 2:
- return _getAndroidHatAxis(AXIS_HAT_X) < 0;
- case 3:
- return _getAndroidHatAxis(AXIS_HAT_X) > 0;
- default:
- return false;
+ case 0:
+ return (_getAndroidHatAxis(AXIS_HAT_Y) < 0);
+ case 1:
+ return (_getAndroidHatAxis(AXIS_HAT_Y) > 0);
+ case 2:
+ return (_getAndroidHatAxis(AXIS_HAT_X) < 0);
+ case 3:
+ return (_getAndroidHatAxis(AXIS_HAT_X) > 0);
+ default:
+ return false;
}
}
-//helper method
-bool JoystickAndroid::init() {
- //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
+bool JoystickAndroid::init()
+{
+ static QList ret(_androidBtnListCount);
- //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;
- clear_jni_exception();
+ (void) AndroidInterface::cleanJavaException();
+
+ int i;
for (i = 1; i <= 16; i++) {
- QString name = "KEYCODE_BUTTON_"+QString::number(i);
- ret[i-1] = QJniObject::getStaticField("android/view/KeyEvent", name.toStdString().c_str());
+ const QString name = QStringLiteral("KEYCODE_BUTTON_") + QString::number(i);
+ ret[i - 1] = QJniObject::getStaticField("android/view/KeyEvent", name.toStdString().c_str());
}
i--;
@@ -284,41 +261,41 @@ bool JoystickAndroid::init() {
return true;
}
-static const char kJniClassName[] {"org/mavlink/qgroundcontrol/QGCUsbSerialManager"};
-
static void jniUpdateAvailableJoysticks(JNIEnv *envA, jobject thizA)
{
- Q_UNUSED(envA);
- Q_UNUSED(thizA);
+ Q_UNUSED(envA); Q_UNUSED(thizA);
+
+ qCDebug(JoystickAndroidLog) << "jniUpdateAvailableJoysticks triggered";
- qCDebug(JoystickLog) << "jniUpdateAvailableJoysticks triggered";
emit JoystickManager::instance()->updateAvailableJoysticksSignal();
}
void JoystickAndroid::setNativeMethods()
{
- qCDebug(JoystickLog) << "Registering Native Functions";
+ qCDebug(JoystickAndroidLog) << "Registering Native Functions";
- // REGISTER THE C++ FUNCTION WITH JNI
- JNINativeMethod javaMethods[] {
- {"nativeUpdateAvailableJoysticks", "()V", reinterpret_cast(jniUpdateAvailableJoysticks)}
+ static const JNINativeMethod javaMethods[] {
+ {"nativeUpdateAvailableJoysticks", "()V", reinterpret_cast(jniUpdateAvailableJoysticks)}
};
- clear_jni_exception();
+ static constexpr const char *kJniClassName = "org/mavlink/qgroundcontrol/QGCUsbSerialManager";
+
+ (void) AndroidInterface::cleanJavaException();
+
QJniEnvironment jniEnv;
jclass objectClass = jniEnv->FindClass(kJniClassName);
- if(!objectClass) {
- clear_jni_exception();
- qWarning() << "Couldn't find class:" << kJniClassName;
+ if (!objectClass) {
+ (void) AndroidInterface::cleanJavaException();
+ qCWarning(JoystickAndroidLog) << "Couldn't find class:" << kJniClassName;
return;
}
- jint val = jniEnv->RegisterNatives(objectClass, javaMethods, sizeof(javaMethods) / sizeof(javaMethods[0]));
-
+ const jint val = jniEnv->RegisterNatives(objectClass, javaMethods, std::size(javaMethods));
if (val < 0) {
- qWarning() << "Error registering methods: " << val;
+ qCWarning(JoystickAndroidLog) << "Error registering methods:" << val;
} else {
- qCDebug(JoystickLog) << "Native Functions Registered";
+ qCDebug(JoystickAndroidLog) << "Native Functions Registered";
}
- clear_jni_exception();
+
+ (void) AndroidInterface::cleanJavaException();
}
diff --git a/src/Joystick/JoystickAndroid.h b/src/Joystick/JoystickAndroid.h
index 2d5ab491c89..39a4006e2a7 100644
--- a/src/Joystick/JoystickAndroid.h
+++ b/src/Joystick/JoystickAndroid.h
@@ -9,44 +9,47 @@
#pragma once
-#include "Joystick.h"
+#include
#include
+#include "Joystick.h"
+
+Q_DECLARE_LOGGING_CATEGORY(JoystickAndroidLog)
+
class JoystickAndroid : public Joystick, public QtAndroidPrivate::GenericMotionEventListener, public QtAndroidPrivate::KeyEventListener
{
public:
- JoystickAndroid(const QString& name, int axisCount, int buttonCount, int id);
+ JoystickAndroid(const QString &name, int axisCount, int buttonCount, int id, QObject *parent = nullptr);
~JoystickAndroid();
static bool init();
-
static void setNativeMethods();
-
static QMap discover();
private:
+ bool _open() final { return true; }
+ void _close() final {}
+ bool _update() final { return true; }
+
+ bool _getButton(int i) final { return btnValue[i]; }
+ int _getAxis(int i) final { return axisValue[i]; }
+ bool _getHat(int hat, int i) final;
+
+ int _getAndroidHatAxis(int axisHatCode);
+
bool handleKeyEvent(jobject event);
bool handleGenericMotionEvent(jobject event);
- int _getAndroidHatAxis(int axisHatCode);
- virtual bool _open ();
- virtual void _close ();
- virtual bool _update ();
+ int deviceId = 0;
- virtual bool _getButton (int i);
- virtual int _getAxis (int i);
- virtual bool _getHat (int hat,int i);
+ QList btnCode;
+ QList axisCode;
+ QList btnValue;
+ QList axisValue;
- int *btnCode;
- int *axisCode;
- bool *btnValue;
- int *axisValue;
-
- static int * _androidBtnList; //list of all possible android buttons
- static int _androidBtnListCount;
+ static constexpr int _androidBtnListCount = 31;
+ static QList _androidBtnList;
static int ACTION_DOWN, ACTION_UP, AXIS_HAT_X, AXIS_HAT_Y;
- static QMutex m_mutex;
-
- int deviceId;
+ static QMutex _mutex;
};
diff --git a/src/Joystick/JoystickManager.cc b/src/Joystick/JoystickManager.cc
index a003c1d69e1..fd00d7caf83 100644
--- a/src/Joystick/JoystickManager.cc
+++ b/src/Joystick/JoystickManager.cc
@@ -11,10 +11,10 @@
#include "Joystick.h"
#if defined(QGC_SDL_JOYSTICK)
#include "JoystickSDL.h"
+ #include
#elif defined(Q_OS_ANDROID)
#include "JoystickAndroid.h"
#endif
-#include "MultiVehicleManager.h"
#include "QGCLoggingCategory.h"
#include
@@ -33,7 +33,7 @@ JoystickManager::JoystickManager(QObject *parent)
{
// qCDebug(JoystickManagerLog) << Q_FUNC_INFO << this;
- _joystickCheckTimer->setInterval(1000);
+ _joystickCheckTimer->setInterval(kTimerInterval);
_joystickCheckTimer->setSingleShot(false);
}
@@ -69,6 +69,7 @@ void JoystickManager::init()
_joystickCheckTimer->start();
});
#endif
+
(void) connect(_joystickCheckTimer, &QTimer::timeout, this, &JoystickManager::_updateAvailableJoysticks);
_joystickCheckTimerCounter = 5;
_joystickCheckTimer->start();
@@ -76,7 +77,7 @@ void JoystickManager::init()
void JoystickManager::_setActiveJoystickFromSettings()
{
- QMap newMap;
+ QMap newMap;
#ifdef QGC_SDL_JOYSTICK
newMap = JoystickSDL::discover();
@@ -95,7 +96,7 @@ void JoystickManager::_setActiveJoystickFromSettings()
if (!newMap.contains(it->first)) {
qCDebug(JoystickManagerLog) << "Releasing joystick:" << it->first;
it->second->stopPolling();
- it->second->wait(1000);
+ (void) it->second->wait(kTimeout);
it->second->deleteLater();
}
}
@@ -144,7 +145,7 @@ void JoystickManager::setActiveJoystick(Joystick *joystick)
_activeJoystick = joystick;
- if (_activeJoystick != nullptr) {
+ if (_activeJoystick) {
qCDebug(JoystickManagerLog) << "Set active:" << _activeJoystick->name();
QSettings settings;
@@ -192,10 +193,12 @@ void JoystickManager::_updateAvailableJoysticks()
case SDL_QUIT:
qCDebug(JoystickManagerLog) << "SDL ERROR:" << SDL_GetError();
break;
+ case SDL_CONTROLLERDEVICEADDED:
case SDL_JOYDEVICEADDED:
qCDebug(JoystickManagerLog) << "Joystick added:" << event.jdevice.which;
_setActiveJoystickFromSettings();
break;
+ case SDL_CONTROLLERDEVICEREMOVED:
case SDL_JOYDEVICEREMOVED:
qCDebug(JoystickManagerLog) << "Joystick removed:" << event.jdevice.which;
_setActiveJoystickFromSettings();
diff --git a/src/Joystick/JoystickManager.h b/src/Joystick/JoystickManager.h
index b549c5d0df4..46bd25e6319 100644
--- a/src/Joystick/JoystickManager.h
+++ b/src/Joystick/JoystickManager.h
@@ -17,7 +17,6 @@
Q_DECLARE_LOGGING_CATEGORY(JoystickManagerLog)
class Joystick;
-class MultiVehicleManager;
class QTimer;
class JoystickManager : public QObject
@@ -68,6 +67,8 @@ private slots:
int _joystickCheckTimerCounter = 0;;
QTimer *_joystickCheckTimer = nullptr;
+ static constexpr int kTimerInterval = 1000;
+ static constexpr int kTimeout = 1000;
static constexpr const char *_settingsGroup = "JoystickManager";
static constexpr const char *_settingsKeyActiveJoystick = "ActiveJoystick";
};
diff --git a/src/Joystick/JoystickSDL.cc b/src/Joystick/JoystickSDL.cc
index 8c2632a7517..d8bdadd366a 100644
--- a/src/Joystick/JoystickSDL.cc
+++ b/src/Joystick/JoystickSDL.cc
@@ -8,184 +8,208 @@
****************************************************************************/
#include "JoystickSDL.h"
-#include "MultiVehicleManager.h"
#include "QGCLoggingCategory.h"
-#include
#include
#include
+#include
+
+#include
+
+QGC_LOGGING_CATEGORY(JoystickSDLLog, "qgc.joystick.joysticksdl")
-JoystickSDL::JoystickSDL(const QString& name, int axisCount, int buttonCount, int hatCount, int index, bool isGameController)
- : Joystick(name,axisCount,buttonCount,hatCount)
+JoystickSDL::JoystickSDL(const QString &name, int axisCount, int buttonCount, int hatCount, int index, bool isGameController, QObject *parent)
+ : Joystick(name, axisCount, buttonCount, hatCount, parent)
, _isGameController(isGameController)
, _index(index)
{
- // qCDebug(JoystickLog) << Q_FUNC_INFO << this;
+ // qCDebug(JoystickSDLLog) << Q_FUNC_INFO << this;
- if(_isGameController) _setDefaultCalibration();
+ if (_isGameController) {
+ _setDefaultCalibration();
+ }
}
JoystickSDL::~JoystickSDL()
{
- // qCDebug(JoystickLog) << Q_FUNC_INFO << this;
+ // qCDebug(JoystickSDLLog) << Q_FUNC_INFO << this;
}
-bool JoystickSDL::init(void) {
+bool JoystickSDL::init()
+{
SDL_SetMainReady();
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK) < 0) {
- SDL_JoystickEventState(SDL_DISABLE);
- qCWarning(JoystickLog) << "Couldn't initialize SimpleDirectMediaLayer:" << SDL_GetError();
+ (void) SDL_JoystickEventState(SDL_DISABLE);
+ qCWarning(JoystickSDLLog) << "Failed to initialize SDL:" << SDL_GetError();
return false;
}
+
_loadGameControllerMappings();
return true;
}
-QMap JoystickSDL::discover() {
+QMap JoystickSDL::discover()
+{
static QMap ret;
- QMap newRet;
+ QMap newRet;
- // Load available joysticks
+ qCDebug(JoystickSDLLog) << "Discovering 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
+ JoystickSDL *const joystick = static_cast(newRet[name]);
+ if (joystick->index() != i) {
+ joystick->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;
+ (void) ret.remove(name);
+
+ qCDebug(JoystickSDLLog) << "Skipping duplicate" << name;
+ continue;
}
- }
- if (!newRet.count()) {
- qCDebug(JoystickLog) << "\tnone found";
- }
+ SDL_Joystick *const sdlJoystick = SDL_JoystickOpen(i);
+ if (!sdlJoystick) {
+ qCWarning(JoystickSDLLog) << "SDL failed opening joystick" << qPrintable(name) << "error:" << SDL_GetError();
+ continue;
+ }
- ret = newRet;
- return ret;
-}
+ SDL_ClearError();
+ const int axisCount = SDL_JoystickNumAxes(sdlJoystick);
+ const int buttonCount = SDL_JoystickNumButtons(sdlJoystick);
+ const int hatCount = SDL_JoystickNumHats(sdlJoystick);
+ if ((axisCount < 0) || (buttonCount < 0) || (hatCount < 0)) {
+ qCWarning(JoystickSDLLog) << "SDL error parsing joystick features:" << SDL_GetError();
+ }
+ SDL_JoystickClose(sdlJoystick);
-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;
- }
+ const bool isGameController = SDL_IsGameController(i);
+ qCDebug(JoystickSDLLog) << name << "axes:" << axisCount << "buttons:" << buttonCount << "hats:" << hatCount << "isGC:" << isGameController;
+
+ // Check for joysticks with duplicate names and differentiate the keys when necessary.
+ // This is required when using an Xbox 360 wireless receiver that always identifies as
+ // 4 individual joysticks, regardless of how many joysticks are actually connected to the
+ // receiver. Using GUID does not help, all of these devices present the same GUID.
+ const QString originalName = name;
+ uint8_t duplicateIdx = 1;
+ while (newRet[name]) {
+ name = QString("%1 %2").arg(originalName).arg(duplicateIdx++);
+ }
- QTextStream s(&file);
+ newRet[name] = new JoystickSDL(name, qMax(0, axisCount), qMax(0, buttonCount), qMax(0, hatCount), i, isGameController);
+ }
- while (!s.atEnd()) {
- SDL_GameControllerAddMapping(s.readLine().toStdString().c_str());
+ if (newRet.isEmpty()) {
+ qCDebug(JoystickSDLLog) << "None found";
}
+
+ ret = newRet;
+ return ret;
}
-bool JoystickSDL::_open(void) {
- if ( _isGameController ) {
- sdlController = SDL_GameControllerOpen(_index);
- sdlJoystick = SDL_GameControllerGetJoystick(sdlController);
+bool JoystickSDL::_open()
+{
+ if (_isGameController) {
+ _sdlController = SDL_GameControllerOpen(_index);
+ _sdlJoystick = SDL_GameControllerGetJoystick(_sdlController);
} else {
- sdlJoystick = SDL_JoystickOpen(_index);
+ _sdlJoystick = SDL_JoystickOpen(_index);
}
- if (!sdlJoystick) {
- qCWarning(JoystickLog) << "SDL_JoystickOpen failed:" << SDL_GetError();
+ if (!_sdlJoystick) {
+ qCWarning(JoystickSDLLog) << "SDL_JoystickOpen failed:" << SDL_GetError();
return false;
}
- qCDebug(JoystickLog) << "Opened joystick at" << sdlJoystick;
+ qCDebug(JoystickSDLLog) << "Opened" << SDL_JoystickName(_sdlJoystick) << "joystick at" << _sdlJoystick;
return true;
}
-void JoystickSDL::_close(void) {
- if (sdlJoystick == nullptr) {
- qCDebug(JoystickLog) << "Attempt to close null joystick!";
+void JoystickSDL::_close()
+{
+ if (!_sdlJoystick) {
+ qCWarning(JoystickSDLLog) << "Attempt to close null joystick!";
return;
}
- qCDebug(JoystickLog) << "Closing" << SDL_JoystickName(sdlJoystick) << "at" << sdlJoystick;
+ qCDebug(JoystickSDLLog) << "Closing" << SDL_JoystickName(_sdlJoystick) << "joystick at" << _sdlJoystick;
if (_isGameController) {
- SDL_GameControllerClose(sdlController);
+ SDL_GameControllerClose(_sdlController);
} else {
- SDL_JoystickClose(sdlJoystick);
+ SDL_JoystickClose(_sdlJoystick);
}
- sdlJoystick = nullptr;
- sdlController = nullptr;
+ _sdlJoystick = nullptr;
+ _sdlController = nullptr;
}
-bool JoystickSDL::_update(void)
+bool JoystickSDL::_update()
{
if (_isGameController) {
SDL_GameControllerUpdate();
} else {
SDL_JoystickUpdate();
}
+
return true;
}
-bool JoystickSDL::_getButton(int i) {
+bool JoystickSDL::_getButton(int i)
+{
+ int button = -1;
+
if (_isGameController) {
- return SDL_GameControllerGetButton(sdlController, SDL_GameControllerButton(i)) == 1;
+ button = SDL_GameControllerGetButton(_sdlController, SDL_GameControllerButton(i));
} else {
- return SDL_JoystickGetButton(sdlJoystick, i) == 1;
+ button = SDL_JoystickGetButton(_sdlJoystick, i);
}
+
+ return (button == 1);
}
-int JoystickSDL::_getAxis(int i) {
+int JoystickSDL::_getAxis(int i)
+{
+ int axis = -1;
+
if (_isGameController) {
- return SDL_GameControllerGetAxis(sdlController, SDL_GameControllerAxis(i));
+ axis = SDL_GameControllerGetAxis(_sdlController, SDL_GameControllerAxis(i));
} else {
- return SDL_JoystickGetAxis(sdlJoystick, i);
+ axis = SDL_JoystickGetAxis(_sdlJoystick, i);
+ }
+
+ return axis;
+}
+
+bool JoystickSDL::_getHat(int hat, int i)
+{
+ static constexpr uint8_t hatButtons[] = {SDL_HAT_UP, SDL_HAT_DOWN, SDL_HAT_LEFT, SDL_HAT_RIGHT};
+
+ if (i >= std::size(hatButtons)) {
+ return false;
}
+
+ return ((SDL_JoystickGetHat(_sdlJoystick, hat) & hatButtons[i]) != 0);
}
-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;
+void JoystickSDL::_loadGameControllerMappings()
+{
+ QFile file(QStringLiteral(":/db/mapping/joystick/gamecontrollerdb.txt"));
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qCWarning(JoystickSDLLog) << "Couldn't load GameController mapping database.";
+ return;
+ }
+
+ QTextStream stream(&file);
+ while (!stream.atEnd()) {
+ if (SDL_GameControllerAddMapping(stream.readLine().toStdString().c_str()) == -1) {
+ qCWarning(JoystickSDLLog) << "Couldn't add GameController mapping:" << SDL_GetError();
+ }
}
- return false;
}
diff --git a/src/Joystick/JoystickSDL.h b/src/Joystick/JoystickSDL.h
index de400a615bb..b1a662898a9 100644
--- a/src/Joystick/JoystickSDL.h
+++ b/src/Joystick/JoystickSDL.h
@@ -7,50 +7,48 @@
*
****************************************************************************/
-/// @file
-/// @brief SDL Joystick Interface
-
#pragma once
+#include
+
#include "Joystick.h"
-#define SDL_MAIN_HANDLED
+struct _SDL_Joystick;
+typedef struct _SDL_Joystick SDL_Joystick;
-#include
+struct _SDL_GameController;
+typedef struct _SDL_GameController SDL_GameController;
-class MultiVehicleManager;
+Q_DECLARE_LOGGING_CATEGORY(JoystickSDLLog)
-/// @brief SDL Joystick Interface
class JoystickSDL : public Joystick
{
public:
- JoystickSDL(const QString& name, int axisCount, int buttonCount, int hatCount, int index, bool isGameController);
+ JoystickSDL(const QString &name, int axisCount, int buttonCount, int hatCount, int index, bool isGameController, QObject *parent = nullptr);
~JoystickSDL();
- static QMap discover();
- static bool init(void);
-
- int index(void) const { return _index; }
+ int index() const { return _index; }
void setIndex(int index) { _index = index; }
- // This can be uncommented to hide the calibration buttons for gamecontrollers in the future
- // bool requiresCalibration(void) final { return !_isGameController; }
+ // bool requiresCalibration() final { return !_isGameController; }
-private:
- static void _loadGameControllerMappings();
+ static bool init();
+ static QMap discover();
- bool _open () final;
- void _close () final;
- bool _update () final;
+private:
+ bool _open() final;
+ void _close() final;
+ bool _update() final;
- bool _getButton (int i) final;
- int _getAxis (int i) final;
- bool _getHat (int hat,int i) final;
+ bool _getButton(int i) final;
+ int _getAxis(int i) final;
+ bool _getHat(int hat, int i) final;
- SDL_Joystick* sdlJoystick;
- SDL_GameController* sdlController;
+ static void _loadGameControllerMappings();
- bool _isGameController;
- int _index; ///< Index for SDL_JoystickOpen
+ bool _isGameController = false;
+ int _index = -1;
+ SDL_Joystick *_sdlJoystick = nullptr;
+ SDL_GameController *_sdlController = nullptr;
};
diff --git a/src/Utilities/QGCLoggingCategory.cc b/src/Utilities/QGCLoggingCategory.cc
index ec3580dc76e..23132b0fd0e 100644
--- a/src/Utilities/QGCLoggingCategory.cc
+++ b/src/Utilities/QGCLoggingCategory.cc
@@ -26,8 +26,6 @@ QGC_LOGGING_CATEGORY(ParameterManagerLog, "ParameterManagerLog")
QGC_LOGGING_CATEGORY(GuidedActionsControllerLog, "GuidedActionsControllerLog")
QGC_LOGGING_CATEGORY(LocalizationLog, "LocalizationLog")
QGC_LOGGING_CATEGORY(VideoAllLog, kVideoAllLogCategory)
-QGC_LOGGING_CATEGORY(JoystickLog, "JoystickLog")
-
QGCLoggingCategoryRegister* _instance = nullptr;
diff --git a/src/Utilities/QGCLoggingCategory.h b/src/Utilities/QGCLoggingCategory.h
index bd22a3f3426..63aeab845b1 100644
--- a/src/Utilities/QGCLoggingCategory.h
+++ b/src/Utilities/QGCLoggingCategory.h
@@ -22,7 +22,6 @@ Q_DECLARE_LOGGING_CATEGORY(ParameterManagerLog)
Q_DECLARE_LOGGING_CATEGORY(GuidedActionsControllerLog)
Q_DECLARE_LOGGING_CATEGORY(LocalizationLog)
Q_DECLARE_LOGGING_CATEGORY(VideoAllLog) // turns on all individual QGC video logs
-Q_DECLARE_LOGGING_CATEGORY(JoystickLog)
/// @def QGC_LOGGING_CATEGORY
/// This is a QGC specific replacement for Q_LOGGING_CATEGORY. It will register the category name into a