Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Joystick: Convert Manager from Tool To Singleton #11974

Merged
merged 1 commit into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ if(ANDROID)
endif()
endif()

set(QT_SILENCE_MISSING_DEPENDENCY_TARGET_WARNING ON)

find_package(Qt6
REQUIRED
COMPONENTS
Expand Down
2 changes: 1 addition & 1 deletion src/API/QGCCorePlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ QQmlApplicationEngine* QGCCorePlugin::createQmlApplicationEngine(QObject* parent
{ "eventMonitor", QVariant::fromValue(&eventMonitor) }
}); */
qmlEngine->addImportPath("qrc:/qml");
qmlEngine->rootContext()->setContextProperty("joystickManager", qgcApp()->toolbox()->joystickManager());
qmlEngine->rootContext()->setContextProperty("joystickManager", JoystickManager::instance());
qmlEngine->rootContext()->setContextProperty("debugMessageModel", AppMessages::getModel());
return qmlEngine;
}
Expand Down
5 changes: 2 additions & 3 deletions src/Camera/QGCCameraManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ void QGCCameraManager::_vehicleReady(bool ready)
if(ready) {
if(qgcApp()->toolbox()->multiVehicleManager()->activeVehicle() == _vehicle) {
_vehicleReadyState = true;
JoystickManager *pJoyMgr = qgcApp()->toolbox()->joystickManager();
_activeJoystickChanged(pJoyMgr->activeJoystick());
connect(pJoyMgr, &JoystickManager::activeJoystickChanged, this, &QGCCameraManager::_activeJoystickChanged);
_activeJoystickChanged(JoystickManager::instance()->activeJoystick());
connect(JoystickManager::instance(), &JoystickManager::activeJoystickChanged, this, &QGCCameraManager::_activeJoystickChanged);
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/Joystick/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ qt_add_resources(Joystick "gamecontrollerdb.txt"
FILES ${sdl_gamecontrollerdb_SOURCE_DIR}/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)

if(NOT QGC_BUILD_DEPENDENCIES)
Expand Down
1 change: 1 addition & 0 deletions src/Joystick/Joystick.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "FirmwarePlugin.h"
#include "QGCLoggingCategory.h"
#include "GimbalController.h"
#include "QmlObjectListModel.h"

#include <QtCore/QSettings>

Expand Down
6 changes: 6 additions & 0 deletions src/Joystick/Joystick.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QLoggingCategory>
#include <QtQmlIntegration/QtQmlIntegration>

// JoystickLog Category declaration moved to QGCLoggingCategory.cc to allow access in Vehicle
Q_DECLARE_LOGGING_CATEGORY(JoystickValuesLog)
Q_DECLARE_METATYPE(GRIPPER_ACTIONS)

class MultiVehicleManager;
class Vehicle;
class QmlObjectListModel;

/// Action assigned to button
class AssignedButtonAction : public QObject {
Expand Down Expand Up @@ -54,6 +56,10 @@ class AssignableButtonAction : public QObject {
class Joystick : public QThread
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_MOC_INCLUDE("QmlObjectListModel.h")
Q_MOC_INCLUDE("Vehicle.h")
public:
Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager);

Expand Down
12 changes: 3 additions & 9 deletions src/Joystick/JoystickAndroid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,8 @@ bool JoystickAndroid::_getHat(int hat,int i) {
}
}

static JoystickManager *_manager = nullptr;

//helper method
bool JoystickAndroid::init(JoystickManager *manager) {
_manager = manager;

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

Expand Down Expand Up @@ -296,10 +292,8 @@ static void jniUpdateAvailableJoysticks(JNIEnv *envA, jobject thizA)
Q_UNUSED(envA);
Q_UNUSED(thizA);

if (_manager != nullptr) {
qCDebug(JoystickLog) << "jniUpdateAvailableJoysticks triggered";
emit _manager->updateAvailableJoysticksSignal();
}
qCDebug(JoystickLog) << "jniUpdateAvailableJoysticks triggered";
emit JoystickManager::instance()->updateAvailableJoysticksSignal();
}

void JoystickAndroid::setNativeMethods()
Expand Down
4 changes: 1 addition & 3 deletions src/Joystick/JoystickAndroid.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,14 @@
#include <QtCore/private/qandroidextras_p.h>

class MultiVehicleManager;
class JoystickManager;

class JoystickAndroid : public Joystick, public QtAndroidPrivate::GenericMotionEventListener, public QtAndroidPrivate::KeyEventListener
{
public:
JoystickAndroid(const QString& name, int axisCount, int buttonCount, int id, MultiVehicleManager* multiVehicleManager);

~JoystickAndroid();

static bool init(JoystickManager *manager);
static bool init();

static void setNativeMethods();

Expand Down
127 changes: 57 additions & 70 deletions src/Joystick/JoystickManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,80 +7,82 @@
*
****************************************************************************/


#include "JoystickManager.h"
#include "MultiVehicleManager.h"
#include "Joystick.h"
#if defined(QGC_SDL_JOYSTICK)
#include "JoystickSDL.h"
#elif defined(Q_OS_ANDROID)
#include "JoystickAndroid.h"
#endif
#include "QGCApplication.h"
#include "MultiVehicleManager.h"
#include "QGCLoggingCategory.h"

#include <QtCore/qapplicationstatic.h>
#include <QtCore/QSettings>
#include <QtCore/QTimer>
#include <QtQml/QQmlEngine>
#include <QtQml/QtQml>

QGC_LOGGING_CATEGORY(JoystickManagerLog, "JoystickManagerLog")
QGC_LOGGING_CATEGORY(JoystickManagerLog, "qgc.joystick.joystickmanager")

JoystickManager::JoystickManager(QGCApplication* app, QGCToolbox* toolbox)
: QGCTool(app, toolbox)
, _activeJoystick(nullptr)
, _multiVehicleManager(nullptr)
Q_APPLICATION_STATIC(JoystickManager, _joystickManager);

JoystickManager::JoystickManager(QObject *parent)
: QObject(parent)
, _joystickCheckTimer(new QTimer(this))
{
// qCDebug(JoystickManagerLog) << Q_FUNC_INFO << this;

_joystickCheckTimer->setInterval(1000);
_joystickCheckTimer->setSingleShot(false);
}

JoystickManager::~JoystickManager()
{
QMap<QString, Joystick*>::iterator i;
for (i = _name2JoystickMap.begin(); i != _name2JoystickMap.end(); ++i) {
qCDebug(JoystickManagerLog) << "Releasing joystick:" << i.key();
i.value()->stop();
delete i.value();
for (QMap<QString, Joystick*>::key_value_iterator it = _name2JoystickMap.keyValueBegin(); it != _name2JoystickMap.keyValueEnd(); ++it) {
qCDebug(JoystickManagerLog) << "Releasing joystick:" << it->first;
it->second->stop();
delete it->second;
}

// qCDebug(JoystickManagerLog) << Q_FUNC_INFO << this;
}

void JoystickManager::setToolbox(QGCToolbox *toolbox)
JoystickManager *JoystickManager::instance()
{
QGCTool::setToolbox(toolbox);

_multiVehicleManager = _toolbox->multiVehicleManager();

QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qmlRegisterUncreatableType<JoystickManager>("QGroundControl.JoystickManager", 1, 0, "JoystickManager", "Reference only");
qmlRegisterUncreatableType<Joystick> ("QGroundControl.JoystickManager", 1, 0, "Joystick", "Reference only");
return _joystickManager();
}

void JoystickManager::init() {
void JoystickManager::init()
{
#ifdef QGC_SDL_JOYSTICK
if (!JoystickSDL::init()) {
return;
}
_setActiveJoystickFromSettings();
#elif defined(Q_OS_ANDROID)
if (!JoystickAndroid::init(this)) {
if (!JoystickAndroid::init()) {
return;
}
connect(this, &JoystickManager::updateAvailableJoysticksSignal, this, &JoystickManager::restartJoystickCheckTimer);
(void) connect(this, &JoystickManager::updateAvailableJoysticksSignal, this, [this]() {
_joystickCheckTimerCounter = 5;
_joystickCheckTimer->start();
});
#endif
connect(&_joystickCheckTimer, &QTimer::timeout, this, &JoystickManager::_updateAvailableJoysticks);
(void) connect(_joystickCheckTimer, &QTimer::timeout, this, &JoystickManager::_updateAvailableJoysticks);
_joystickCheckTimerCounter = 5;
_joystickCheckTimer.start(1000);
_joystickCheckTimer->start();
}

void JoystickManager::_setActiveJoystickFromSettings(void)
void JoystickManager::_setActiveJoystickFromSettings()
{
QMap<QString,Joystick*> newMap;

#ifdef QGC_SDL_JOYSTICK
// Get the latest joystick mapping
newMap = JoystickSDL::discover(_multiVehicleManager);
newMap = JoystickSDL::discover(qgcApp()->toolbox()->multiVehicleManager());
#elif defined(Q_OS_ANDROID)
newMap = JoystickAndroid::discover(_multiVehicleManager);
newMap = JoystickAndroid::discover(qgcApp()->toolbox()->multiVehicleManager());
#endif

if (_activeJoystick && !newMap.contains(_activeJoystick->name())) {
Expand All @@ -90,47 +92,45 @@ void JoystickManager::_setActiveJoystickFromSettings(void)

// Check to see if our current mapping contains any joysticks that are not in the new mapping
// If so, those joysticks have been unplugged, and need to be cleaned up
QMap<QString, Joystick*>::iterator i;
for (i = _name2JoystickMap.begin(); i != _name2JoystickMap.end(); ++i) {
if (!newMap.contains(i.key())) {
qCDebug(JoystickManagerLog) << "Releasing joystick:" << i.key();
i.value()->stopPolling();
i.value()->wait(1000);
i.value()->deleteLater();
for (QMap<QString, Joystick*>::key_value_iterator it = _name2JoystickMap.keyValueBegin(); it != _name2JoystickMap.keyValueEnd(); ++it) {
if (!newMap.contains(it->first)) {
qCDebug(JoystickManagerLog) << "Releasing joystick:" << it->first;
it->second->stopPolling();
it->second->wait(1000);
it->second->deleteLater();
}
}

_name2JoystickMap = newMap;
emit availableJoysticksChanged();

if (!_name2JoystickMap.count()) {
if (_name2JoystickMap.isEmpty()) {
setActiveJoystick(nullptr);
return;
}

QSettings settings;

settings.beginGroup(_settingsGroup);
QString name = settings.value(_settingsKeyActiveJoystick).toString();

QString name = settings.value(_settingsKeyActiveJoystick).toString();
if (name.isEmpty()) {
name = _name2JoystickMap.first()->name();
}

setActiveJoystick(_name2JoystickMap.value(name, _name2JoystickMap.first()));
settings.setValue(_settingsKeyActiveJoystick, _activeJoystick->name());

settings.endGroup();
}

Joystick* JoystickManager::activeJoystick(void)
Joystick *JoystickManager::activeJoystick()
{
return _activeJoystick;
}

void JoystickManager::setActiveJoystick(Joystick* joystick)
void JoystickManager::setActiveJoystick(Joystick *joystick)
{
QSettings settings;

if (joystick != nullptr && !_name2JoystickMap.contains(joystick->name())) {
if (joystick && !_name2JoystickMap.contains(joystick->name())) {
qCWarning(JoystickManagerLog) << "Set active not in map" << joystick->name();
return;
}
Expand All @@ -148,49 +148,42 @@ void JoystickManager::setActiveJoystick(Joystick* joystick)
if (_activeJoystick != nullptr) {
qCDebug(JoystickManagerLog) << "Set active:" << _activeJoystick->name();

QSettings settings;
settings.beginGroup(_settingsGroup);
settings.setValue(_settingsKeyActiveJoystick, _activeJoystick->name());
settings.endGroup();
}

emit activeJoystickChanged(_activeJoystick);
emit activeJoystickNameChanged(_activeJoystick?_activeJoystick->name():"");
emit activeJoystickNameChanged(_activeJoystick ? _activeJoystick->name() : "");
}

QVariantList JoystickManager::joysticks(void)
QVariantList JoystickManager::joysticks()
{
QVariantList list;

for (const QString &name: _name2JoystickMap.keys()) {
list += QVariant::fromValue(_name2JoystickMap[name]);
for (auto it = _name2JoystickMap.constBegin(); it != _name2JoystickMap.constEnd(); ++it) {
list += QVariant::fromValue(it.value());
}

return list;
}

QStringList JoystickManager::joystickNames(void)
{
return _name2JoystickMap.keys();
}

QString JoystickManager::activeJoystickName(void)
QString JoystickManager::activeJoystickName() const
{
return _activeJoystick ? _activeJoystick->name() : QString();
return (_activeJoystick ? _activeJoystick->name() : QString());
}

bool JoystickManager::setActiveJoystickName(const QString& name)
bool JoystickManager::setActiveJoystickName(const QString &name)
{
if (_name2JoystickMap.contains(name)) {
setActiveJoystick(_name2JoystickMap[name]);
return true;
} else {
qCWarning(JoystickManagerLog) << "Set active not in map" << name;
return false;
}

qCWarning(JoystickManagerLog) << "Set active not in map" << name;
return false;
}

/*
* TODO: move this to the right place: JoystickSDL.cc and JoystickAndroid.cc respectively and call through Joystick.cc
*/
void JoystickManager::_updateAvailableJoysticks()
{
#ifdef QGC_SDL_JOYSTICK
Expand All @@ -216,13 +209,7 @@ void JoystickManager::_updateAvailableJoysticks()
_joystickCheckTimerCounter--;
_setActiveJoystickFromSettings();
if (_joystickCheckTimerCounter <= 0) {
_joystickCheckTimer.stop();
_joystickCheckTimer->stop();
}
#endif
}

void JoystickManager::restartJoystickCheckTimer()
{
_joystickCheckTimerCounter = 5;
_joystickCheckTimer.start(1000);
}
Loading
Loading