From 9cc5d6487ead4daaf651b608fc383bbe751ec70e Mon Sep 17 00:00:00 2001 From: Bryant Date: Mon, 10 Jun 2013 15:47:42 -0700 Subject: [PATCH] The Joystick Settings window now supports selecting between multiple joysticks for control input and updates its UI accordingly. Much work is left to be done: light/dark styling, settings management, control mappings. --- src/input/JoystickInput.cc | 60 ++++--- src/input/JoystickInput.h | 39 ++++- src/ui/JoystickWidget.cc | 168 +++++++++++--------- src/ui/JoystickWidget.h | 10 +- src/ui/JoystickWidget.ui | 309 ++++++++----------------------------- 5 files changed, 246 insertions(+), 340 deletions(-) diff --git a/src/input/JoystickInput.cc b/src/input/JoystickInput.cc index 074e3c1a7..6c54c70a0 100644 --- a/src/input/JoystickInput.cc +++ b/src/input/JoystickInput.cc @@ -38,7 +38,9 @@ JoystickInput::JoystickInput() : autoButtonMapping(-1), manualButtonMapping(-1), stabilizeButtonMapping(-1), - joystickName(tr("Unitinialized")) + joystickName(tr("Unitinialized")), + joystickButtons(0), + joystickID(0) { loadSettings(); @@ -47,10 +49,11 @@ JoystickInput::JoystickInput() : calibrationNegative[i] = sdlJoystickMin; } + // Listen for when the active UAS changes so we can change who we're sending data to. connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); - // Enter main loop - //start(); + // Start this thread. This allows the Joystick Settings window to work correctly even w/o any UASes connected. + start(); } JoystickInput::~JoystickInput() @@ -108,14 +111,13 @@ void JoystickInput::setActiveUAS(UASInterface* uas) this->uas = uas; - tmp = dynamic_cast(this->uas); - if(tmp) { - connect(this, SIGNAL(joystickChanged(double,double,double,double,int,int,int)), tmp, SLOT(setManualControlCommands(double,double,double,double,int,int,int))); - connect(this, SIGNAL(buttonPressed(int)), tmp, SLOT(receiveButton(int))); - } - if (!isRunning()) + if (this->uas) { - start(); + tmp = dynamic_cast(this->uas); + if(tmp) { + connect(this, SIGNAL(joystickChanged(double,double,double,double,int,int,int)), tmp, SLOT(setManualControlCommands(double,double,double,double,int,int,int))); + connect(this, SIGNAL(buttonPressed(int)), tmp, SLOT(receiveButton(int))); + } } } @@ -127,10 +129,10 @@ void JoystickInput::init() } // Enumerate joysticks and select one - int numJoysticks = SDL_NumJoysticks(); + joysticksFound = SDL_NumJoysticks(); - // Wait for joysticks if none is connected - while (numJoysticks == 0 && !done) + // Wait for joysticks if none are connected + while (joysticksFound == 0 && !done) { QGC::SLEEP::msleep(400); // INITIALIZE SDL Joystick support @@ -138,29 +140,33 @@ void JoystickInput::init() { printf("Couldn't initialize SimpleDirectMediaLayer: %s\n", SDL_GetError()); } - numJoysticks = SDL_NumJoysticks(); + joysticksFound = SDL_NumJoysticks(); } if (done) { return; } - printf("%d Input devices found:\n", numJoysticks); - for(int i=0; i < SDL_NumJoysticks(); i++ ) + qDebug() << QString("%1 Input devices found:").arg(joysticksFound); + for(int i=0; i < joysticksFound; i++ ) { - printf("\t- %s\n", SDL_JoystickName(i)); - joystickName = QString(SDL_JoystickName(i)); + qDebug() << QString("\t- %1").arg(SDL_JoystickName(i)); + SDL_Joystick* x = SDL_JoystickOpen(i); + qDebug() << QString("Number of Axes: %1").arg(QString::number(SDL_JoystickNumAxes(x))); + qDebug() << QString("Number of Buttons: %1").arg(QString::number(SDL_JoystickNumButtons(x))); + qDebug() << QString("Number of Balls: %1").arg(QString::number(SDL_JoystickNumBalls(x))); + SDL_JoystickClose(x); } - printf("\nOpened %s\n", SDL_JoystickName(defaultIndex)); - SDL_JoystickEventState(SDL_ENABLE); - joystick = SDL_JoystickOpen(defaultIndex); + // And attach to the default joystick. + setActiveJoystick(defaultIndex); // Make sure active UAS is set setActiveUAS(UASManager::instance()->getActiveUAS()); } + void JoystickInput::shutdown() { done = true; @@ -324,6 +330,18 @@ void JoystickInput::run() } +void JoystickInput::setActiveJoystick(int id) +{ + joystickID = id; + joystick = SDL_JoystickOpen(joystickID); + if (joystick) + { + joystickName = QString(SDL_JoystickName(joystickID)); + joystickButtons = SDL_JoystickNumButtons(joystick); + qDebug() << QString("Switching to joystick '%1' with %2 buttons").arg(joystickName, QString::number(joystickButtons)); + } +} + const QString& JoystickInput::getName() { return joystickName; diff --git a/src/input/JoystickInput.h b/src/input/JoystickInput.h index 6315b55e9..ea5e59de2 100644 --- a/src/input/JoystickInput.h +++ b/src/input/JoystickInput.h @@ -69,41 +69,61 @@ public: */ void storeSettings(); - int getMappingThrustAxis() + int getMappingThrustAxis() const { return thrustAxis; } - int getMappingXAxis() + int getMappingXAxis() const { return xAxis; } - int getMappingYAxis() + int getMappingYAxis() const { return yAxis; } - int getMappingYawAxis() + int getMappingYawAxis() const { return yawAxis; } - int getMappingAutoButton() + int getMappingAutoButton() const { return autoButtonMapping; } - int getMappingManualButton() + int getMappingManualButton() const { return manualButtonMapping; } - int getMappingStabilizeButton() + int getMappingStabilizeButton() const { return stabilizeButtonMapping; } + int getJoystickNumButtons() const + { + return joystickButtons; + } + + int getJoystickID() const + { + return joystickID; + } + + int getNumJoysticks() const + { + return joysticksFound; + } + + QString getJoystickNameById(int id) const + { + return QString(SDL_JoystickName(id)); + } + const double sdlJoystickMin; const double sdlJoystickMax; @@ -127,6 +147,9 @@ protected: int stabilizeButtonMapping; SDL_Event event; QString joystickName; + int joystickButtons; + int joystickID; + int joysticksFound; void init(); @@ -198,6 +221,8 @@ signals: public slots: void setActiveUAS(UASInterface* uas); + /** @brief Switch to a new joystick by ID number. */ + void setActiveJoystick(int id); void setMappingThrustAxis(int mapping) { thrustAxis = mapping; diff --git a/src/ui/JoystickWidget.cc b/src/ui/JoystickWidget.cc index 1fb49e249..e0a180214 100644 --- a/src/ui/JoystickWidget.cc +++ b/src/ui/JoystickWidget.cc @@ -5,6 +5,7 @@ JoystickWidget::JoystickWidget(JoystickInput* joystick, QWidget *parent) : QDialog(parent), + joystick(joystick), m_ui(new Ui::JoystickWidget) { m_ui->setupUi(this); @@ -14,30 +15,50 @@ JoystickWidget::JoystickWidget(JoystickInput* joystick, QWidget *parent) : position.moveCenter(QDesktopWidget().availableGeometry().center()); move(position.topLeft()); - clearKeys(); - this->joystick = joystick; - - m_ui->rollMapSpinBox->setValue(joystick->getMappingXAxis()); - m_ui->pitchMapSpinBox->setValue(joystick->getMappingYAxis()); - m_ui->yawMapSpinBox->setValue(joystick->getMappingYawAxis()); - m_ui->throttleMapSpinBox->setValue(joystick->getMappingThrustAxis()); - m_ui->autoMapSpinBox->setValue(joystick->getMappingAutoButton()); + // Initialize the UI based on the current joystick + initUI(); + // Watch for input events from the joystick connect(this->joystick, SIGNAL(joystickChanged(double,double,double,double,int,int,int)), this, SLOT(updateJoystick(double,double,double,double,int,int))); connect(this->joystick, SIGNAL(buttonPressed(int)), this, SLOT(pressKey(int))); + + // Watch for changes to the button/axis mappings connect(m_ui->rollMapSpinBox, SIGNAL(valueChanged(int)), this->joystick, SLOT(setMappingXAxis(int))); connect(m_ui->pitchMapSpinBox, SIGNAL(valueChanged(int)), this->joystick, SLOT(setMappingYAxis(int))); connect(m_ui->yawMapSpinBox, SIGNAL(valueChanged(int)), this->joystick, SLOT(setMappingYawAxis(int))); connect(m_ui->throttleMapSpinBox, SIGNAL(valueChanged(int)), this->joystick, SLOT(setMappingThrustAxis(int))); connect(m_ui->autoMapSpinBox, SIGNAL(valueChanged(int)), this->joystick, SLOT(setMappingAutoButton(int))); - // Display the widget - this->window()->setWindowTitle(tr("Joystick Settings")); - if (joystick) updateStatus(tr("Found joystick: %1").arg(joystick->getName())); + // Update the UI if the joystick changes. + connect(m_ui->joystickNameComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUIForJoystick(int))); + // Display the widget above all other windows. + this->raise(); this->show(); } +void JoystickWidget::initUI() +{ + // Add the joysticks to the top combobox. They're indexed by their item number. + // And set the currently-selected combobox item to the current joystick. + int joysticks = joystick->getNumJoysticks(); + if (joysticks) + { + for (int i = 0; i < joysticks; i++) + { + m_ui->joystickNameComboBox->addItem(joystick->getJoystickNameById(i)); + } + m_ui->joystickNameComboBox->setCurrentIndex(joystick->getJoystickID()); + } + else + { + m_ui->joystickNameComboBox->addItem(tr("No joysticks found. Connect and restart QGC to add one.")); + } + + // Add any missing buttons + updateUIForJoystick(joystick->getJoystickID()); +} + JoystickWidget::~JoystickWidget() { delete m_ui; @@ -63,6 +84,35 @@ void JoystickWidget::changeEvent(QEvent *e) } } +void JoystickWidget::updateUIForJoystick(int id) +{ + // Delete all the old buttonlabels + foreach (QLabel* l, m_ui->buttonLabelBox->findChildren()) + { + delete l; + } + + // Set the JoystickInput to listen to the new joystick instead. + joystick->setActiveJoystick(id); + + // And add new ones for every new button found. + for (int i = 0; i < joystick->getJoystickNumButtons(); i++) + { + QLabel* buttonLabel = new QLabel(m_ui->buttonLabelBox); + buttonLabel->setText(QString::number(i)); + buttonLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + buttonLabel->setAlignment(Qt::AlignCenter); + // And make sure we insert BEFORE the vertical spacer. + m_ui->buttonLabelLayout->insertWidget(i, buttonLabel); + } + + // Update the mapping UI + m_ui->rollMapSpinBox->setValue(joystick->getMappingXAxis()); + m_ui->pitchMapSpinBox->setValue(joystick->getMappingYAxis()); + m_ui->yawMapSpinBox->setValue(joystick->getMappingYawAxis()); + m_ui->throttleMapSpinBox->setValue(joystick->getMappingThrustAxis()); + m_ui->autoMapSpinBox->setValue(joystick->getMappingAutoButton()); +} void JoystickWidget::setThrottle(float thrust) { @@ -91,66 +141,46 @@ void JoystickWidget::setHat(float x, float y) updateStatus(tr("Hat position: x: %1, y: %2").arg(x).arg(y)); } -void JoystickWidget::clearKeys() -{ - QString colorstyle; - QColor buttonStyleColor = QColor(200, 20, 20); - colorstyle = QString("QLabel { border: 1px solid #EEEEEE; border-radius: 4px; padding: 0px; margin: 0px; background-color: %1;}").arg(buttonStyleColor.name()); - - m_ui->button0->setStyleSheet(colorstyle); - m_ui->button1->setStyleSheet(colorstyle); - m_ui->button2->setStyleSheet(colorstyle); - m_ui->button3->setStyleSheet(colorstyle); - m_ui->button4->setStyleSheet(colorstyle); - m_ui->button5->setStyleSheet(colorstyle); - m_ui->button6->setStyleSheet(colorstyle); - m_ui->button7->setStyleSheet(colorstyle); - m_ui->button8->setStyleSheet(colorstyle); - m_ui->button9->setStyleSheet(colorstyle); - m_ui->button10->setStyleSheet(colorstyle); -} - void JoystickWidget::pressKey(int key) { - QString colorstyle; - QColor buttonStyleColor = QColor(20, 200, 20); - colorstyle = QString("QLabel { border: 1px solid #EEEEEE; border-radius: 4px; padding: 0px; margin: 0px; background-color: %1;}").arg(buttonStyleColor.name()); - switch(key) { - case 0: - m_ui->button0->setStyleSheet(colorstyle); - break; - case 1: - m_ui->button1->setStyleSheet(colorstyle); - break; - case 2: - m_ui->button2->setStyleSheet(colorstyle); - break; - case 3: - m_ui->button3->setStyleSheet(colorstyle); - break; - case 4: - m_ui->button4->setStyleSheet(colorstyle); - break; - case 5: - m_ui->button5->setStyleSheet(colorstyle); - break; - case 6: - m_ui->button6->setStyleSheet(colorstyle); - break; - case 7: - m_ui->button7->setStyleSheet(colorstyle); - break; - case 8: - m_ui->button8->setStyleSheet(colorstyle); - break; - case 9: - m_ui->button9->setStyleSheet(colorstyle); - break; - case 10: - m_ui->button10->setStyleSheet(colorstyle); - break; - } - QTimer::singleShot(20, this, SLOT(clearKeys())); +// QString colorstyle; +// QColor buttonStyleColor = QColor(20, 200, 20); +// colorstyle = QString("QLabel { border: 1px solid #EEEEEE; border-radius: 4px; padding: 0px; margin: 0px; background-color: %1;}").arg(buttonStyleColor.name()); +// switch(key) { +// case 0: +// m_ui->button0->setStyleSheet(colorstyle); +// break; +// case 1: +// m_ui->button1->setStyleSheet(colorstyle); +// break; +// case 2: +// m_ui->button2->setStyleSheet(colorstyle); +// break; +// case 3: +// m_ui->button3->setStyleSheet(colorstyle); +// break; +// case 4: +// m_ui->button4->setStyleSheet(colorstyle); +// break; +// case 5: +// m_ui->button5->setStyleSheet(colorstyle); +// break; +// case 6: +// m_ui->button6->setStyleSheet(colorstyle); +// break; +// case 7: +// m_ui->button7->setStyleSheet(colorstyle); +// break; +// case 8: +// m_ui->button8->setStyleSheet(colorstyle); +// break; +// case 9: +// m_ui->button9->setStyleSheet(colorstyle); +// break; +// case 10: +// m_ui->button10->setStyleSheet(colorstyle); +// break; +// } updateStatus(tr("Key %1 pressed").arg(key)); } diff --git a/src/ui/JoystickWidget.h b/src/ui/JoystickWidget.h index b6c47c628..cf29745ac 100644 --- a/src/ui/JoystickWidget.h +++ b/src/ui/JoystickWidget.h @@ -69,20 +69,26 @@ public slots: void setZ(float z); /** @brief Hat switch position */ void setHat(float x, float y); - /** @brief Clear keys */ - void clearKeys(); /** @brief Joystick keys, as labeled on the joystick */ void pressKey(int key); /** @brief Update status string */ void updateStatus(const QString& status); protected: + /** @brief Update the proper number of buttons for the current joystick. */ + void updateButtons(); /** @brief UI change event */ virtual void changeEvent(QEvent *e); JoystickInput* joystick; ///< Reference to the joystick +protected slots: + /** @brief Update the UI for a new joystick based on SDL ID. */ + void updateUIForJoystick(int id); + private: Ui::JoystickWidget *m_ui; + /** @brief Initialize all dynamic UI elements (button list, joystick names, etc.) */ + void initUI(); }; #endif // JOYSTICKWIDGET_H diff --git a/src/ui/JoystickWidget.ui b/src/ui/JoystickWidget.ui index 5c426fc3b..b499cda04 100644 --- a/src/ui/JoystickWidget.ui +++ b/src/ui/JoystickWidget.ui @@ -17,17 +17,26 @@ - Dialog + Joystick Settings - - + + + 8 + + + 8 + + + 8 + + 8 8 - + 0 @@ -37,7 +46,7 @@ 40 - 400 + 16777215 @@ -49,226 +58,39 @@ false - + 1 - + + 3 + + + 3 + + + 3 + + 3 - - - true - - - - 0 - 0 - - - - 0 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 1 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 2 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 3 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 4 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 5 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 6 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 7 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 8 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 9 - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - 10 + + + Qt::Vertical - - Qt::AlignCenter + + + 20 + 40 + - + - + Mappings @@ -363,7 +185,7 @@ - + Stick @@ -372,7 +194,16 @@ Qt::AlignCenter - + + 6 + + + 6 + + + 6 + + 6 @@ -395,7 +226,7 @@ true - + 3 @@ -436,7 +267,7 @@ true - + 3 @@ -493,7 +324,7 @@ - + @@ -508,13 +339,22 @@ 0 - + + 2 + + + 2 + + + 2 + + 2 - true + false @@ -533,7 +373,7 @@ - + @@ -541,7 +381,7 @@ 1 - No joystick detected yet.. waiting + @@ -551,12 +391,15 @@ Qt::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::Ok + + + @@ -568,8 +411,8 @@ accept() - 248 - 254 + 263 + 438 157 @@ -577,21 +420,5 @@ - - buttonBox - rejected() - JoystickWidget - reject() - - - 316 - 260 - - - 286 - 274 - - - -- 2.22.0