diff --git a/src/antimicro.pro b/src/antimicro.pro index d794ef563..33de38cfc 100644 --- a/src/antimicro.pro +++ b/src/antimicro.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -#USE_SDL_2 = 1 +USE_SDL_2 = 1 isEmpty(INSTALL_PREFIX) { unix { @@ -181,7 +181,8 @@ SOURCES += main.cpp\ mousedialog/springmoderegionpreview.cpp \ joystickstatuswindow.cpp \ joybuttonstatusbox.cpp \ - flashbuttonwidget.cpp + flashbuttonwidget.cpp \ + inputdevice.cpp unix { @@ -190,6 +191,14 @@ unix { SOURCES += wininfo.cpp } +!isEmpty(USE_SDL_2) { + SOURCES += gamecontroller.cpp \ + gamecontrollerdpad.cpp \ + gamecontrollerset.cpp \ + gamecontrollertrigger.cpp \ + gamecontrollermappingdialog.cpp +} + HEADERS += mainwindow.h \ joybuttonwidget.h \ joystick.h \ @@ -242,8 +251,16 @@ HEADERS += mainwindow.h \ mousedialog/springmoderegionpreview.h \ joystickstatuswindow.h \ joybuttonstatusbox.h \ - flashbuttonwidget.h + flashbuttonwidget.h \ + inputdevice.h +!isEmpty(USE_SDL_2) { + HEADERS += gamecontroller.h \ + gamecontrollerdpad.h \ + gamecontrollerset.h \ + gamecontrollertrigger.h \ + gamecontrollermappingdialog.h +} unix { HEADERS += x11info.h @@ -262,7 +279,8 @@ FORMS += mainwindow.ui \ dpadeditdialog.ui \ quicksetdialog.ui \ mousesettingsdialog.ui \ - joystickstatuswindow.ui + joystickstatuswindow.ui \ + gamecontrollermappingdialog.ui unix { diff --git a/src/axiseditdialog.cpp b/src/axiseditdialog.cpp index 2596a5fd2..5be75fa57 100644 --- a/src/axiseditdialog.cpp +++ b/src/axiseditdialog.cpp @@ -51,14 +51,18 @@ AxisEditDialog::AxisEditDialog(JoyAxis *axis, QWidget *parent) : } int currentThrottle = axis->getThrottle(); - ui->comboBox_2->setCurrentIndex(currentThrottle+1); - if (currentThrottle == -1) + //ui->comboBox_2->setCurrentIndex(currentThrottle+1); + if (currentThrottle == JoyAxis::NegativeThrottle || currentThrottle == JoyAxis::NegativeHalfThrottle) { + int tempindex = currentThrottle == JoyAxis::NegativeHalfThrottle ? 0 : 1; + ui->comboBox_2->setCurrentIndex(tempindex); ui->nPushButton->setEnabled(true); ui->pPushButton->setEnabled(false); } - else if (currentThrottle == 1) + else if (currentThrottle == JoyAxis::PositiveThrottle || currentThrottle == JoyAxis::PositiveHalfThrottle) { + int tempindex = currentThrottle == JoyAxis::PositiveThrottle ? 3 : 4; + ui->comboBox_2->setCurrentIndex(tempindex); ui->pPushButton->setEnabled(true); ui->nPushButton->setEnabled(false); } @@ -203,24 +207,28 @@ void AxisEditDialog::updateMaxZoneBox(int value) void AxisEditDialog::updateThrottleUi(int index) { - if (index == 0) + int tempthrottle = 0; + if (index == 0 || index == 1) { ui->nPushButton->setEnabled(true); ui->pPushButton->setEnabled(false); + tempthrottle = index == 0 ? JoyAxis::NegativeHalfThrottle : JoyAxis::NegativeThrottle; } - else if (index == 1) + else if (index == 2) { ui->nPushButton->setEnabled(true); ui->pPushButton->setEnabled(true); + tempthrottle = JoyAxis::NormalThrottle; } - else if (index == 2) + else if (index == 3 || index == 4) { ui->pPushButton->setEnabled(true); ui->nPushButton->setEnabled(false); + tempthrottle = index == 3 ? JoyAxis::PositiveThrottle : JoyAxis::PositiveHalfThrottle; } - ui->axisstatusBox->setThrottle(index - 1); - axis->setThrottle(index - 1); + axis->setThrottle(tempthrottle); + ui->axisstatusBox->setThrottle(tempthrottle); } void AxisEditDialog::updateJoyValue(int value) diff --git a/src/axiseditdialog.ui b/src/axiseditdialog.ui index 4fb27135e..0cbe1a6f6 100644 --- a/src/axiseditdialog.ui +++ b/src/axiseditdialog.ui @@ -327,14 +327,19 @@ defective analog stick. interpret an axis hold or release. - 1 + 2 - 3 + 5 - 3 + 5 + + + Negative Half Throttle + + Negative Throttle @@ -350,6 +355,11 @@ interpret an axis hold or release. Positive Throttle + + + Positive Half Throttle + + diff --git a/src/axisvaluebox.cpp b/src/axisvaluebox.cpp index 471877c6c..9deec49e4 100644 --- a/src/axisvaluebox.cpp +++ b/src/axisvaluebox.cpp @@ -19,7 +19,7 @@ AxisValueBox::AxisValueBox(QWidget *parent) : void AxisValueBox::setThrottle(int throttle) { - if (throttle <= 1 && throttle >= -1) + if (throttle <= JoyAxis::PositiveHalfThrottle && throttle >= JoyAxis::NegativeHalfThrottle) { this->throttle = throttle; setValue(joyValue); @@ -31,18 +31,26 @@ void AxisValueBox::setValue(int value) { if (value >= JoyAxis::AXISMIN && value <= JoyAxis::AXISMAX) { - if (throttle == 0) + if (throttle == JoyAxis::NormalThrottle) { this->joyValue = value; } - else if (throttle == -1) + else if (throttle == JoyAxis::NegativeThrottle) { this->joyValue = (value + JoyAxis::AXISMIN) / 2; } - else if (throttle == 1) + else if (throttle == JoyAxis::PositiveThrottle) { this->joyValue = (value + JoyAxis::AXISMAX) / 2; } + else if (throttle == JoyAxis::NegativeHalfThrottle) + { + this->joyValue = value <= 0 ? value : -value; + } + else if (throttle == JoyAxis::PositiveHalfThrottle) + { + this->joyValue = value >= 0 ? value : -value; + } } update(); } @@ -158,7 +166,7 @@ void AxisValueBox::paintEvent(QPaintEvent *event) brush.setColor(Qt::blue); QBrush maxBrush(Qt::red); - if (throttle == 0) + if (throttle == JoyAxis::NormalThrottle) { qDrawPlainRect(&paint, rboxstart + 2 + deadLine, 2, 4, boxheight + 2, Qt::black, 1, &brush); qDrawPlainRect(&paint, lboxend - deadLine - 2, 2, 4, boxheight + 2, Qt::black, 1, &brush); @@ -167,14 +175,14 @@ void AxisValueBox::paintEvent(QPaintEvent *event) qDrawPlainRect(&paint, rboxstart + 2 + maxLine, 2, 4, boxheight + 2, Qt::black, 1, &maxBrush); qDrawPlainRect(&paint, lboxend - maxLine - 2, 2, 4, boxheight + 2, Qt::black, 1, &maxBrush); } - else if (throttle == 1) + else if (throttle == JoyAxis::PositiveThrottle || JoyAxis::PositiveHalfThrottle) { qDrawPlainRect(&paint, lboxstart + deadLine - 2, 2, 4, boxheight + 2, Qt::black, 1, &brush); paint.setPen(Qt::red); qDrawPlainRect(&paint, lboxstart + maxLine, 2, 4, boxheight + 2, Qt::black, 1, &maxBrush); } - else if (throttle == -1) + else if (throttle == JoyAxis::NegativeThrottle || throttle == JoyAxis::NegativeHalfThrottle) { qDrawPlainRect(&paint, singleend - deadLine - 2, 2, 4, boxheight + 2, Qt::black, 1, &brush); paint.setPen(Qt::red); diff --git a/src/common.h b/src/common.h index 04ac82ac2..a0ca0f478 100644 --- a/src/common.h +++ b/src/common.h @@ -19,8 +19,11 @@ const QString configPath = (!qgetenv("LocalAppData").isEmpty()) ? QDir::homePath() + "/.config/antimicro"; #endif + const QString configFileName = "antimicro_settings.ini"; + const QString controllerMappingFileName = "controller_mappings.ini"; const QString configFilePath = configPath + "/" + configFileName; + const QString controllerMappingFilePath = configPath + "/" + controllerMappingFileName; const int LATESTCONFIGFILEVERSION = 5; const QString programVersion = "1.2"; const QString localSocketKey = "antimicroSignalListener"; diff --git a/src/gamecontroller.cpp b/src/gamecontroller.cpp new file mode 100644 index 000000000..2f36d5681 --- /dev/null +++ b/src/gamecontroller.cpp @@ -0,0 +1,499 @@ +#include "gamecontroller.h" + +const QString GameController::xmlName = "gamecontroller"; + +GameController::GameController(SDL_GameController *controller, QObject *parent) : + InputDevice(parent) +{ + this->controller = controller; + SDL_Joystick *joyhandle = SDL_GameControllerGetJoystick(controller); + joyNumber = SDL_JoystickInstanceID(joyhandle); + for (int i=0; i < NUMBER_JOYSETS; i++) + { + SetJoystick *setstick = new GameControllerSet(this, i, this); + joystick_sets.insert(i, setstick); + enableSetConnections(setstick); + } +} + +QString GameController::getName() +{ + return QString(tr("GameController")).append(" ").append(QString::number(getRealJoyNumber())); +} + +QString GameController::getSDLName() +{ + QString temp; + if (controller) + { + temp = SDL_GameControllerName(controller); + } + + return temp; +} + +QString GameController::getGUIDString() +{ + QString temp; + if (controller) + { + SDL_Joystick *joyhandle = SDL_GameControllerGetJoystick(controller); + if (joyhandle) + { + SDL_JoystickGUID tempGUID = SDL_JoystickGetGUID(joyhandle); + char guidString[65] = {'0'}; + SDL_JoystickGetGUIDString(tempGUID, guidString, sizeof(guidString)); + temp = QString(guidString); + } + } + + return temp; +} + +QString GameController::getXmlName() +{ + return this->xmlName; +} + +void GameController::closeSDLDevice() +{ + if (controller && SDL_GameControllerGetAttached(controller)) + { + SDL_GameControllerClose(controller); + controller = 0; + } +} + +int GameController::getNumberRawButtons() +{ + return SDL_CONTROLLER_BUTTON_MAX; +} + +int GameController::getNumberRawAxes() +{ + return SDL_CONTROLLER_AXIS_MAX; +} + +int GameController::getNumberRawHats() +{ + return 0; +} + + +void GameController::readConfig(QXmlStreamReader *xml) +{ + if (xml->isStartElement() && xml->name() == getXmlName()) + { + reset(); + + xml->readNextStartElement(); + while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != getXmlName())) + { + if (xml->name() == "sets" && xml->isStartElement()) + { + xml->readNextStartElement(); + + while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "sets")) + { + if (xml->name() == "set" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + index = index - 1; + if (index >= 0 && index < joystick_sets.size()) + { + joystick_sets.value(index)->readConfig(xml); + } + } + else + { + // If none of the above, skip the element + xml->skipCurrentElement(); + } + + xml->readNextStartElement(); + } + } + else if (xml->name() == "names" && xml->isStartElement()) + { + xml->readNextStartElement(); + while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "names")) + { + if (xml->name() == "buttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setButtonName(index, temp); + } + } + else if (xml->name() == "axisbuttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + int buttonIndex = xml->attributes().value("button").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + buttonIndex = buttonIndex - 1; + if (index >= 0 && !temp.isEmpty()) + { + setAxisButtonName(index, buttonIndex, temp); + } + } + else if (xml->name() == "controlstickbuttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + int buttonIndex = xml->attributes().value("button").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setStickButtonName(index, buttonIndex, temp); + } + } + else if (xml->name() == "dpadbuttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + int buttonIndex = xml->attributes().value("button").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setVDPadButtonName(index, buttonIndex, temp); + } + } + else if (xml->name() == "axisname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setAxisName(index, temp); + } + } + else if (xml->name() == "controlstickname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setStickName(index, temp); + } + } + else if (xml->name() == "dpadname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setVDPadName(index, temp); + } + } + else + { + // If none of the above, skip the element + xml->skipCurrentElement(); + } + + xml->readNextStartElement(); + } + } + else + { + // If none of the above, skip the element + xml->skipCurrentElement(); + } + + xml->readNextStartElement(); + } + } +} + +void GameController::writeConfig(QXmlStreamWriter *xml) +{ + xml->writeStartElement(getXmlName()); + xml->writeAttribute("configversion", QString::number(PadderCommon::LATESTCONFIGFILEVERSION)); + xml->writeAttribute("appversion", PadderCommon::programVersion); + + xml->writeComment("The SDL name for a joystick is included for informational purposes only."); + xml->writeTextElement("sdlname", getSDLName()); + + xml->writeStartElement("names"); // + + SetJoystick *tempSet = getActiveSetJoystick(); + for (int i=0; i < getNumberButtons(); i++) + { + JoyButton *button = tempSet->getJoyButton(i); + if (button && !button->getButtonName().isEmpty()) + { + xml->writeStartElement("buttonname"); + xml->writeAttribute("index", QString::number(button->getRealJoyNumber())); + xml->writeCharacters(button->getButtonName()); + xml->writeEndElement(); + } + } + + for (int i=0; i < getNumberAxes(); i++) + { + JoyAxis *axis = tempSet->getJoyAxis(i); + if (axis) + { + if (!axis->getAxisName().isEmpty()) + { + xml->writeStartElement("axisname"); + xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); + xml->writeCharacters(axis->getAxisName()); + xml->writeEndElement(); + } + + JoyAxisButton *naxisbutton = axis->getNAxisButton(); + if (!naxisbutton->getButtonName().isEmpty()) + { + xml->writeStartElement("axisbuttonname"); + xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(naxisbutton->getRealJoyNumber())); + xml->writeCharacters(naxisbutton->getButtonName()); + xml->writeEndElement(); + } + + JoyAxisButton *paxisbutton = axis->getPAxisButton(); + if (!paxisbutton->getButtonName().isEmpty()) + { + xml->writeStartElement("axisbuttonname"); + xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(paxisbutton->getRealJoyNumber())); + xml->writeCharacters(paxisbutton->getButtonName()); + xml->writeEndElement(); + } + } + } + + for (int i=0; i < getNumberSticks(); i++) + { + JoyControlStick *stick = tempSet->getJoyStick(i); + if (stick) + { + if (!stick->getStickName().isEmpty()) + { + xml->writeStartElement("controlstickname"); + xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); + xml->writeCharacters(stick->getStickName()); + xml->writeEndElement(); + } + + QHash *buttons = stick->getButtons(); + QHashIterator iter(*buttons); + while (iter.hasNext()) + { + JoyControlStickButton *button = iter.next().value(); + if (button && !button->getButtonName().isEmpty()) + { + xml->writeStartElement("controlstickbuttonname"); + xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + xml->writeCharacters(button->getButtonName()); + xml->writeEndElement(); + } + } + } + } + + for (int i=0; i < getNumberVDPads(); i++) + { + VDPad *vdpad = getActiveSetJoystick()->getVDPad(i); + if (vdpad) + { + if (!vdpad->getDpadName().isEmpty()) + { + xml->writeStartElement("dpadname"); + xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); + xml->writeCharacters(vdpad->getDpadName()); + xml->writeEndElement(); + } + + QHash *temp = vdpad->getButtons(); + QHashIterator iter(*temp); + while (iter.hasNext()) + { + JoyDPadButton *button = iter.next().value(); + if (button && !button->getButtonName().isEmpty()) + { + xml->writeStartElement("dpadbutton"); + xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + xml->writeCharacters(button->getButtonName()); + xml->writeEndElement(); + } + } + } + } + xml->writeEndElement(); // + + xml->writeStartElement("sets"); + for (int i=0; i < joystick_sets.size(); i++) + { + joystick_sets.value(i)->writeConfig(xml); + } + xml->writeEndElement(); + + xml->writeEndElement(); +} + +QString GameController::getBindStringForAxis(int index) +{ + QString temp; + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(controller, (SDL_GameControllerAxis)index); + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) + { + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + { + temp.append("Button %1").arg(QString::number(bind.value.button)); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + { + temp.append("Axis %1").arg(QString::number(bind.value.axis)); + } + } + return temp; +} + +QString GameController::getBindStringForButton(int index) +{ + QString temp; + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(controller, (SDL_GameControllerButton)index); + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) + { + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + { + temp.append("Button %1").arg(QString::number(bind.value.button)); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + { + temp.append("Axis %1").arg(QString::number(bind.value.axis)); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) + { + temp.append("Hat %1.%2").arg(QString::number(bind.value.hat.hat)) + .arg(QString::number(bind.value.hat.hat_mask)); + } + } + return temp; +} + +SDL_GameControllerButtonBind GameController::getBindForAxis(int index) +{ + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(controller, (SDL_GameControllerAxis)index); + return bind; +} + +SDL_GameControllerButtonBind GameController::getBindForButton(int index) +{ + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(controller, (SDL_GameControllerButton)index); + return bind; +} + +void GameController::buttonClickEvent(int setindex, int buttonindex) +{ + Q_UNUSED(setindex); + + SDL_GameControllerButtonBind bind = getBindForButton((SDL_GameControllerButton)buttonindex); + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) + { + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + { + //emit rawAxisButtonClick(bind.value.axis, 0); + emit rawAxisActivated(bind.value.axis, JoyAxis::AXISMAX); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + { + emit rawButtonClick(bind.value.button); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) + { + emit rawDPadButtonClick(bind.value.hat.hat, bind.value.hat.hat_mask); + } + } +} + +void GameController::buttonReleaseEvent(int setindex, int buttonindex) +{ + Q_UNUSED(setindex); + + SDL_GameControllerButtonBind bind = getBindForButton((SDL_GameControllerButton)buttonindex); + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) + { + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + { + emit rawAxisButtonRelease(bind.value.axis, 0); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + { + emit rawButtonRelease(bind.value.button); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) + { + emit rawDPadButtonRelease(bind.value.hat.hat, bind.value.hat.hat_mask); + } + } +} + +void GameController::axisButtonDownEvent(int setindex, int axisindex, int buttonindex) +{ + Q_UNUSED(axisindex); + + buttonDownEvent(setindex, buttonindex); +} + +void GameController::axisButtonUpEvent(int setindex, int axisindex, int buttonindex) +{ + Q_UNUSED(axisindex); + + buttonUpEvent(setindex, buttonindex); +} + +void GameController::axisActivatedEvent(int setindex, int axisindex, int value) +{ + Q_UNUSED(setindex); + + SDL_GameControllerButtonBind bind = getBindForAxis((SDL_GameControllerButton)axisindex); + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) + { + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + { + //emit rawAxisButtonClick(bind.value.axis, 0); + emit rawAxisActivated(bind.value.axis, value); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + { + emit rawButtonClick(bind.value.button); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) + { + emit rawDPadButtonClick(bind.value.hat.hat, bind.value.hat.hat_mask); + } + } +} + +void GameController::dpadButtonDownEvent(int setindex, int dpadindex, int buttonindex) +{ + Q_UNUSED(dpadindex); + + buttonDownEvent(setindex, buttonindex); +} + +void GameController::dpadButtonUpEvent(int setindex, int dpadindex, int buttonindex) +{ + Q_UNUSED(dpadindex); + + buttonUpEvent(setindex, buttonindex); +} + +SDL_JoystickID GameController::getSDLJoystickID() +{ + SDL_Joystick *temphandle = SDL_GameControllerGetJoystick(controller); + SDL_JoystickID tempid = SDL_JoystickInstanceID(temphandle); + return tempid; +} diff --git a/src/gamecontroller.h b/src/gamecontroller.h new file mode 100644 index 000000000..37ee41130 --- /dev/null +++ b/src/gamecontroller.h @@ -0,0 +1,59 @@ +#ifndef GAMECONTROLLER_H +#define GAMECONTROLLER_H + +#include + +#include +#include + +#include "inputdevice.h" +#include "gamecontrollerdpad.h" +#include "gamecontrollerset.h" + +class GameController : public InputDevice +{ + Q_OBJECT +public: + explicit GameController(SDL_GameController *controller, QObject *parent = 0); + + virtual QString getName(); + virtual QString getSDLName(); + virtual QString getGUIDString(); // GUID available on SDL 2. + virtual QString getXmlName(); + virtual void closeSDLDevice(); + virtual SDL_JoystickID getSDLJoystickID(); + + virtual int getNumberRawButtons(); + virtual int getNumberRawAxes(); + virtual int getNumberRawHats(); + + QString getBindStringForAxis(int index); + QString getBindStringForButton(int index); + + SDL_GameControllerButtonBind getBindForAxis(int index); + SDL_GameControllerButtonBind getBindForButton(int index); + + virtual void readConfig(QXmlStreamReader *xml); + virtual void writeConfig(QXmlStreamWriter *xml); + + static const QString xmlName; + +protected: + SDL_GameController *controller; + +signals: + + +public slots: + +protected slots: + virtual void axisActivatedEvent(int setindex, int axisindex, int value); + virtual void buttonClickEvent(int setindex, int buttonindex); + virtual void buttonReleaseEvent(int setindex, int buttonindex); + virtual void axisButtonDownEvent(int setindex, int axisindex, int buttonindex); + virtual void axisButtonUpEvent(int setindex, int axisindex, int buttonindex); + virtual void dpadButtonDownEvent(int setindex, int dpadindex, int buttonindex); + virtual void dpadButtonUpEvent(int setindex, int dpadindex, int buttonindex); +}; + +#endif // GAMECONTROLLER_H diff --git a/src/gamecontrollerdpad.cpp b/src/gamecontrollerdpad.cpp new file mode 100644 index 000000000..32cdbbf60 --- /dev/null +++ b/src/gamecontrollerdpad.cpp @@ -0,0 +1,44 @@ +#include "gamecontrollerdpad.h" + +const QString GameControllerDPad::xmlName = "dpad"; + +GameControllerDPad::GameControllerDPad(JoyButton *upButton, JoyButton *downButton, JoyButton *leftButton, JoyButton *rightButton, + int index, int originset, QObject *parent) : + VDPad(upButton, downButton, leftButton, rightButton, index, originset, parent) +{ +} + +QString GameControllerDPad::getName(bool forceFullFormat, bool displayName) +{ + QString label; + + if (!dpadName.isEmpty() && displayName) + { + if (forceFullFormat) + { + label.append(tr("DPad")).append(" "); + } + + label.append(dpadName); + } + else if (!defaultDPadName.isEmpty()) + { + if (forceFullFormat) + { + label.append(tr("DPad")).append(" "); + } + label.append(defaultDPadName); + } + else + { + label.append(tr("DPad")).append(" "); + label.append(QString::number(getRealJoyNumber())); + } + + return label; +} + +QString GameControllerDPad::getXmlName() +{ + return this->xmlName; +} diff --git a/src/gamecontrollerdpad.h b/src/gamecontrollerdpad.h new file mode 100644 index 000000000..8ddd5a5e0 --- /dev/null +++ b/src/gamecontrollerdpad.h @@ -0,0 +1,26 @@ +#ifndef GAMECONTROLLERDPAD_H +#define GAMECONTROLLERDPAD_H + +#include + +#include "vdpad.h" + +class GameControllerDPad : public VDPad +{ + Q_OBJECT +public: + explicit GameControllerDPad(JoyButton *upButton, JoyButton *downButton, JoyButton *leftButton, JoyButton *rightButton, + int index, int originset, QObject *parent = 0); + + virtual QString getName(bool forceFullFormat, bool displayName); + virtual QString getXmlName(); + + static const QString xmlName; + +signals: + +public slots: + +}; + +#endif // GAMECONTROLLERDPAD_H diff --git a/src/gamecontrollermappingdialog.cpp b/src/gamecontrollermappingdialog.cpp new file mode 100644 index 000000000..5cb9dc8fa --- /dev/null +++ b/src/gamecontrollermappingdialog.cpp @@ -0,0 +1,413 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gamecontrollermappingdialog.h" +#include "ui_gamecontrollermappingdialog.h" + +static QHash initAliases() +{ + QHash temp; + temp.insert(0, "a"); + temp.insert(1, "b"); + temp.insert(2, "x"); + temp.insert(3, "y"); + temp.insert(4, "back"); + temp.insert(5, "start"); + temp.insert(6, "guide"); + temp.insert(7, "leftshoulder"); + temp.insert(8, "rightshoulder"); + temp.insert(9, "leftstick"); + temp.insert(10, "rightstick"); + temp.insert(11, "leftx"); + temp.insert(12, "lefty"); + temp.insert(13, "rightx"); + temp.insert(14, "righty"); + temp.insert(15, "lefttrigger"); + temp.insert(16, "righttrigger"); + temp.insert(17, "dpup"); + temp.insert(18, "dpleft"); + temp.insert(19, "dpdown"); + temp.insert(20, "dpright"); + return temp; +} + +static QHash initButtonPlacement() +{ + QHash temp; + temp.insert(SDL_CONTROLLER_BUTTON_A, 0); + temp.insert(SDL_CONTROLLER_BUTTON_B, 1); + temp.insert(SDL_CONTROLLER_BUTTON_X, 2); + temp.insert(SDL_CONTROLLER_BUTTON_Y, 3); + temp.insert(SDL_CONTROLLER_BUTTON_BACK, 4); + temp.insert(SDL_CONTROLLER_BUTTON_START, 5); + temp.insert(SDL_CONTROLLER_BUTTON_GUIDE, 6); + temp.insert(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, 7); + temp.insert(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, 8); + temp.insert(SDL_CONTROLLER_BUTTON_LEFTSTICK, 9); + temp.insert(SDL_CONTROLLER_BUTTON_RIGHTSTICK, 10); + temp.insert(SDL_CONTROLLER_BUTTON_DPAD_UP, 17); + temp.insert(SDL_CONTROLLER_BUTTON_DPAD_LEFT, 18); + temp.insert(SDL_CONTROLLER_BUTTON_DPAD_DOWN, 19); + temp.insert(SDL_CONTROLLER_BUTTON_DPAD_RIGHT, 20); + return temp; +} + +static QHash initAxisPlacement() +{ + QHash temp; + temp.insert(SDL_CONTROLLER_AXIS_LEFTX, 11); + temp.insert(SDL_CONTROLLER_AXIS_LEFTY, 12); + temp.insert(SDL_CONTROLLER_AXIS_RIGHTX, 13); + temp.insert(SDL_CONTROLLER_AXIS_RIGHTY, 14); + temp.insert(SDL_CONTROLLER_AXIS_TRIGGERLEFT, 15); + temp.insert(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 16); + return temp; +} + +QHash GameControllerMappingDialog::tempaliases = initAliases(); + +QHash GameControllerMappingDialog::buttonPlacement = initButtonPlacement(); +QHash GameControllerMappingDialog::axisPlacement = initAxisPlacement(); + +GameControllerMappingDialog::GameControllerMappingDialog(InputDevice *device, QWidget *parent) : + QDialog(parent), + ui(new Ui::GameControllerMappingDialog) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + + this->device = device; + + if (qobject_cast(device) != 0) + { + populateGameControllerBindings(static_cast(device)); + } + + enableDeviceConnections(); + connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(testsave())); + connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(testOther(QAbstractButton*))); +} + +GameControllerMappingDialog::~GameControllerMappingDialog() +{ + delete ui; +} + +void GameControllerMappingDialog::testButtonAssign(int buttonindex) +{ + QTableWidgetItem* item = ui->buttonMappingTableWidget->currentItem(); + int column = ui->buttonMappingTableWidget->currentColumn(); + int row = ui->buttonMappingTableWidget->currentRow(); + + if (row < 17) + { + if (!item) + { + item = new QTableWidgetItem(QString("Button %1").arg(buttonindex+1)); + ui->buttonMappingTableWidget->setItem(row, column, item); + } + + QList templist; + templist.append(QVariant(0)); + templist.append(QVariant(buttonindex)); + QAbstractItemModel *model = ui->buttonMappingTableWidget->model(); + QModelIndexList matchlist = model->match(model->index(0,0), Qt::UserRole, templist, 1, Qt::MatchExactly); + foreach (const QModelIndex &index, matchlist) { + QTableWidgetItem *existingItem = ui->buttonMappingTableWidget->item(index.row(), index.column()); + if (existingItem) + { + existingItem->setText(""); + existingItem->setData(Qt::UserRole, QVariant()); + } + } + + QList tempvalue; + tempvalue.append(QVariant(0)); + tempvalue.append(QVariant(buttonindex)); + + item->setData(Qt::UserRole, tempvalue); + item->setText(QString("Button %1").arg(buttonindex+1)); + + if (row < ui->buttonMappingTableWidget->rowCount()-1) + { + ui->buttonMappingTableWidget->setCurrentCell(row+1, column); + } + } +} + +void GameControllerMappingDialog::testAxisAssign(int axis, int value) +{ + Q_UNUSED(value); + + QTableWidgetItem* item = ui->buttonMappingTableWidget->currentItem(); + int column = ui->buttonMappingTableWidget->currentColumn(); + int row = ui->buttonMappingTableWidget->currentRow(); + + if (row < 17) + { + if (!item) + { + item = new QTableWidgetItem(QString("Axis %1").arg(axis+1)); + ui->buttonMappingTableWidget->setItem(row, column, item); + } + + QList templist; + templist.append(QVariant(axis+1)); + templist.append(QVariant(0)); + QAbstractItemModel *model = ui->buttonMappingTableWidget->model(); + QModelIndexList matchlist = model->match(model->index(0,0), Qt::UserRole, templist, 1, Qt::MatchExactly); + foreach (const QModelIndex &index, matchlist) { + QTableWidgetItem *existingItem = ui->buttonMappingTableWidget->item(index.row(), index.column()); + if (existingItem) + { + existingItem->setText(""); + existingItem->setData(Qt::UserRole, QVariant()); + } + } + + QList tempvalue; + tempvalue.append(QVariant(axis+1)); + tempvalue.append(QVariant(0)); + + item->setData(Qt::UserRole, tempvalue); + item->setText(QString("Axis %1").arg(axis+1)); + + if (row < ui->buttonMappingTableWidget->rowCount()-1) + { + ui->buttonMappingTableWidget->setCurrentCell(row+1, column); + } + } +} + +void GameControllerMappingDialog::testDPadAssign(int dpad, int buttonindex) +{ + if (buttonindex == JoyDPadButton::DpadUp || + buttonindex == JoyDPadButton::DpadDown || + buttonindex == JoyDPadButton::DpadLeft || + buttonindex == JoyDPadButton::DpadRight) + { + QTableWidgetItem* item = ui->buttonMappingTableWidget->currentItem(); + int column = ui->buttonMappingTableWidget->currentColumn(); + int row = ui->buttonMappingTableWidget->currentRow(); + + if (row <= 10 || row >= 17) + { + if (!item) + { + item = new QTableWidgetItem(QString("Hat %1.%2").arg(dpad+1).arg(buttonindex)); + ui->buttonMappingTableWidget->setItem(row, column, item); + } + + QList templist; + templist.append(QVariant(-dpad-1)); + templist.append(QVariant(buttonindex)); + QAbstractItemModel *model = ui->buttonMappingTableWidget->model(); + QModelIndexList matchlist = model->match(model->index(0,0), Qt::UserRole, templist, 1, Qt::MatchExactly); + foreach (const QModelIndex &index, matchlist) { + QTableWidgetItem *existingItem = ui->buttonMappingTableWidget->item(index.row(), index.column()); + if (existingItem) + { + existingItem->setText(""); + existingItem->setData(Qt::UserRole, QVariant()); + } + } + + QList tempvalue; + tempvalue.append(QVariant(-dpad-1)); + tempvalue.append(QVariant(buttonindex)); + + item->setData(Qt::UserRole, tempvalue); + item->setText(QString("Hat %1.%2").arg(dpad+1).arg(buttonindex)); + } + + if (row < ui->buttonMappingTableWidget->rowCount()-1) + { + ui->buttonMappingTableWidget->setCurrentCell(row+1, column); + } + } +} + +void GameControllerMappingDialog::testsave() +{ + QStringList templist; + templist.append(device->getGUIDString()); + templist.append(device->getSDLName()); + + for (int i=0; i < ui->buttonMappingTableWidget->rowCount(); i++) + { + QTableWidgetItem *item = ui->buttonMappingTableWidget->item(i, 0); + if (item) + { + QString mapNative; + QList tempassociation = item->data(Qt::UserRole).toList(); + int bindingType = tempassociation.value(0).toInt(); + if (bindingType == 0) + { + mapNative.append("b"); + mapNative.append(QString::number(tempassociation.value(1).toInt())); + } + else if (bindingType > 0) + { + mapNative.append("a"); + mapNative.append(QString::number(tempassociation.value(0).toInt()-1)); + } + else if (bindingType < 0) + { + mapNative.append("h"); + mapNative.append(QString::number(tempassociation.value(0).toInt()+1)); + mapNative.append(".").append(QString::number(tempassociation.value(1).toInt())); + } + + QString sdlButtonName = tempaliases.value(i); + QString temp = QString("%1:%2").arg(sdlButtonName).arg(mapNative); + templist.append(temp); + } + } + + qDebug() << "THIS IS IT"; + qDebug() << templist.join(","); + qDebug(); + + QSettings settings(PadderCommon::controllerMappingFilePath, QSettings::IniFormat); + settings.setValue(QString("Mappings/").append(device->getGUIDString()), templist.join(",")); + emit mappingUpdate(templist.join(","), device); +} + +void GameControllerMappingDialog::populateGameControllerBindings(GameController *controller) +{ + if (controller) + { + for (int i = 0; i < controller->getNumberButtons(); i++) + { + int associatedRow = buttonPlacement.value((SDL_GameControllerButton)i); + SDL_GameControllerButtonBind bind = controller->getBindForButton(i); + QString temptext = bindingString(bind); + if (!temptext.isEmpty()) + { + QList tempvariant = bindingValues(bind); + QTableWidgetItem* item = new QTableWidgetItem(); + ui->buttonMappingTableWidget->setItem(associatedRow, 0, item); + item->setText(temptext); + item->setData(Qt::UserRole, tempvariant); + } + } + + for (int i = 0; i < controller->getNumberAxes(); i++) + { + int associatedRow = axisPlacement.value((SDL_GameControllerAxis)i); + SDL_GameControllerButtonBind bind = controller->getBindForAxis(i); + QString temptext = bindingString(bind); + if (!temptext.isEmpty()) + { + QList tempvariant = bindingValues(bind); + QTableWidgetItem* item = new QTableWidgetItem(); + ui->buttonMappingTableWidget->setItem(associatedRow, 0, item); + item->setText(temptext); + item->setData(Qt::UserRole, tempvariant); + } + } + } +} + +QString GameControllerMappingDialog::bindingString(SDL_GameControllerButtonBind bind) +{ + QString temp; + + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) + { + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + { + temp.append(QString("Button %1").arg(bind.value.button+1)); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + { + temp.append(QString("Axis %1").arg(bind.value.axis+1)); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) + { + temp.append(QString("Hat %1.%2").arg(bind.value.hat.hat+1) + .arg(bind.value.hat.hat_mask)); + } + } + + return temp; +} + +QList GameControllerMappingDialog::bindingValues(SDL_GameControllerButtonBind bind) +{ + QList temp; + + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) + { + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + { + temp.append(QVariant(0)); + temp.append(QVariant(bind.value.button)); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + { + temp.append(QVariant(bind.value.axis+1)); + temp.append(QVariant(0)); + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) + { + temp.append(QVariant(-bind.value.hat.hat-1)); + temp.append(QVariant(bind.value.hat.hat_mask)); + } + } + + return temp; +} + +void GameControllerMappingDialog::testOther(QAbstractButton *button) +{ + disableDeviceConnections(); + QDialogButtonBox::ButtonRole currentRole = ui->buttonBox->buttonRole(button); + if (currentRole == QDialogButtonBox::DestructiveRole) + { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Discard Controller Mapping?")); + msgBox.setText(tr("Discard mapping for this controller?\n\nIf discarded, the controller will be reverted to a joystick once you refresh all joysticks.")); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Close); + + int status = msgBox.exec(); + if (status == QMessageBox::Ok) + { + removeControllerMapping(); + close(); + } + else + { + connect(device, SIGNAL(rawButtonClick(int)), this, SLOT(testButtonAssign(int))); + connect(device, SIGNAL(rawAxisActivated(int,int)), this, SLOT(testAxisAssign(int,int))); + connect(device, SIGNAL(rawDPadButtonClick(int,int)), this, SLOT(testDPadAssign(int,int))); + } + } +} + +void GameControllerMappingDialog::removeControllerMapping() +{ + QSettings settings(PadderCommon::controllerMappingFilePath, QSettings::IniFormat); + settings.remove(QString("Mappings/").append(device->getGUIDString())); +} + +void GameControllerMappingDialog::enableDeviceConnections() +{ + connect(device, SIGNAL(rawButtonClick(int)), this, SLOT(testButtonAssign(int))); + connect(device, SIGNAL(rawAxisActivated(int,int)), this, SLOT(testAxisAssign(int,int))); + connect(device, SIGNAL(rawDPadButtonClick(int,int)), this, SLOT(testDPadAssign(int,int))); +} + +void GameControllerMappingDialog::disableDeviceConnections() +{ + disconnect(device, SIGNAL(rawButtonClick(int)), this, SLOT(testButtonAssign(int))); + disconnect(device, SIGNAL(rawAxisActivated(int,int)), this, SLOT(testAxisAssign(int,int))); + disconnect(device, SIGNAL(rawDPadButtonClick(int,int)), this, SLOT(testDPadAssign(int,int))); +} diff --git a/src/gamecontrollermappingdialog.h b/src/gamecontrollermappingdialog.h new file mode 100644 index 000000000..7338c5779 --- /dev/null +++ b/src/gamecontrollermappingdialog.h @@ -0,0 +1,52 @@ +#ifndef GAMECONTROLLERMAPPINGDIALOG_H +#define GAMECONTROLLERMAPPINGDIALOG_H + +#include +#include +#include + +#include "inputdevice.h" +#include "gamecontroller.h" + +namespace Ui { +class GameControllerMappingDialog; +} + +class GameControllerMappingDialog : public QDialog +{ + Q_OBJECT + +public: + explicit GameControllerMappingDialog(InputDevice *device, QWidget *parent = 0); + ~GameControllerMappingDialog(); + + static QHash tempaliases; + static QHash buttonPlacement; + static QHash axisPlacement; + +protected: + void populateGameControllerBindings(GameController *controller); + void removeControllerMapping(); + void enableDeviceConnections(); + void disableDeviceConnections(); + + QString bindingString(SDL_GameControllerButtonBind bind); + QList bindingValues(SDL_GameControllerButtonBind bind); + + InputDevice *device; + +private: + Ui::GameControllerMappingDialog *ui; + +signals: + void mappingUpdate(QString mapping, InputDevice *device); + +private slots: + void testButtonAssign(int buttonindex); + void testAxisAssign(int axis, int value); + void testDPadAssign(int dpad, int buttonindex); + void testsave(); + void testOther(QAbstractButton *button); +}; + +#endif // GAMECONTROLLERMAPPINGDIALOG_H diff --git a/src/gamecontrollermappingdialog.ui b/src/gamecontrollermappingdialog.ui new file mode 100644 index 000000000..d0993c413 --- /dev/null +++ b/src/gamecontrollermappingdialog.ui @@ -0,0 +1,262 @@ + + + GameControllerMappingDialog + + + + 0 + 0 + 669 + 474 + + + + Game Controller Mapping + + + + + + + + + QFrame::Sunken + + + 1 + + + true + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + false + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectItems + + + Qt::ElideRight + + + true + + + Qt::SolidLine + + + false + + + true + + + true + + + 21 + + + 1 + + + true + + + false + + + true + + + true + + + false + + + 30 + + + true + + + 20 + + + false + + + false + + + + A + + + + + B + + + + + X + + + + + Y + + + + + Back + + + + + Start + + + + + Guide + + + + + Left Bumper + + + + + Right Bumper + + + + + Left Stick Click + + + + + Right Stick Click + + + + + Left Stick X + + + + + Left Stick Y + + + + + Right Stick X + + + + + Right Stick Y + + + + + Left Trigger + + + + + Right Trigger + + + + + DPad Up + + + + + DPad Left + + + + + DPad Down + + + + + DPad Right + + + + + Mapping + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close|QDialogButtonBox::Discard|QDialogButtonBox::Save + + + + + + + + + buttonBox + accepted() + GameControllerMappingDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + GameControllerMappingDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/gamecontrollerset.cpp b/src/gamecontrollerset.cpp new file mode 100644 index 000000000..246ec02a3 --- /dev/null +++ b/src/gamecontrollerset.cpp @@ -0,0 +1,156 @@ +#include "gamecontrollerset.h" +#include "inputdevice.h" + +GameControllerSet::GameControllerSet(InputDevice *device, int index, QObject *parent) : + SetJoystick(device, index, parent) +{ + populateSticksDPad(); +} + +void GameControllerSet::reset() +{ + SetJoystick::reset(); + populateSticksDPad(); +} + +void GameControllerSet::populateSticksDPad() +{ + // Left Stick Assignment + JoyAxis *axisX = getJoyAxis(SDL_CONTROLLER_AXIS_LEFTX); + JoyAxis *axisY = getJoyAxis(SDL_CONTROLLER_AXIS_LEFTY); + addControlStick(0, new JoyControlStick(axisX, axisY, 0, index, this)); + + // Right Stick Assignment + axisX = getJoyAxis(SDL_CONTROLLER_AXIS_RIGHTX); + axisY = getJoyAxis(SDL_CONTROLLER_AXIS_RIGHTY); + addControlStick(1, new JoyControlStick(axisX, axisY, 1, index, this)); + + // Assign DPad buttons as a virtual DPad. Allows rougelike controls + // to be assigned. + JoyButton *buttonUp = getJoyButton(SDL_CONTROLLER_BUTTON_DPAD_UP); + JoyButton *buttonDown = getJoyButton(SDL_CONTROLLER_BUTTON_DPAD_DOWN); + JoyButton *buttonLeft = getJoyButton(SDL_CONTROLLER_BUTTON_DPAD_LEFT); + JoyButton *buttonRight = getJoyButton(SDL_CONTROLLER_BUTTON_DPAD_RIGHT); + GameControllerDPad *controllerDPad = new GameControllerDPad(buttonUp, buttonDown, buttonLeft, buttonRight, 0, index, this); + addVDPad(0, controllerDPad); + + // Give default names to buttons + getJoyButton(SDL_CONTROLLER_BUTTON_A)->setDefaultButtonName("A"); + getJoyButton(SDL_CONTROLLER_BUTTON_B)->setDefaultButtonName("B"); + getJoyButton(SDL_CONTROLLER_BUTTON_X)->setDefaultButtonName("X"); + getJoyButton(SDL_CONTROLLER_BUTTON_Y)->setDefaultButtonName("Y"); + getJoyButton(SDL_CONTROLLER_BUTTON_BACK)->setDefaultButtonName("Back"); + getJoyButton(SDL_CONTROLLER_BUTTON_GUIDE)->setDefaultButtonName("Guide"); + getJoyButton(SDL_CONTROLLER_BUTTON_START)->setDefaultButtonName("Start"); + getJoyButton(SDL_CONTROLLER_BUTTON_LEFTSTICK)->setDefaultButtonName("LS Click"); + getJoyButton(SDL_CONTROLLER_BUTTON_RIGHTSTICK)->setDefaultButtonName("RS Click"); + getJoyButton(SDL_CONTROLLER_BUTTON_LEFTSHOULDER)->setDefaultButtonName("LB"); + getJoyButton(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)->setDefaultButtonName("RB"); + + // Give default names to triggers + getJoyAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT)->setDefaultAxisName("Left Trigger"); + getJoyAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT)->setDefaultAxisName("Right Trigger"); +} + +void GameControllerSet::readConfig(QXmlStreamReader *xml) +{ + if (xml->isStartElement() && xml->name() == "set") + { + //reset(); + + xml->readNextStartElement(); + while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "set")) + { + if (xml->name() == "button" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + JoyButton *button = getJoyButton(index-1); + if (button) + { + button->readConfig(xml); + } + else + { + xml->skipCurrentElement(); + } + } + else if (xml->name() == "axis" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + JoyAxis *axis = getJoyAxis(index-1); + if (axis) + { + axis->readConfig(xml); + } + else + { + xml->skipCurrentElement(); + } + } + else if (xml->name() == "stick" && xml->isStartElement()) + { + int stickIndex = xml->attributes().value("index").toString().toInt(); + + if (stickIndex > 0) + { + stickIndex -= 1; + JoyControlStick *stick = getJoyStick(stickIndex); + if (stick) + { + stick->readConfig(xml); + } + else + { + xml->skipCurrentElement(); + } + } + else + { + xml->skipCurrentElement(); + } + } + else if (xml->name() == "dpad" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + VDPad *vdpad = getVDPad(index-1); + if (vdpad) + { + vdpad->readConfig(xml); + } + else + { + xml->skipCurrentElement(); + } + } + else + { + // If none of the above, skip the element + xml->skipCurrentElement(); + } + + xml->readNextStartElement(); + } + } +} + +void GameControllerSet::refreshAxes() +{ + deleteAxes(); + + for (int i=0; i < device->getNumberRawAxes(); i++) + { + if (i == SDL_CONTROLLER_AXIS_TRIGGERLEFT || + i == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + { + GameControllerTrigger *trigger = new GameControllerTrigger(i, index, this); + axes.insert(i, trigger); + enableAxisConnections(trigger); + } + else + { + JoyAxis *axis = new JoyAxis(i, index, this); + axes.insert(i, axis); + enableAxisConnections(axis); + } + } +} diff --git a/src/gamecontrollerset.h b/src/gamecontrollerset.h new file mode 100644 index 000000000..536288f55 --- /dev/null +++ b/src/gamecontrollerset.h @@ -0,0 +1,33 @@ +#ifndef GAMECONTROLLERSET_H +#define GAMECONTROLLERSET_H + +#include +#include +#include + +#include + +#include "setjoystick.h" +#include "gamecontrollerdpad.h" +#include "gamecontrollertrigger.h" + +class GameControllerSet : public SetJoystick +{ + Q_OBJECT +public: + explicit GameControllerSet(InputDevice *device, int index, QObject *parent = 0); + + virtual void refreshAxes(); + + virtual void readConfig(QXmlStreamReader *xml); + +protected: + void populateSticksDPad(); + +signals: + +public slots: + virtual void reset(); +}; + +#endif // GAMECONTROLLERSET_H diff --git a/src/gamecontrollertrigger.cpp b/src/gamecontrollertrigger.cpp new file mode 100644 index 000000000..f93ed0128 --- /dev/null +++ b/src/gamecontrollertrigger.cpp @@ -0,0 +1,14 @@ +#include "gamecontrollertrigger.h" + +GameControllerTrigger::GameControllerTrigger(int index, int originset, QObject *parent) : + JoyAxis(index, originset, parent) +{ + this->setThrottle(JoyAxis::PositiveHalfThrottle); +} + +bool GameControllerTrigger::isDefault() +{ + bool temp = JoyAxis::isDefault(); + temp = temp && (throttle == PositiveHalfThrottle); + return temp; +} diff --git a/src/gamecontrollertrigger.h b/src/gamecontrollertrigger.h new file mode 100644 index 000000000..cdc42a7ed --- /dev/null +++ b/src/gamecontrollertrigger.h @@ -0,0 +1,24 @@ +#ifndef GAMECONTROLLERTRIGGER_H +#define GAMECONTROLLERTRIGGER_H + +#include + +#include + +#include "joyaxis.h" + +class GameControllerTrigger : public JoyAxis +{ + Q_OBJECT +public: + explicit GameControllerTrigger(int index, int originset, QObject *parent = 0); + + virtual bool isDefault(); + +signals: + +public slots: + +}; + +#endif // GAMECONTROLLERTRIGGER_H diff --git a/src/inputdaemon.cpp b/src/inputdaemon.cpp index a30df7da0..5bd85d0c5 100644 --- a/src/inputdaemon.cpp +++ b/src/inputdaemon.cpp @@ -3,22 +3,12 @@ #include #include -#ifdef USE_SDL_2 -#include -#include - -#else -#include -#include - -#endif - #include "inputdaemon.h" #ifdef USE_SDL_2 -InputDaemon::InputDaemon(QHash *joysticks, bool graphical, QObject *parent) : +InputDaemon::InputDaemon(QHash *joysticks, bool graphical, QObject *parent) : #else -InputDaemon::InputDaemon(QHash *joysticks, bool graphical, QObject *parent) : +InputDaemon::InputDaemon(QHash *joysticks, bool graphical, QObject *parent) : #endif QObject(parent) { @@ -74,54 +64,122 @@ void InputDaemon::run () { case SDL_JOYBUTTONDOWN: { - Joystick *joy = joysticks->value(event.jbutton.which); - SetJoystick* set = joy->getActiveSetJoystick(); - JoyButton *button = set->getJoyButton(event.jbutton.button); - - if (button) +#ifdef USE_SDL_2 + InputDevice *joy = trackjoysticks.value(event.jbutton.which); +#else + InputDevice *joy = joysticks->value(event.jbutton.which); +#endif + if (joy) { - button->joyEvent(true); + SetJoystick* set = joy->getActiveSetJoystick(); + JoyButton *button = set->getJoyButton(event.jbutton.button); + + if (button) + { + button->joyEvent(true); + } } + break; } case SDL_JOYBUTTONUP: { - Joystick *joy = joysticks->value(event.jbutton.which); - SetJoystick* set = joy->getActiveSetJoystick(); - JoyButton *button = set->getJoyButton(event.jbutton.button); - - if (button) +#ifdef USE_SDL_2 + InputDevice *joy = trackjoysticks.value(event.jbutton.which); +#else + InputDevice *joy = joysticks->value(event.jbutton.which); +#endif + if (joy) { - button->joyEvent(false); + SetJoystick* set = joy->getActiveSetJoystick(); + JoyButton *button = set->getJoyButton(event.jbutton.button); + + if (button) + { + button->joyEvent(false); + } } + break; } case SDL_JOYAXISMOTION: { - Joystick *joy = joysticks->value(event.jaxis.which); - SetJoystick* set = joy->getActiveSetJoystick(); - JoyAxis *axis = set->getJoyAxis(event.jaxis.axis); - if (axis) +#ifdef USE_SDL_2 + InputDevice *joy = trackjoysticks.value(event.jaxis.which); +#else + InputDevice *joy = joysticks->value(event.jaxis.which); +#endif + if (joy) { - axis->joyEvent(event.jaxis.value); + SetJoystick* set = joy->getActiveSetJoystick(); + JoyAxis *axis = set->getJoyAxis(event.jaxis.axis); + if (axis) + { + axis->joyEvent(event.jaxis.value); + } } + break; } case SDL_JOYHATMOTION: { - Joystick *joy = joysticks->value(event.jhat.which); - SetJoystick* set = joy->getActiveSetJoystick(); - JoyDPad *dpad = set->getJoyDPad(event.jhat.hat); - if (dpad) +#ifdef USE_SDL_2 + InputDevice *joy = trackjoysticks.value(event.jhat.which); +#else + InputDevice *joy = joysticks->value(event.jhat.which); +#endif + if (joy) + { + SetJoystick* set = joy->getActiveSetJoystick(); + JoyDPad *dpad = set->getJoyDPad(event.jhat.hat); + if (dpad) + { + dpad->joyEvent(event.jhat.value); + } + } + + break; + } + +#ifdef USE_SDL_2 + case SDL_CONTROLLERAXISMOTION: + { + InputDevice *joy = trackcontrollers.value(event.caxis.which); + if (joy) { - dpad->joyEvent(event.jhat.value); + SetJoystick* set = joy->getActiveSetJoystick(); + JoyAxis *axis = set->getJoyAxis(event.caxis.axis); + if (axis) + { + axis->joyEvent(event.caxis.value); + } } break; } + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + { + //InputDevice *joy = joysticks->value(event.cbutton.which); + InputDevice *joy = trackcontrollers.value(event.cbutton.which); + if (joy) + { + SetJoystick* set = joy->getActiveSetJoystick(); + JoyButton *button = set->getJoyButton(event.cbutton.button); + + if (button) + { + button->joyEvent(event.type == SDL_CONTROLLERBUTTONDOWN ? true : false); + } + } + + break; + } +#endif + case SDL_QUIT: { stopped = true; @@ -167,13 +225,13 @@ void InputDaemon::run () void InputDaemon::refreshJoysticks() { #ifdef USE_SDL_2 - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #else - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #endif while (iter.hasNext()) { - Joystick *joystick = iter.next().value(); + InputDevice *joystick = iter.next().value(); if (joystick) { delete joystick; @@ -182,15 +240,34 @@ void InputDaemon::refreshJoysticks() } joysticks->clear(); +#ifdef USE_SDL_2 + trackjoysticks.clear(); + trackcontrollers.clear(); +#endif for (int i=0; i < SDL_NumJoysticks(); i++) { - SDL_Joystick *joystick = SDL_JoystickOpen(i); - Joystick *curJoystick = new Joystick(joystick, this); #ifdef USE_SDL_2 - SDL_JoystickID joystickID = SDL_JoystickInstanceID(joystick); - joysticks->insert(joystickID, curJoystick); + if (SDL_IsGameController(i)) + { + SDL_GameController *controller = SDL_GameControllerOpen(i); + GameController *damncontroller = new GameController(controller, this); + SDL_Joystick *sdlStick = SDL_GameControllerGetJoystick(controller); + SDL_JoystickID joystickID = SDL_JoystickInstanceID(sdlStick); + joysticks->insert(joystickID, damncontroller); + trackcontrollers.insert(joystickID, damncontroller); + } + else + { + SDL_Joystick *joystick = SDL_JoystickOpen(i); + Joystick *curJoystick = new Joystick(joystick, this); + SDL_JoystickID joystickID = SDL_JoystickInstanceID(joystick); + joysticks->insert(joystickID, curJoystick); + trackjoysticks.insert(joystickID, curJoystick); + } #else + SDL_Joystick *joystick = SDL_JoystickOpen(i); + Joystick *curJoystick = new Joystick(joystick, this); joysticks->insert(i, curJoystick); #endif } @@ -224,7 +301,7 @@ void InputDaemon::refresh() QTimer::singleShot(0, eventWorker, SLOT(performWork())); } -void InputDaemon::refreshJoystick(Joystick *joystick) +void InputDaemon::refreshJoystick(InputDevice *joystick) { joystick->reset(); @@ -248,3 +325,50 @@ void InputDaemon::quit() delete eventWorker; eventWorker = 0; } + +#ifdef USE_SDL_2 +void InputDaemon::refreshMapping(QString mapping, InputDevice *device) +{ + bool found = false; + + for (int i=0; i < SDL_NumJoysticks() && !found; i++) + { + SDL_Joystick *joystick = SDL_JoystickOpen(i); + SDL_JoystickID joystickID = SDL_JoystickInstanceID(joystick); + if (device->getJoyNumber() == joystickID) + { + found = true; + + if (SDL_IsGameController(i)) + { + // Mapping string updated. Perform basic refresh + QByteArray tempbarray = mapping.toUtf8(); + SDL_GameControllerAddMapping(tempbarray.data()); + } + else + { + // Previously registered as a plain joystick. Add + // mapping and check for validity. If SDL accepts it, + // close current device and re-open as + // a game controller. + SDL_GameControllerAddMapping(mapping.toUtf8().constData()); + + if (SDL_IsGameController(i)) + { + device->closeSDLDevice(); + trackjoysticks.remove(joystickID); + joysticks->remove(joystickID); + + SDL_GameController *controller = SDL_GameControllerOpen(i); + GameController *damncontroller = new GameController(controller, this); + SDL_Joystick *sdlStick = SDL_GameControllerGetJoystick(controller); + joystickID = SDL_JoystickInstanceID(sdlStick); + joysticks->insert(joystickID, damncontroller); + trackcontrollers.insert(joystickID, damncontroller); + emit deviceUpdated(i, damncontroller); + } + } + } + } +} +#endif diff --git a/src/inputdaemon.h b/src/inputdaemon.h index 416fca93a..8d28cd246 100644 --- a/src/inputdaemon.h +++ b/src/inputdaemon.h @@ -4,6 +4,17 @@ #include #include +#ifdef USE_SDL_2 +#include +#include +#include "gamecontroller.h" + +#else +#include +#include + +#endif + #include "joystick.h" #include "sdleventreader.h" @@ -12,17 +23,20 @@ class InputDaemon : public QObject Q_OBJECT public: #ifdef USE_SDL_2 - explicit InputDaemon (QHash *joysticks, bool graphical=true, QObject *parent=0); + explicit InputDaemon (QHash *joysticks, bool graphical=true, QObject *parent=0); #else - explicit InputDaemon (QHash *joysticks, bool graphical=true, QObject *parent=0); + explicit InputDaemon (QHash *joysticks, bool graphical=true, QObject *parent=0); #endif ~InputDaemon(); protected: #ifdef USE_SDL_2 - QHash *joysticks; + QHash *joysticks; + QHash trackjoysticks; + QHash trackcontrollers; + #else - QHash *joysticks; + QHash *joysticks; #endif bool stopped; bool graphical; @@ -31,21 +45,28 @@ class InputDaemon : public QObject QThread *thread; signals: - void joystickRefreshed (Joystick *joystick); + void joystickRefreshed (InputDevice *joystick); #ifdef USE_SDL_2 - void joysticksRefreshed(QHash *joysticks); + void joysticksRefreshed(QHash *joysticks); #else - void joysticksRefreshed(QHash *joysticks); + void joysticksRefreshed(QHash *joysticks); #endif - void complete(Joystick* joystick); + void complete(InputDevice* joystick); void complete(); +#ifdef USE_SDL_2 + void deviceUpdated(int index, InputDevice *device); +#endif + public slots: void run(); void quit(); void refresh(); - void refreshJoystick(Joystick *joystick); + void refreshJoystick(InputDevice *joystick); void refreshJoysticks(); +#ifdef USE_SDL_2 + void refreshMapping(QString mapping, InputDevice *device); +#endif private slots: void stop(); diff --git a/src/inputdevice.cpp b/src/inputdevice.cpp new file mode 100644 index 000000000..f4c0e6e51 --- /dev/null +++ b/src/inputdevice.cpp @@ -0,0 +1,1273 @@ +#include + +#include "inputdevice.h" + +const int InputDevice::NUMBER_JOYSETS = 8; + +InputDevice::InputDevice(QObject *parent) : + QObject(parent) +{ + buttonDownCount = 0; + joyNumber = 0; + active_set = 0; +} + +InputDevice::~InputDevice() +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *setjoystick = iter.next().value(); + if (setjoystick) + { + delete setjoystick; + setjoystick = 0; + } + } + + joystick_sets.clear(); +} + +int InputDevice::getJoyNumber() +{ + return joyNumber; +} + +int InputDevice::getRealJoyNumber() +{ + int joynumber = getJoyNumber(); + return joynumber + 1; +} + +void InputDevice::reset() +{ + for (int i=0; i < NUMBER_JOYSETS; i++) + { + SetJoystick* set = joystick_sets.value(i); + set->reset(); + } + + buttonDownCount = 0; +} + +void InputDevice::setActiveSetNumber(int index) +{ + if ((index >= 0 && index < NUMBER_JOYSETS) && (index != active_set)) + { + QList buttonstates; + QList axesstates; + QList dpadstates; + + SetJoystick *current_set = joystick_sets.value(active_set); + SetJoystick *old_set = current_set; + for (int i = 0; i < current_set->getNumberButtons(); i++) + { + JoyButton *button = current_set->getJoyButton(i); + buttonstates.append(button->getButtonState()); + } + + for (int i = 0; i < current_set->getNumberAxes(); i++) + { + JoyAxis *axis = current_set->getJoyAxis(i); + axesstates.append(axis->getCurrentRawValue()); + } + + for (int i = 0; i < current_set->getNumberHats(); i++) + { + JoyDPad *dpad = current_set->getJoyDPad(i); + dpadstates.append(dpad->getCurrentDirection()); + } + + joystick_sets.value(active_set)->release(); + active_set = index; + + current_set = joystick_sets.value(active_set); + for (int i = 0; i < current_set->getNumberButtons(); i++) + { + bool value = buttonstates.at(i); + bool tempignore = true; + JoyButton *button = current_set->getJoyButton(i); + JoyButton *oldButton = old_set->getJoyButton(i); + if (button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) + { + if (value) + { + if (oldButton->getChangeSetCondition() == JoyButton::SetChangeWhileHeld && oldButton->getWhileHeldStatus()) + { + button->setWhileHeldStatus(true); + } + else if (!button->getWhileHeldStatus()) + { + tempignore = false; + } + } + else + { + button->setWhileHeldStatus(false); + } + } + + //button->joyEvent(value, true); + button->joyEvent(value, tempignore); + } + + for (int i = 0; i < current_set->getNumberAxes(); i++) + { + int value = axesstates.at(i); + bool tempignore = true; + JoyAxis *axis = current_set->getJoyAxis(i); + JoyAxisButton *oldButton = old_set->getJoyAxis(i)->getAxisButtonByValue(value); + JoyAxisButton *button = axis->getAxisButtonByValue(value); + + if (button && oldButton) + { + if (button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) + { + if (value) + { + if (oldButton->getChangeSetCondition() == JoyButton::SetChangeWhileHeld && oldButton->getWhileHeldStatus()) + { + button->setWhileHeldStatus(true); + } + else if (!button->getWhileHeldStatus()) + { + tempignore = false; + } + } + } + } + else if (!button) + { + axis->getPAxisButton()->setWhileHeldStatus(false); + axis->getNAxisButton()->setWhileHeldStatus(false); + } + + axis->joyEvent(value, tempignore); + } + + for (int i = 0; i < current_set->getNumberHats(); i++) + { + int value = dpadstates.at(i); + bool tempignore = true; + JoyDPad *dpad = current_set->getJoyDPad(i); + JoyDPadButton *button = dpad->getJoyButton(value); + JoyDPadButton *oldButton = old_set->getJoyDPad(i)->getJoyButton(value); + + if (button && oldButton) + { + if (button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) + { + if (value) + { + if (oldButton->getChangeSetCondition() == JoyButton::SetChangeWhileHeld && oldButton->getWhileHeldStatus()) + { + button->setWhileHeldStatus(true); + } + else if (!button->getWhileHeldStatus()) + { + tempignore = false; + } + } + } + } + else if (!button) + { + QHashIterator iter(*dpad->getJoyButtons()); + while (iter.hasNext()) + { + JoyDPadButton *button = iter.next().value(); + button->setWhileHeldStatus(false); + } + } + + dpad->joyEvent(value, tempignore); + } + } +} + +int InputDevice::getActiveSetNumber() +{ + return active_set; +} + +SetJoystick* InputDevice::getActiveSetJoystick() +{ + return joystick_sets.value(active_set); +} + +int InputDevice::getNumberButtons() +{ + return getActiveSetJoystick()->getNumberButtons(); +} + +int InputDevice::getNumberAxes() +{ + return getActiveSetJoystick()->getNumberAxes(); +} + +int InputDevice::getNumberHats() +{ + return getActiveSetJoystick()->getNumberHats(); +} + +int InputDevice::getNumberSticks() +{ + return getActiveSetJoystick()->getNumberSticks(); +} + +int InputDevice::getNumberVDPads() +{ + return getActiveSetJoystick()->getNumberVDPads(); +} + +SetJoystick* InputDevice::getSetJoystick(int index) +{ + return joystick_sets.value(index); +} + +void InputDevice::propogateSetChange(int index) +{ + emit setChangeActivated(index); +} + +void InputDevice::changeSetButtonAssociation(int button_index, int originset, int newset, int mode) +{ + JoyButton *button = joystick_sets.value(newset)->getJoyButton(button_index); + JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; + button->setChangeSetSelection(originset); + button->setChangeSetCondition(tempmode, true); +} + +void InputDevice::readConfig(QXmlStreamReader *xml) +{ + if (xml->isStartElement() && xml->name() == getXmlName()) + { + reset(); + + xml->readNextStartElement(); + while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != getXmlName())) + { + if (xml->name() == "sets" && xml->isStartElement()) + { + xml->readNextStartElement(); + + while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "sets")) + { + if (xml->name() == "set" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + index = index - 1; + if (index >= 0 && index < joystick_sets.size()) + { + joystick_sets.value(index)->readConfig(xml); + } + } + else + { + // If none of the above, skip the element + xml->skipCurrentElement(); + } + + xml->readNextStartElement(); + } + } + else if (xml->name() == "stickAxisAssociation" && xml->isStartElement()) + { + int stickIndex = xml->attributes().value("index").toString().toInt(); + int xAxis = xml->attributes().value("xAxis").toString().toInt(); + int yAxis = xml->attributes().value("yAxis").toString().toInt(); + + if (stickIndex > 0 && xAxis > 0 && yAxis > 0) + { + xAxis -= 1; + yAxis -= 1; + stickIndex -= 1; + + for (int i=0; i getJoyAxis(xAxis); + JoyAxis *axis2 = currentset->getJoyAxis(yAxis); + if (axis1 && axis2) + { + JoyControlStick *stick = new JoyControlStick(axis1, axis2, stickIndex, i, this); + currentset->addControlStick(stickIndex, stick); + } + } + + xml->readNext(); + } + else + { + xml->skipCurrentElement(); + } + } + else if (xml->name() == "vdpadButtonAssociations" && xml->isStartElement()) + { + int vdpadIndex = xml->attributes().value("index").toString().toInt(); + if (vdpadIndex > 0) + { + for (int i=0; i getVDPad(vdpadIndex-1); + if (!vdpad) + { + vdpad = new VDPad(vdpadIndex-1, i, currentset); + currentset->addVDPad(vdpadIndex-1, vdpad); + } + } + + xml->readNextStartElement(); + while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "vdpadButtonAssociations")) + { + if (xml->name() == "vdpadButtonAssociation" && xml->isStartElement()) + { + int vdpadAxisIndex = xml->attributes().value("axis").toString().toInt(); + int vdpadButtonIndex = xml->attributes().value("button").toString().toInt(); + int vdpadDirection = xml->attributes().value("direction").toString().toInt(); + + if (vdpadAxisIndex > 0 && vdpadDirection > 0) + { + vdpadAxisIndex -= 1; + for (int i=0; i < joystick_sets.size(); i++) + { + SetJoystick *currentset = joystick_sets.value(i); + VDPad *vdpad = currentset->getVDPad(vdpadIndex-1); + if (vdpad) + { + JoyAxis *axis = currentset->getJoyAxis(vdpadAxisIndex); + if (axis) + { + JoyButton *button = 0; + if (vdpadButtonIndex == 0) + { + button = axis->getNAxisButton(); + } + else if (vdpadButtonIndex == 1) + { + button = axis->getPAxisButton(); + } + + if (button) + { + vdpad->addVButton((JoyDPadButton::JoyDPadDirections)vdpadDirection, button); + } + } + } + } + } + else if (vdpadButtonIndex > 0 && vdpadDirection > 0) + { + vdpadButtonIndex -= 1; + + for (int i=0; i < joystick_sets.size(); i++) + { + SetJoystick *currentset = joystick_sets.value(i); + VDPad *vdpad = currentset->getVDPad(vdpadIndex-1); + if (vdpad) + { + JoyButton *button = currentset->getJoyButton(vdpadButtonIndex); + if (button) + { + vdpad->addVButton((JoyDPadButton::JoyDPadDirections)vdpadDirection, button); + } + } + } + } + xml->readNext(); + } + else + { + xml->skipCurrentElement(); + } + + xml->readNextStartElement(); + } + } + + for (int i=0; i < joystick_sets.size(); i++) + { + SetJoystick *currentset = joystick_sets.value(i); + for (int j=0; j < currentset->getNumberVDPads(); j++) + { + VDPad *vdpad = currentset->getVDPad(j); + if (vdpad && vdpad->isEmpty()) + { + currentset->removeVDPad(j); + } + } + } + } + else if (xml->name() == "names" && xml->isStartElement()) + { + xml->readNextStartElement(); + while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "names")) + { + if (xml->name() == "buttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setButtonName(index, temp); + } + } + else if (xml->name() == "axisbuttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + int buttonIndex = xml->attributes().value("button").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + buttonIndex = buttonIndex - 1; + if (index >= 0 && !temp.isEmpty()) + { + setAxisButtonName(index, buttonIndex, temp); + } + } + else if (xml->name() == "controlstickbuttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + int buttonIndex = xml->attributes().value("button").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setStickButtonName(index, buttonIndex, temp); + } + } + else if (xml->name() == "dpadbuttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + int buttonIndex = xml->attributes().value("button").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setDPadButtonName(index, buttonIndex, temp); + } + } + else if (xml->name() == "vdpadbuttonname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + int buttonIndex = xml->attributes().value("button").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setVDPadButtonName(index, buttonIndex, temp); + } + } + else if (xml->name() == "axisname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setAxisName(index, temp); + } + } + else if (xml->name() == "controlstickname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setStickName(index, temp); + } + } + else if (xml->name() == "dpadname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setDPadName(index, temp); + } + } + else if (xml->name() == "vdpadname" && xml->isStartElement()) + { + int index = xml->attributes().value("index").toString().toInt(); + QString temp = xml->readElementText(); + index = index - 1; + if (index >= 0 && !temp.isEmpty()) + { + setVDPadName(index, temp); + } + } + else + { + // If none of the above, skip the element + xml->skipCurrentElement(); + } + + xml->readNextStartElement(); + } + } + else + { + // If none of the above, skip the element + xml->skipCurrentElement(); + } + + xml->readNextStartElement(); + } + } +} + +void InputDevice::writeConfig(QXmlStreamWriter *xml) +{ + xml->writeStartElement(getXmlName()); + xml->writeAttribute("configversion", QString::number(PadderCommon::LATESTCONFIGFILEVERSION)); + xml->writeAttribute("appversion", PadderCommon::programVersion); + + xml->writeComment("The SDL name for a joystick is included for informational purposes only."); + xml->writeTextElement("sdlname", getSDLName()); + + for (int i=0; i < getNumberSticks(); i++) + { + JoyControlStick *stick = getActiveSetJoystick()->getJoyStick(i); + xml->writeStartElement("stickAxisAssociation"); + xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); + xml->writeAttribute("xAxis", QString::number(stick->getAxisX()->getRealJoyIndex())); + xml->writeAttribute("yAxis", QString::number(stick->getAxisY()->getRealJoyIndex())); + xml->writeEndElement(); + } + + for (int i=0; i < getNumberVDPads(); i++) + { + VDPad *vdpad = getActiveSetJoystick()->getVDPad(i); + xml->writeStartElement("vdpadButtonAssociations"); + xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); + + JoyButton *button = vdpad->getVButton(JoyDPadButton::DpadUp); + if (button) + { + xml->writeStartElement("vdpadButtonAssociation"); + + if (typeid(*button) == typeid(JoyAxisButton)) + { + JoyAxisButton *axisbutton = static_cast(button); + xml->writeAttribute("axis", QString::number(axisbutton->getAxis()->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(button->getJoyNumber())); + } + else + { + xml->writeAttribute("axis", QString::number(0)); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + } + + xml->writeAttribute("direction", QString::number(JoyDPadButton::DpadUp)); + xml->writeEndElement(); + } + + button = vdpad->getVButton(JoyDPadButton::DpadDown); + if (button) + { + xml->writeStartElement("vdpadButtonAssociation"); + + if (typeid(*button) == typeid(JoyAxisButton)) + { + JoyAxisButton *axisbutton = static_cast(button); + xml->writeAttribute("axis", QString::number(axisbutton->getAxis()->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(button->getJoyNumber())); + } + else + { + xml->writeAttribute("axis", QString::number(0)); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + } + + xml->writeAttribute("direction", QString::number(JoyDPadButton::DpadDown)); + xml->writeEndElement(); + } + + button = vdpad->getVButton(JoyDPadButton::DpadLeft); + if (button) + { + xml->writeStartElement("vdpadButtonAssociation"); + + if (typeid(*button) == typeid(JoyAxisButton)) + { + JoyAxisButton *axisbutton = static_cast(button); + xml->writeAttribute("axis", QString::number(axisbutton->getAxis()->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(button->getJoyNumber())); + } + else + { + xml->writeAttribute("axis", QString::number(0)); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + } + + xml->writeAttribute("direction", QString::number(JoyDPadButton::DpadLeft)); + xml->writeEndElement(); + } + + button = vdpad->getVButton(JoyDPadButton::DpadRight); + if (button) + { + xml->writeStartElement("vdpadButtonAssociation"); + + if (typeid(*button) == typeid(JoyAxisButton)) + { + JoyAxisButton *axisbutton = static_cast(button); + xml->writeAttribute("axis", QString::number(axisbutton->getAxis()->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(button->getJoyNumber())); + } + else + { + xml->writeAttribute("axis", QString::number(0)); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + } + + xml->writeAttribute("direction", QString::number(JoyDPadButton::DpadRight)); + xml->writeEndElement(); + } + + xml->writeEndElement(); + } + + xml->writeStartElement("names"); // + + SetJoystick *tempSet = getActiveSetJoystick(); + for (int i=0; i < getNumberButtons(); i++) + { + JoyButton *button = tempSet->getJoyButton(i); + if (button && !button->getButtonName().isEmpty()) + { + xml->writeStartElement("buttonname"); + xml->writeAttribute("index", QString::number(button->getRealJoyNumber())); + xml->writeCharacters(button->getButtonName()); + xml->writeEndElement(); + } + } + + for (int i=0; i < getNumberAxes(); i++) + { + JoyAxis *axis = tempSet->getJoyAxis(i); + if (axis) + { + if (!axis->getAxisName().isEmpty()) + { + xml->writeStartElement("axisname"); + xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); + xml->writeCharacters(axis->getAxisName()); + xml->writeEndElement(); + } + + JoyAxisButton *naxisbutton = axis->getNAxisButton(); + if (!naxisbutton->getButtonName().isEmpty()) + { + xml->writeStartElement("axisbuttonname"); + xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(naxisbutton->getRealJoyNumber())); + xml->writeCharacters(naxisbutton->getButtonName()); + xml->writeEndElement(); + } + + JoyAxisButton *paxisbutton = axis->getPAxisButton(); + if (!paxisbutton->getButtonName().isEmpty()) + { + xml->writeStartElement("axisbuttonname"); + xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(paxisbutton->getRealJoyNumber())); + xml->writeCharacters(paxisbutton->getButtonName()); + xml->writeEndElement(); + } + } + } + + for (int i=0; i < getNumberSticks(); i++) + { + JoyControlStick *stick = tempSet->getJoyStick(i); + if (stick) + { + if (!stick->getStickName().isEmpty()) + { + xml->writeStartElement("controlstickname"); + xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); + xml->writeCharacters(stick->getStickName()); + xml->writeEndElement(); + } + + QHash *buttons = stick->getButtons(); + QHashIterator iter(*buttons); + while (iter.hasNext()) + { + JoyControlStickButton *button = iter.next().value(); + if (button && !button->getButtonName().isEmpty()) + { + xml->writeStartElement("controlstickbuttonname"); + xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + xml->writeCharacters(button->getButtonName()); + xml->writeEndElement(); + } + } + } + } + + for (int i=0; i < getNumberHats(); i++) + { + JoyDPad *dpad = tempSet->getJoyDPad(i); + if (dpad) + { + if (!dpad->getDpadName().isEmpty()) + { + xml->writeStartElement("dpadname"); + xml->writeAttribute("index", QString::number(dpad->getRealJoyNumber())); + xml->writeCharacters(dpad->getDpadName()); + xml->writeEndElement(); + } + + QHash *temp = dpad->getButtons(); + QHashIterator iter(*temp); + while (iter.hasNext()) + { + JoyDPadButton *button = iter.next().value(); + if (button && !button->getButtonName().isEmpty()) + { + xml->writeStartElement("dpadbuttonname"); + xml->writeAttribute("index", QString::number(dpad->getRealJoyNumber())); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + xml->writeCharacters(button->getButtonName()); + xml->writeEndElement(); + } + } + } + } + + for (int i=0; i < getNumberVDPads(); i++) + { + VDPad *vdpad = getActiveSetJoystick()->getVDPad(i); + if (vdpad) + { + if (!vdpad->getDpadName().isEmpty()) + { + xml->writeStartElement("vdpadname"); + xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); + xml->writeCharacters(vdpad->getDpadName()); + xml->writeEndElement(); + } + + QHash *temp = vdpad->getButtons(); + QHashIterator iter(*temp); + while (iter.hasNext()) + { + JoyDPadButton *button = iter.next().value(); + if (button && !button->getButtonName().isEmpty()) + { + xml->writeStartElement("vdpadbutton"); + xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); + xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); + xml->writeCharacters(button->getButtonName()); + xml->writeEndElement(); + } + } + } + } + xml->writeEndElement(); // + + xml->writeStartElement("sets"); + for (int i=0; i < joystick_sets.size(); i++) + { + joystick_sets.value(i)->writeConfig(xml); + } + xml->writeEndElement(); + + xml->writeEndElement(); +} + +void InputDevice::changeSetAxisButtonAssociation(int button_index, int axis_index, int originset, int newset, int mode) +{ + JoyAxisButton *button = 0; + if (button_index == 0) + { + button = joystick_sets.value(newset)->getJoyAxis(axis_index)->getNAxisButton(); + } + else if (button_index == 1) + { + button = joystick_sets.value(newset)->getJoyAxis(axis_index)->getPAxisButton(); + } + + JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; + button->setChangeSetSelection(originset); + button->setChangeSetCondition(tempmode, true); +} + +void InputDevice::changeSetStickButtonAssociation(int button_index, int stick_index, int originset, int newset, int mode) +{ + JoyControlStickButton *button = joystick_sets.value(newset)->getJoyStick(stick_index)->getDirectionButton((JoyControlStick::JoyStickDirections)button_index); + + JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; + button->setChangeSetSelection(originset); + button->setChangeSetCondition(tempmode, true); +} + +void InputDevice::changeSetDPadButtonAssociation(int button_index, int dpad_index, int originset, int newset, int mode) +{ + JoyDPadButton *button = joystick_sets.value(newset)->getJoyDPad(dpad_index)->getJoyButton(button_index); + + JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; + button->setChangeSetSelection(originset); + button->setChangeSetCondition(tempmode, true); +} + +void InputDevice::propogateSetAxisThrottleChange(int index, int originset) +{ + SetJoystick *currentSet = joystick_sets.value(originset); + if (currentSet) + { + JoyAxis *axis = currentSet->getJoyAxis(index); + if (axis) + { + int throttleSetting = axis->getThrottle(); + + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + iter.next(); + SetJoystick *temp = iter.value(); + // Ignore change for set axis that initiated the change + if (temp != currentSet) + { + temp->getJoyAxis(index)->setThrottle(throttleSetting); + } + } + } + } +} + +void InputDevice::removeControlStick(int index) +{ + for (int i=0; i < NUMBER_JOYSETS; i++) + { + SetJoystick *currentset = getSetJoystick(i); + if (currentset->getJoyStick(index)) + { + currentset->removeControlStick(index); + } + } +} + +bool InputDevice::isActive() +{ + return buttonDownCount != 0; +} + +void InputDevice::buttonDownEvent(int setindex, int buttonindex) +{ + Q_UNUSED(setindex); + Q_UNUSED(buttonindex); + + bool old = isActive(); + buttonDownCount += 1; + if (isActive() != old) + { + emit clicked(joyNumber); + } +} + +void InputDevice::buttonUpEvent(int setindex, int buttonindex) +{ + Q_UNUSED(setindex); + Q_UNUSED(buttonindex); + + bool old = isActive(); + buttonDownCount -= 1; + if (buttonDownCount < 0) + { + buttonDownCount = 0; + } + + if (isActive() != old) + { + emit released(joyNumber); + } +} + +void InputDevice::buttonClickEvent(int setindex, int buttonindex) +{ + Q_UNUSED(setindex); + + emit rawButtonClick(buttonindex); +} + +void InputDevice::buttonReleaseEvent(int setindex, int buttonindex) +{ + Q_UNUSED(setindex); + + emit rawButtonRelease(buttonindex); +} + +void InputDevice::axisButtonDownEvent(int setindex, int axisindex, int buttonindex) +{ + Q_UNUSED(axisindex); + + buttonDownEvent(setindex, buttonindex); +} + +void InputDevice::axisButtonUpEvent(int setindex, int axisindex, int buttonindex) +{ + Q_UNUSED(axisindex); + + buttonUpEvent(setindex, buttonindex); +} + +void InputDevice::dpadButtonDownEvent(int setindex, int dpadindex, int buttonindex) +{ + buttonDownEvent(setindex, buttonindex); + emit rawDPadButtonClick(dpadindex, buttonindex); +} + +void InputDevice::dpadButtonUpEvent(int setindex, int dpadindex, int buttonindex) +{ + buttonUpEvent(setindex, buttonindex); + emit rawDPadButtonRelease(dpadindex, buttonindex); +} + +void InputDevice::stickButtonDownEvent(int setindex, int stickindex, int buttonindex) +{ + Q_UNUSED(stickindex); + + buttonDownEvent(setindex, buttonindex); +} + +void InputDevice::stickButtonUpEvent(int setindex, int stickindex, int buttonindex) +{ + Q_UNUSED(stickindex); + + buttonUpEvent(setindex, buttonindex); +} + +void InputDevice::setButtonName(int index, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setButtonNameChange(int)), this, SLOT(updateSetButtonNames(int))); + JoyButton *button = tempSet->getJoyButton(index); + if (button) + { + button->setButtonName(tempName); + } + connect(tempSet, SIGNAL(setButtonNameChange(int)), this, SLOT(updateSetButtonNames(int))); + } +} + +void InputDevice::setAxisButtonName(int axisIndex, int buttonIndex, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setAxisButtonNameChange(int,int)), this, SLOT(updateSetAxisButtonNames(int,int))); + JoyAxis *axis = tempSet->getJoyAxis(axisIndex); + if (axis) + { + JoyAxisButton *button = 0; + if (buttonIndex == 0) + { + button = axis->getNAxisButton(); + } + else if (buttonIndex == 1) + { + button = axis->getPAxisButton(); + } + + if (button) + { + button->setButtonName(tempName); + } + } + connect(tempSet, SIGNAL(setAxisButtonNameChange(int,int)), this, SLOT(updateSetAxisButtonNames(int,int))); + } +} + +void InputDevice::setStickButtonName(int stickIndex, int buttonIndex, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setStickButtonNameChange(int,int)), this, SLOT(updateSetStickButtonNames(int,int))); + JoyControlStick *stick = tempSet->getJoyStick(stickIndex); + if (stick) + { + JoyControlStickButton *button = stick->getDirectionButton(JoyControlStick::JoyStickDirections(buttonIndex)); + if (button) + { + button->setButtonName(tempName); + } + } + connect(tempSet, SIGNAL(setStickButtonNameChange(int,int)), this, SLOT(updateSetStickButtonNames(int,int))); + } +} + +void InputDevice::setDPadButtonName(int dpadIndex, int buttonIndex, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setDPadButtonNameChange(int,int)), this, SLOT(updateSetDPadButtonNames(int,int))); + JoyDPad *dpad = tempSet->getJoyDPad(dpadIndex); + if (dpad) + { + JoyDPadButton *button = dpad->getJoyButton(buttonIndex); + if (button) + { + button->setButtonName(tempName); + } + } + connect(tempSet, SIGNAL(setDPadButtonNameChange(int,int)), this, SLOT(updateSetDPadButtonNames(int,int))); + } +} + +void InputDevice::setVDPadButtonName(int vdpadIndex, int buttonIndex, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setVDPadButtonNameChange(int,int)), this, SLOT(updateSetVDPadButtonNames(int,int))); + VDPad *vdpad = tempSet->getVDPad(vdpadIndex); + if (vdpad) + { + JoyDPadButton *button = vdpad->getJoyButton(buttonIndex); + if (button) + { + button->setButtonName(tempName); + } + } + connect(tempSet, SIGNAL(setVDPadButtonNameChange(int,int)), this, SLOT(updateSetVDPadButtonNames(int,int))); + } +} + +void InputDevice::setAxisName(int axisIndex, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setAxisNameChange(int)), this, SLOT(updateSetAxisNames(int))); + JoyAxis *axis = tempSet->getJoyAxis(axisIndex); + if (axis) + { + axis->setAxisName(tempName); + } + connect(tempSet, SIGNAL(setAxisNameChange(int)), this, SLOT(updateSetAxisNames(int))); + } +} + +void InputDevice::setStickName(int stickIndex, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setStickNameChange(int)), this, SLOT(updateSetStickNames(int))); + JoyControlStick *stick = tempSet->getJoyStick(stickIndex); + if (stick) + { + stick->setStickName(tempName); + } + connect(tempSet, SIGNAL(setStickNameChange(int)), this, SLOT(updateSetStickNames(int))); + } +} + +void InputDevice::setDPadName(int dpadIndex, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setDPadNameChange(int)), this, SLOT(updateSetDPadNames(int))); + JoyDPad *dpad = tempSet->getJoyDPad(dpadIndex); + if (dpad) + { + dpad->setDPadName(tempName); + } + connect(tempSet, SIGNAL(setDPadNameChange(int)), this, SLOT(updateSetDPadNames(int))); + } +} + +void InputDevice::setVDPadName(int vdpadIndex, QString tempName) +{ + QHashIterator iter(joystick_sets); + while (iter.hasNext()) + { + SetJoystick *tempSet = iter.next().value(); + disconnect(tempSet, SIGNAL(setVDPadNameChange(int)), this, SLOT(updateSetVDPadNames(int))); + VDPad *vdpad = tempSet->getVDPad(vdpadIndex); + if (vdpad) + { + vdpad->setDPadName(tempName); + } + connect(tempSet, SIGNAL(setVDPadNameChange(int)), this, SLOT(updateSetVDPadNames(int))); + } +} + + +void InputDevice::updateSetButtonNames(int index) +{ + JoyButton *button = getActiveSetJoystick()->getJoyButton(index); + if (button) + { + setButtonName(index, button->getButtonName()); + } +} + +void InputDevice::updateSetAxisButtonNames(int axisIndex, int buttonIndex) +{ + JoyAxis *axis = getActiveSetJoystick()->getJoyAxis(axisIndex); + if (axis) + { + JoyAxisButton *button = 0; + if (buttonIndex == 0) + { + button = axis->getNAxisButton(); + } + else if (buttonIndex == 1) + { + button = axis->getPAxisButton(); + } + + if (button) + { + setAxisButtonName(axisIndex, buttonIndex, button->getButtonName()); + } + } +} + +void InputDevice::updateSetStickButtonNames(int stickIndex, int buttonIndex) +{ + JoyControlStick *stick = getActiveSetJoystick()->getJoyStick(stickIndex); + if (stick) + { + JoyControlStickButton *button = stick->getDirectionButton(JoyControlStick::JoyStickDirections(buttonIndex)); + if (button) + { + setStickButtonName(stickIndex, buttonIndex, button->getButtonName()); + } + } +} + +void InputDevice::updateSetDPadButtonNames(int dpadIndex, int buttonIndex) +{ + JoyDPad *dpad = getActiveSetJoystick()->getJoyDPad(dpadIndex); + if (dpad) + { + JoyDPadButton *button = dpad->getJoyButton(buttonIndex); + if (button) + { + setDPadButtonName(dpadIndex, buttonIndex, button->getButtonName()); + } + } +} + +void InputDevice::updateSetVDPadButtonNames(int vdpadIndex, int buttonIndex) +{ + VDPad *vdpad = getActiveSetJoystick()->getVDPad(vdpadIndex); + if (vdpad) + { + JoyDPadButton *button = vdpad->getJoyButton(buttonIndex); + if (button) + { + setVDPadButtonName(vdpadIndex, buttonIndex, button->getButtonName()); + } + } +} + +void InputDevice::updateSetAxisNames(int axisIndex) +{ + JoyAxis *axis = getActiveSetJoystick()->getJoyAxis(axisIndex); + if (axis) + { + setAxisName(axisIndex, axis->getAxisName()); + } +} + +void InputDevice::updateSetStickNames(int stickIndex) +{ + JoyControlStick *stick = getActiveSetJoystick()->getJoyStick(stickIndex); + if (stick) + { + setStickName(stickIndex, stick->getStickName()); + } +} + +void InputDevice::updateSetDPadNames(int dpadIndex) +{ + JoyDPad *dpad = getActiveSetJoystick()->getJoyDPad(dpadIndex); + if (dpad) + { + setDPadName(dpadIndex, dpad->getDpadName()); + } +} + +void InputDevice::updateSetVDPadNames(int vdpadIndex) +{ + VDPad *vdpad = getActiveSetJoystick()->getVDPad(vdpadIndex); + if (vdpad) + { + setVDPadName(vdpadIndex, vdpad->getDpadName()); + } +} + +void InputDevice::resetButtonDownCount() +{ + buttonDownCount = 0; + released(0); +} + +void InputDevice::enableSetConnections(SetJoystick *setstick) +{ + connect(setstick, SIGNAL(setChangeActivated(int)), this, SLOT(setActiveSetNumber(int))); + connect(setstick, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); + connect(setstick, SIGNAL(setAssignmentButtonChanged(int,int,int,int)), this, SLOT(changeSetButtonAssociation(int,int,int,int))); + + connect(setstick, SIGNAL(setAssignmentAxisChanged(int,int,int,int,int)), this, SLOT(changeSetAxisButtonAssociation(int,int,int,int,int))); + connect(setstick, SIGNAL(setAssignmentDPadChanged(int,int,int,int,int)), this, SLOT(changeSetDPadButtonAssociation(int,int,int,int,int))); + connect(setstick, SIGNAL(setAssignmentStickChanged(int,int,int,int,int)), this, SLOT(changeSetStickButtonAssociation(int,int,int,int,int))); + connect(setstick, SIGNAL(setAssignmentAxisThrottleChanged(int,int)), this, SLOT(propogateSetAxisThrottleChange(int, int))); + + connect(setstick, SIGNAL(setButtonClick(int,int)), this, SLOT(buttonDownEvent(int,int))); + connect(setstick, SIGNAL(setButtonClick(int,int)), this, SLOT(buttonClickEvent(int,int))); + + connect(setstick, SIGNAL(setButtonRelease(int,int)), this, SLOT(buttonUpEvent(int,int))); + connect(setstick, SIGNAL(setButtonRelease(int,int)), this, SLOT(buttonReleaseEvent(int,int))); + + connect(setstick, SIGNAL(setAxisButtonClick(int,int,int)), this, SLOT(axisButtonDownEvent(int,int,int))); + connect(setstick, SIGNAL(setAxisButtonRelease(int,int,int)), this, SLOT(axisButtonUpEvent(int,int,int))); + connect(setstick, SIGNAL(setAxisActivated(int,int, int)), this, SLOT(axisActivatedEvent(int,int,int))); + + connect(setstick, SIGNAL(setDPadButtonClick(int,int,int)), this, SLOT(dpadButtonDownEvent(int,int,int))); + connect(setstick, SIGNAL(setDPadButtonRelease(int,int,int)), this, SLOT(dpadButtonUpEvent(int,int,int))); + + connect(setstick, SIGNAL(setStickButtonClick(int,int,int)), this, SLOT(stickButtonDownEvent(int,int,int))); + connect(setstick, SIGNAL(setStickButtonRelease(int,int,int)), this, SLOT(stickButtonUpEvent(int,int,int))); + + connect(setstick, SIGNAL(setButtonNameChange(int)), this, SLOT(updateSetButtonNames(int))); + connect(setstick, SIGNAL(setAxisButtonNameChange(int,int)), this, SLOT(updateSetAxisButtonNames(int,int))); + connect(setstick, SIGNAL(setStickButtonNameChange(int,int)), this, SLOT(updateSetStickButtonNames(int,int))); + connect(setstick, SIGNAL(setDPadButtonNameChange(int,int)), this, SLOT(updateSetDPadButtonNames(int,int))); + connect(setstick, SIGNAL(setVDPadButtonNameChange(int,int)), this, SLOT(updateSetVDPadButtonNames(int,int))); + + connect(setstick, SIGNAL(setAxisNameChange(int)), this, SLOT(updateSetAxisNames(int))); + connect(setstick, SIGNAL(setStickNameChange(int)), this, SLOT(updateSetStickNames(int))); + connect(setstick, SIGNAL(setDPadNameChange(int)), this, SLOT(updateSetDPadNames(int))); + connect(setstick, SIGNAL(setVDPadNameChange(int)), this, SLOT(updateSetVDPadNames(int))); +} + +void InputDevice::axisActivatedEvent(int setindex, int axisindex, int value) +{ + Q_UNUSED(setindex); + + emit rawAxisActivated(axisindex, value); +} diff --git a/src/inputdevice.h b/src/inputdevice.h new file mode 100644 index 000000000..e73dfd277 --- /dev/null +++ b/src/inputdevice.h @@ -0,0 +1,130 @@ +#ifndef INPUTDEVICE_H +#define INPUTDEVICE_H + +#include +#include +#include + +#ifdef USE_SDL_2 +#include +#else +#include +typedef Sint32 SDL_JoystickID; +#endif + +#include "setjoystick.h" +#include "common.h" + +class InputDevice : public QObject +{ + Q_OBJECT +public: + explicit InputDevice(QObject *parent = 0); + virtual ~InputDevice(); + + virtual int getNumberButtons(); + virtual int getNumberAxes(); + virtual int getNumberHats(); + virtual int getNumberSticks(); + virtual int getNumberVDPads(); + + int getJoyNumber(); + int getRealJoyNumber(); + int getActiveSetNumber(); + SetJoystick* getActiveSetJoystick(); + SetJoystick* getSetJoystick(int index); + void removeControlStick(int index); + bool isActive(); + + virtual QString getName() = 0; + virtual QString getSDLName() = 0; + virtual QString getGUIDString() = 0; // GUID available on SDL 2. + virtual QString getXmlName() = 0; + virtual void closeSDLDevice() = 0; +#ifdef USE_SDL_2 + virtual SDL_JoystickID getSDLJoystickID() = 0; +#endif + + void setButtonName(int index, QString tempName); + void setAxisButtonName(int axisIndex, int buttonIndex, QString tempName); + void setStickButtonName(int stickIndex, int buttonIndex, QString tempName); + void setDPadButtonName(int dpadIndex, int buttonIndex, QString tempName); + void setVDPadButtonName(int vdpadIndex, int buttonIndex, QString tempName); + + void setAxisName(int axisIndex, QString tempName); + void setStickName(int stickIndex, QString tempName); + void setDPadName(int dpadIndex, QString tempName); + void setVDPadName(int vdpadIndex, QString tempName); + + void resetButtonDownCount(); + + virtual void readConfig(QXmlStreamReader *xml); + virtual void writeConfig(QXmlStreamWriter *xml); + + virtual int getNumberRawButtons() = 0; + virtual int getNumberRawAxes() = 0; + virtual int getNumberRawHats() = 0; + + static const int NUMBER_JOYSETS; + +protected: + void enableSetConnections(SetJoystick *setstick); + + SDL_Joystick* joyhandle; + QHash joystick_sets; + int active_set; + int joyNumber; + int buttonDownCount; + +signals: + void setChangeActivated(int index); + void setAxisThrottleActivated(int index); + void clicked(int index); + void released(int index); + + void rawButtonClick(int index); + void rawButtonRelease(int index); + void rawAxisButtonClick(int axis, int buttonindex); + void rawAxisButtonRelease(int axis, int buttonindex); + void rawDPadButtonClick(int dpad, int buttonindex); + void rawDPadButtonRelease(int dpad, int buttonindex); + void rawAxisActivated(int axis, int value); + +public slots: + void reset(); + void setActiveSetNumber(int index); + void changeSetButtonAssociation(int button_index, int originset, int newset, int mode); + void changeSetAxisButtonAssociation(int button_index, int axis_index, int originset, int newset, int mode); + void changeSetStickButtonAssociation(int button_index, int stick_index, int originset, int newset, int mode); + void changeSetDPadButtonAssociation(int button_index, int dpad_index, int originset, int newset, int mode); + +protected slots: + void propogateSetChange(int index); + void propogateSetAxisThrottleChange(int index, int originset); + void buttonDownEvent(int setindex, int buttonindex); + void buttonUpEvent(int setindex, int buttonindex); + virtual void axisActivatedEvent(int setindex, int axisindex, int value); + virtual void buttonClickEvent(int setindex, int buttonindex); + virtual void buttonReleaseEvent(int setindex, int buttonindex); + virtual void axisButtonDownEvent(int setindex, int axisindex, int buttonindex); + virtual void axisButtonUpEvent(int setindex, int axisindex, int buttonindex); + virtual void dpadButtonDownEvent(int setindex, int dpadindex, int buttonindex); + virtual void dpadButtonUpEvent(int setindex, int dpadindex, int buttonindex); + virtual void stickButtonDownEvent(int setindex, int stickindex, int buttonindex); + virtual void stickButtonUpEvent(int setindex, int stickindex, int buttonindex); + + void updateSetButtonNames(int index); + void updateSetAxisButtonNames(int axisIndex, int buttonIndex); + void updateSetStickButtonNames(int stickIndex, int buttonIndex); + void updateSetDPadButtonNames(int dpadIndex, int buttonIndex); + void updateSetVDPadButtonNames(int vdpadIndex, int buttonIndex); + + void updateSetAxisNames(int axisIndex); + void updateSetStickNames(int stickIndex); + void updateSetDPadNames(int dpadIndex); + void updateSetVDPadNames(int vdpadIndex); +}; + +Q_DECLARE_METATYPE(InputDevice*) + +#endif // INPUTDEVICE_H diff --git a/src/joyaxis.cpp b/src/joyaxis.cpp index 75d509a52..d20af44cd 100644 --- a/src/joyaxis.cpp +++ b/src/joyaxis.cpp @@ -116,6 +116,14 @@ QString JoyAxis::getName(bool forceFullFormat, bool displayNames) label.append(axisName); } + else if (!defaultAxisName.isEmpty()) + { + if (forceFullFormat) + { + label.append(tr("Axis")).append(" "); + } + label.append(defaultAxisName); + } else { label.append(tr("Axis")).append(" "); @@ -124,7 +132,7 @@ QString JoyAxis::getName(bool forceFullFormat, bool displayNames) label.append(": "); - if (throttle == 0) + if (throttle == NormalThrottle) { label.append("-"); if (!naxisbutton->getActionName().isEmpty() && displayNames) @@ -146,7 +154,7 @@ QString JoyAxis::getName(bool forceFullFormat, bool displayNames) label.append(paxisbutton->getSlotsSummary()); } } - else if (throttle == 1) + else if (throttle == PositiveThrottle || throttle == PositiveHalfThrottle) { label.append("+"); if (!paxisbutton->getActionName().isEmpty() && displayNames) @@ -158,7 +166,7 @@ QString JoyAxis::getName(bool forceFullFormat, bool displayNames) label.append(paxisbutton->getSlotsSummary()); } } - else if (throttle == -1) + else if (throttle == NegativeThrottle || throttle == NegativeHalfThrottle) { label.append("-"); if (!naxisbutton->getActionName().isEmpty() && displayNames) @@ -188,14 +196,24 @@ int JoyAxis::calculateThrottledValue(int value) { int temp = value; - if (throttle == -1) + if (throttle == NegativeHalfThrottle) + { + value = value <= 0 ? value : -value; + temp = value; + } + if (throttle == NegativeThrottle) { temp = (value + AXISMIN) / 2; } - else if (throttle == 1) + else if (throttle == PositiveThrottle) { temp = (value + AXISMAX) / 2; } + else if (throttle == PositiveHalfThrottle) + { + value = value >= 0 ? value : -value; + temp = value; + } return temp; } @@ -282,7 +300,7 @@ int JoyAxis::getMaxZoneValue() void JoyAxis::setThrottle(int value) { - if (value >= -1 && value <= 1) + if (value >= JoyAxis::NegativeHalfThrottle && value <= JoyAxis::PositiveHalfThrottle) { if (value != throttle) { @@ -322,17 +340,25 @@ void JoyAxis::readConfig(QXmlStreamReader *xml) else if (xml->name() == "throttle" && xml->isStartElement()) { QString temptext = xml->readElementText(); - if (temptext == "negative") + if (temptext == "negativehalf") + { + this->setThrottle(JoyAxis::NegativeHalfThrottle); + } + else if (temptext == "negative") { - this->setThrottle(-1); + this->setThrottle(JoyAxis::NegativeThrottle); } else if (temptext == "normal") { - this->setThrottle(0); + this->setThrottle(JoyAxis::NormalThrottle); } else if (temptext == "positive") { - this->setThrottle(1); + this->setThrottle(JoyAxis::PositiveThrottle); + } + else if (temptext == "positivehalf") + { + this->setThrottle(JoyAxis::PositiveHalfThrottle); } setCurrentRawValue(currentThrottledDeadValue); @@ -372,18 +398,28 @@ void JoyAxis::writeConfig(QXmlStreamWriter *xml) xml->writeTextElement("maxZone", QString::number(maxZoneValue)); xml->writeStartElement("throttle"); - if (throttle == -1) + + if (throttle == JoyAxis::NegativeHalfThrottle) + { + xml->writeCharacters("negativehalf"); + } + else if (throttle == JoyAxis::NegativeThrottle) { xml->writeCharacters("negative"); } - else if (throttle == 0) + else if (throttle == JoyAxis::NormalThrottle) { xml->writeCharacters("normal"); } - else if (throttle == 1) + else if (throttle == JoyAxis::PositiveThrottle) { xml->writeCharacters("positive"); } + else if (throttle == JoyAxis::PositiveHalfThrottle) + { + xml->writeCharacters("positivehalf"); + } + xml->writeEndElement(); naxisbutton->writeConfig(xml); @@ -796,3 +832,13 @@ void JoyAxis::setButtonsWheelSpeedY(int value) paxisbutton->setWheelSpeedY(value); naxisbutton->setWheelSpeedY(value); } + +void JoyAxis::setDefaultAxisName(QString tempname) +{ + defaultAxisName = tempname; +} + +QString JoyAxis::getDefaultAxisName() +{ + return defaultAxisName; +} diff --git a/src/joyaxis.h b/src/joyaxis.h index 810025ea0..a06e4cfb2 100644 --- a/src/joyaxis.h +++ b/src/joyaxis.h @@ -20,6 +20,14 @@ class JoyAxis : public QObject explicit JoyAxis(int index, int originset, QObject *parent=0); ~JoyAxis(); + enum ThrottleTypes { + NegativeHalfThrottle = -2, + NegativeThrottle = -1, + NormalThrottle = 0, + PositiveThrottle = 1, + PositiveHalfThrottle = 2 + }; + void joyEvent(int value, bool ignoresets=false); bool inDeadZone(int value); QString getName(bool forceFullFormat=false, bool displayNames=false); @@ -80,7 +88,10 @@ class JoyAxis : public QObject void setButtonsWheelSpeedX(int value); void setButtonsWheelSpeedY(int value); - QString getAxisName(); + virtual QString getAxisName(); + + virtual void setDefaultAxisName(QString tempname); + virtual QString getDefaultAxisName(); virtual bool isDefault(); @@ -120,6 +131,7 @@ class JoyAxis : public QObject int currentThrottledDeadValue; JoyControlStick *stick; QString axisName; + QString defaultAxisName; signals: void active(int value); diff --git a/src/joyaxisbutton.cpp b/src/joyaxisbutton.cpp index 8f7c69ae4..5fdf73914 100644 --- a/src/joyaxisbutton.cpp +++ b/src/joyaxisbutton.cpp @@ -25,6 +25,14 @@ QString JoyAxisButton::getPartialName(bool forceFullFormat, bool displayNames) } temp.append(buttonName); } + else if (!defaultButtonName.isEmpty() && displayNames) + { + if (forceFullFormat) + { + temp.append(tr("Button")).append(" "); + } + temp.append(defaultButtonName); + } else { QString buttontype; diff --git a/src/joybutton.cpp b/src/joybutton.cpp index e74ff4084..194c3669c 100644 --- a/src/joybutton.cpp +++ b/src/joybutton.cpp @@ -1249,6 +1249,14 @@ QString JoyButton::getPartialName(bool forceFullFormat, bool displayNames) } temp.append(buttonName); } + else if (!defaultButtonName.isEmpty()) + { + if (forceFullFormat) + { + temp.append(tr("Button")).append(" "); + } + temp.append(defaultButtonName); + } else { temp.append(tr("Button")).append(" ").append(QString::number(getRealJoyNumber())); @@ -2333,7 +2341,7 @@ bool JoyButton::isDefault() value = value && (sensitivity == 1.0); value = value && (smoothing == false); value = value && (actionName.isEmpty()); - value = value && (buttonName.isEmpty()); + //value = value && (buttonName.isEmpty()); value = value && (wheelSpeedX == 20); value = value && (wheelSpeedY == 20); return value; @@ -2481,3 +2489,13 @@ int JoyButton::getWheelSpeedY() { return wheelSpeedY; } + +void JoyButton::setDefaultButtonName(QString tempname) +{ + defaultButtonName = tempname; +} + +QString JoyButton::getDefaultButtonName() +{ + return defaultButtonName; +} diff --git a/src/joybutton.h b/src/joybutton.h index 97ef29711..76b909ee0 100644 --- a/src/joybutton.h +++ b/src/joybutton.h @@ -100,6 +100,9 @@ class JoyButton : public QObject QString getActionName(); QString getButtonName(); + virtual void setDefaultButtonName(QString tempname); + virtual QString getDefaultButtonName(); + static const QString xmlName; static const int ENABLEDTURBODEFAULT; static const double SMOOTHINGFACTOR; @@ -185,7 +188,8 @@ class JoyButton : public QObject bool whileHeldStatus; QString actionName; - QString buttonName; + QString buttonName; // User specified button name + QString defaultButtonName; // Name used by the system static double mouseSpeedModifier; static QList mouseSpeedModList; diff --git a/src/joydpad.cpp b/src/joydpad.cpp index 7f0721e8f..6024778f4 100644 --- a/src/joydpad.cpp +++ b/src/joydpad.cpp @@ -86,6 +86,14 @@ QString JoyDPad::getName(bool fullForceFormat, bool displayActionName) label.append(dpadName); } + else if (!defaultDPadName.isEmpty()) + { + if (fullForceFormat) + { + label.append(tr("DPad")).append(" "); + } + label.append(defaultDPadName); + } else { label.append(tr("DPad")).append(" "); @@ -742,3 +750,13 @@ void JoyDPad::setButtonsWheelSpeedY(int value) button->setWheelSpeedY(value); } } + +void JoyDPad::setDefaultDPadName(QString tempname) +{ + defaultDPadName = tempname; +} + +QString JoyDPad::getDefaultDPadName() +{ + return defaultDPadName; +} diff --git a/src/joydpad.h b/src/joydpad.h index 92ed15819..676caaf65 100644 --- a/src/joydpad.h +++ b/src/joydpad.h @@ -68,6 +68,9 @@ class JoyDPad : public QObject virtual QString getXmlName(); + virtual void setDefaultDPadName(QString tempname); + virtual QString getDefaultDPadName(); + static const QString xmlName; protected: @@ -81,6 +84,7 @@ class JoyDPad : public QObject int originset; JoyMode currentMode; QString dpadName; + QString defaultDPadName; signals: void active(int value); diff --git a/src/joydpadbutton.cpp b/src/joydpadbutton.cpp index 214166d4a..a6b40b399 100644 --- a/src/joydpadbutton.cpp +++ b/src/joydpadbutton.cpp @@ -72,6 +72,14 @@ QString JoyDPadButton::getPartialName(bool forceFullFormat, bool displayNames) } temp.append(buttonName); } + else if (!defaultButtonName.isEmpty() && displayNames) + { + if (forceFullFormat) + { + temp.append(tr("Button")).append(" "); + } + temp.append(defaultButtonName); + } else { temp.append(tr("Button")).append(" "); diff --git a/src/joystick.cpp b/src/joystick.cpp index 76420fb18..8f7f5ca7f 100644 --- a/src/joystick.cpp +++ b/src/joystick.cpp @@ -5,62 +5,27 @@ #include "joystick.h" -const int Joystick::NUMBER_JOYSETS = 8; +const QString Joystick::xmlName = "joystick"; Joystick::Joystick(SDL_Joystick *joyhandle, QObject *parent) : - QObject(parent) + InputDevice(parent) { - buttonDownCount = 0; - this->joyhandle = joyhandle; #ifdef USE_SDL_2 joyNumber = SDL_JoystickInstanceID(joyhandle); #else - joyNumber= SDL_JoystickIndex(joyhandle); + joyNumber = SDL_JoystickIndex(joyhandle); #endif - joystick_sets = QHash (); for (int i=0; i < NUMBER_JOYSETS; i++) { - SetJoystick *setstick = new SetJoystick(joyhandle, i, this); + SetJoystick *setstick = new SetJoystick(this, i, this); joystick_sets.insert(i, setstick); - connect(setstick, SIGNAL(setChangeActivated(int)), this, SLOT(setActiveSetNumber(int))); - connect(setstick, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); - connect(setstick, SIGNAL(setAssignmentButtonChanged(int,int,int,int)), this, SLOT(changeSetButtonAssociation(int,int,int,int))); - - connect(setstick, SIGNAL(setAssignmentAxisChanged(int,int,int,int,int)), this, SLOT(changeSetAxisButtonAssociation(int,int,int,int,int))); - connect(setstick, SIGNAL(setAssignmentDPadChanged(int,int,int,int,int)), this, SLOT(changeSetDPadButtonAssociation(int,int,int,int,int))); - connect(setstick, SIGNAL(setAssignmentStickChanged(int,int,int,int,int)), this, SLOT(changeSetStickButtonAssociation(int,int,int,int,int))); - connect(setstick, SIGNAL(setAssignmentAxisThrottleChanged(int,int)), this, SLOT(propogateSetAxisThrottleChange(int, int))); - - connect(setstick, SIGNAL(setButtonClick(int,int)), this, SLOT(buttonDownEvent(int,int))); - connect(setstick, SIGNAL(setButtonRelease(int,int)), this, SLOT(buttonUpEvent(int,int))); - - connect(setstick, SIGNAL(setAxisButtonClick(int,int,int)), this, SLOT(axisButtonDownEvent(int,int,int))); - connect(setstick, SIGNAL(setAxisButtonRelease(int,int,int)), this, SLOT(axisButtonUpEvent(int,int,int))); - - connect(setstick, SIGNAL(setDPadButtonClick(int,int,int)), this, SLOT(dpadButtonDownEvent(int,int,int))); - connect(setstick, SIGNAL(setDPadButtonRelease(int,int,int)), this, SLOT(dpadButtonUpEvent(int,int,int))); - - connect(setstick, SIGNAL(setStickButtonClick(int,int,int)), this, SLOT(stickButtonDownEvent(int,int,int))); - connect(setstick, SIGNAL(setStickButtonRelease(int,int,int)), this, SLOT(stickButtonUpEvent(int,int,int))); - - connect(setstick, SIGNAL(setButtonNameChange(int)), this, SLOT(updateSetButtonNames(int))); - connect(setstick, SIGNAL(setAxisButtonNameChange(int,int)), this, SLOT(updateSetAxisButtonNames(int,int))); - connect(setstick, SIGNAL(setStickButtonNameChange(int,int)), this, SLOT(updateSetStickButtonNames(int,int))); - connect(setstick, SIGNAL(setDPadButtonNameChange(int,int)), this, SLOT(updateSetDPadButtonNames(int,int))); - connect(setstick, SIGNAL(setVDPadButtonNameChange(int,int)), this, SLOT(updateSetVDPadButtonNames(int,int))); - - connect(setstick, SIGNAL(setAxisNameChange(int)), this, SLOT(updateSetAxisNames(int))); - connect(setstick, SIGNAL(setStickNameChange(int)), this, SLOT(updateSetStickNames(int))); - connect(setstick, SIGNAL(setDPadNameChange(int)), this, SLOT(updateSetDPadNames(int))); - connect(setstick, SIGNAL(setVDPadNameChange(int)), this, SLOT(updateSetVDPadNames(int))); + enableSetConnections(setstick); } - - active_set = 0; } -Joystick::~Joystick() +/*Joystick::~Joystick() { QHashIterator iter(joystick_sets); while (iter.hasNext()) @@ -90,13 +55,14 @@ int Joystick::getRealJoyNumber() { int joynumber = getJoyNumber(); return joynumber + 1; -} +}*/ QString Joystick::getName() { return QString(tr("Joystick")).append(" ").append(QString::number(getRealJoyNumber())); } +/* void Joystick::reset() { for (int i=0; i < NUMBER_JOYSETS; i++) @@ -1340,6 +1306,7 @@ void Joystick::updateSetVDPadNames(int vdpadIndex) setVDPadName(vdpadIndex, vdpad->getDpadName()); } } +*/ QString Joystick::getSDLName() { @@ -1355,11 +1322,13 @@ QString Joystick::getSDLName() return temp; } +/* void Joystick::resetButtonDownCount() { buttonDownCount = 0; released(0); } +*/ QString Joystick::getGUIDString() { @@ -1373,3 +1342,49 @@ QString Joystick::getGUIDString() // Not available on SDL 1.2. Return empty string in that case. return temp; } + +QString Joystick::getXmlName() +{ + return this->xmlName; +} + +void Joystick::closeSDLDevice() +{ +#ifdef USE_SDL_2 + if (joyhandle && SDL_JoystickGetAttached(joyhandle)) + { + SDL_JoystickClose(joyhandle); + } +#else + if (joyhandle && SDL_JoystickOpened(joyNumber)) + { + SDL_JoystickClose(joyhandle); + } +#endif +} + +int Joystick::getNumberRawButtons() +{ + int numbuttons = SDL_JoystickNumButtons(joyhandle); + return numbuttons; +} + +int Joystick::getNumberRawAxes() +{ + int numaxes = SDL_JoystickNumAxes(joyhandle); + return numaxes; +} + +int Joystick::getNumberRawHats() +{ + int numhats = SDL_JoystickNumHats(joyhandle); + return numhats; +} + +#ifdef USE_SDL_2 +SDL_JoystickID Joystick::getSDLJoystickID() +{ + SDL_JoystickID temp = SDL_JoystickInstanceID(joyhandle); + return temp; +} +#endif diff --git a/src/joystick.h b/src/joystick.h index 8641febc8..b351aa053 100644 --- a/src/joystick.h +++ b/src/joystick.h @@ -1,7 +1,7 @@ #ifndef JOYSTICK_H #define JOYSTICK_H -#include +/*#include #include #include @@ -16,93 +16,42 @@ #include "joybutton.h" #include "setjoystick.h" #include "common.h" +*/ + +#include +#include +#include + +#include "inputdevice.h" -class Joystick : public QObject +class Joystick : public InputDevice { Q_OBJECT public: explicit Joystick(SDL_Joystick *joyhandle, QObject *parent=0); - ~Joystick(); - - int getNumberButtons (); - int getNumberAxes(); - int getNumberHats(); - int getNumberSticks(); - int getNumberVDPads(); - SDL_Joystick* getSDLHandle (); - int getJoyNumber (); - int getRealJoyNumber (); - QString getName(); - int getActiveSetNumber(); - SetJoystick* getActiveSetJoystick(); - SetJoystick* getSetJoystick(int index); - void removeControlStick(int index); - bool isActive(); - QString getSDLName(); - QString getGUIDString(); // GUID available on SDL 2. - - void setButtonName(int index, QString tempName); - void setAxisButtonName(int axisIndex, int buttonIndex, QString tempName); - void setStickButtonName(int stickIndex, int buttonIndex, QString tempName); - void setDPadButtonName(int dpadIndex, int buttonIndex, QString tempName); - void setVDPadButtonName(int vdpadIndex, int buttonIndex, QString tempName); - void setAxisName(int axisIndex, QString tempName); - void setStickName(int stickIndex, QString tempName); - void setDPadName(int dpadIndex, QString tempName); - void setVDPadName(int vdpadIndex, QString tempName); - - void resetButtonDownCount(); - - virtual void readConfig(QXmlStreamReader *xml); - virtual void writeConfig(QXmlStreamWriter *xml); + virtual QString getName(); + virtual QString getSDLName(); + virtual QString getGUIDString(); // GUID available on SDL 2. + virtual QString getXmlName(); + virtual void closeSDLDevice(); +#ifdef USE_SDL_2 + virtual SDL_JoystickID getSDLJoystickID(); +#endif - static const int NUMBER_JOYSETS; + static const QString xmlName; protected: - SDL_Joystick* joyhandle; - QHash joystick_sets; - int active_set; - int joyNumber; - int buttonDownCount; + virtual int getNumberRawButtons(); + virtual int getNumberRawAxes(); + virtual int getNumberRawHats(); + + SDL_Joystick *joyhandle; signals: - void setChangeActivated(int index); - void setAxisThrottleActivated(int index); - void clicked(int index); - void released(int index); public slots: - void reset(); - void setActiveSetNumber(int index); - void changeSetButtonAssociation(int button_index, int originset, int newset, int mode); - void changeSetAxisButtonAssociation(int button_index, int axis_index, int originset, int newset, int mode); - void changeSetStickButtonAssociation(int button_index, int stick_index, int originset, int newset, int mode); - void changeSetDPadButtonAssociation(int button_index, int dpad_index, int originset, int newset, int mode); - - -private slots: - void propogateSetChange(int index); - void propogateSetAxisThrottleChange(int index, int originset); - void buttonDownEvent(int setindex, int buttonindex); - void buttonUpEvent(int setindex, int buttonindex); - void axisButtonDownEvent(int setindex, int axisindex, int buttonindex); - void axisButtonUpEvent(int setindex, int axisindex, int buttonindex); - void dpadButtonDownEvent(int setindex, int dpadindex, int buttonindex); - void dpadButtonUpEvent(int setindex, int dpadindex, int buttonindex); - void stickButtonDownEvent(int setindex, int stickindex, int buttonindex); - void stickButtonUpEvent(int setindex, int stickindex, int buttonindex); - - void updateSetButtonNames(int index); - void updateSetAxisButtonNames(int axisIndex, int buttonIndex); - void updateSetStickButtonNames(int stickIndex, int buttonIndex); - void updateSetDPadButtonNames(int dpadIndex, int buttonIndex); - void updateSetVDPadButtonNames(int vdpadIndex, int buttonIndex); - void updateSetAxisNames(int axisIndex); - void updateSetStickNames(int stickIndex); - void updateSetDPadNames(int dpadIndex); - void updateSetVDPadNames(int vdpadIndex); }; Q_DECLARE_METATYPE(Joystick*) diff --git a/src/joystickstatuswindow.cpp b/src/joystickstatuswindow.cpp index 3178e8d0a..a6324d203 100644 --- a/src/joystickstatuswindow.cpp +++ b/src/joystickstatuswindow.cpp @@ -11,7 +11,7 @@ #include "joybuttonstatusbox.h" -JoystickStatusWindow::JoystickStatusWindow(Joystick *joystick, QWidget *parent) : +JoystickStatusWindow::JoystickStatusWindow(InputDevice *joystick, QWidget *parent) : QDialog(parent), ui(new Ui::JoystickStatusWindow) { diff --git a/src/joystickstatuswindow.h b/src/joystickstatuswindow.h index f891764ef..8f784b032 100644 --- a/src/joystickstatuswindow.h +++ b/src/joystickstatuswindow.h @@ -3,7 +3,7 @@ #include -#include "joystick.h" +#include "inputdevice.h" namespace Ui { class JoystickStatusWindow; @@ -14,11 +14,11 @@ class JoystickStatusWindow : public QDialog Q_OBJECT public: - explicit JoystickStatusWindow(Joystick *joystick, QWidget *parent = 0); + explicit JoystickStatusWindow(InputDevice *joystick, QWidget *parent = 0); ~JoystickStatusWindow(); protected: - Joystick *joystick; + InputDevice *joystick; private: Ui::JoystickStatusWindow *ui; diff --git a/src/joytabwidget.cpp b/src/joytabwidget.cpp index 4d1b113f2..c16236cdd 100644 --- a/src/joytabwidget.cpp +++ b/src/joytabwidget.cpp @@ -17,7 +17,11 @@ #include "joydpadbuttonwidget.h" #include "quicksetdialog.h" -JoyTabWidget::JoyTabWidget(Joystick *joystick, QWidget *parent) : +#ifdef USE_SDL_2 +#include "gamecontroller.h" +#endif + +JoyTabWidget::JoyTabWidget(InputDevice *joystick, QWidget *parent) : QWidget(parent) { this->joystick = joystick; @@ -346,6 +350,14 @@ JoyTabWidget::JoyTabWidget(Joystick *joystick, QWidget *parent) : displayingNames = false; +#ifdef USE_SDL_2 + if (qobject_cast(joystick) != 0) + { + stickAssignPushButton->setEnabled(false); + stickAssignPushButton->setVisible(false); + } +#endif + connect(loadButton, SIGNAL(clicked()), this, SLOT(openConfigFileDialog())); connect(saveButton, SIGNAL(clicked()), this, SLOT(saveConfigFile())); connect(resetButton, SIGNAL(clicked()), this, SLOT(resetJoystick())); @@ -1038,7 +1050,7 @@ void JoyTabWidget::changeJoyConfig(int index) removeCurrentButtons(); joystick->reset(); fillButtons(); - //emit joystickRefreshRequested(joystick); + emit joystickRefreshRequested(joystick); } } @@ -1291,9 +1303,10 @@ void JoyTabWidget::changeSetEight() void JoyTabWidget::showStickAssignmentDialog() { - AdvanceStickAssignmentDialog *dialog = new AdvanceStickAssignmentDialog(joystick, this); - dialog->show(); + Joystick *temp = static_cast(joystick); + AdvanceStickAssignmentDialog *dialog = new AdvanceStickAssignmentDialog(temp, this); connect(dialog, SIGNAL(finished(int)), this, SLOT(fillButtons())); + dialog->show(); } void JoyTabWidget::loadConfigFile(QString fileLocation) @@ -1339,8 +1352,8 @@ void JoyTabWidget::showDPadDialog() void JoyTabWidget::showQuickSetDialog() { QuickSetDialog *dialog = new QuickSetDialog(joystick, this); - dialog->show(); connect(dialog, SIGNAL(finished(int)), this, SLOT(fillButtons())); + dialog->show(); } void JoyTabWidget::removeCurrentButtons() @@ -1402,7 +1415,7 @@ void JoyTabWidget::removeCurrentButtons() } } -Joystick* JoyTabWidget::getJoystick() +InputDevice *JoyTabWidget::getJoystick() { return joystick; } diff --git a/src/joytabwidget.h b/src/joytabwidget.h index 77cb842a5..e6f6d063f 100644 --- a/src/joytabwidget.h +++ b/src/joytabwidget.h @@ -17,12 +17,14 @@ #include "joystick.h" #include "axiseditdialog.h" +#include "inputdevice.h" + class JoyTabWidget : public QWidget { Q_OBJECT public: - explicit JoyTabWidget(Joystick *joystick, QWidget *parent = 0); + explicit JoyTabWidget(InputDevice *joystick, QWidget *parent = 0); void saveSettings(QSettings *settings); void loadSettings(QSettings *settings, bool forceRefresh=false); @@ -31,7 +33,7 @@ class JoyTabWidget : public QWidget int getCurrentConfigIndex(); QString getCurrentConfigName(); void loadConfigFile(QString fileLocation); - Joystick *getJoystick(); + InputDevice *getJoystick(); protected: void removeCurrentButtons(); @@ -83,12 +85,12 @@ class JoyTabWidget : public QWidget QPushButton *pushButton; QSpacerItem *verticalSpacer_3; - Joystick *joystick; + InputDevice *joystick; bool displayingNames; signals: void joystickRefreshRequested(); - void joystickRefreshRequested(Joystick *joystick); + void joystickRefreshRequested(InputDevice *joystick); void joystickConfigChanged(int index); void joystickAxisRefreshLabels(int axisIndex); diff --git a/src/joytabwidgetcontainer.cpp b/src/joytabwidgetcontainer.cpp index a8a52530e..65fbf32fa 100644 --- a/src/joytabwidgetcontainer.cpp +++ b/src/joytabwidgetcontainer.cpp @@ -12,7 +12,7 @@ int JoyTabWidgetContainer::addTab(QWidget *widget, const QString &string) int JoyTabWidgetContainer::addTab(JoyTabWidget *widget, const QString &string) { - Joystick *joystick = widget->getJoystick(); + InputDevice *joystick = widget->getJoystick(); if (joystick) { @@ -24,23 +24,23 @@ int JoyTabWidgetContainer::addTab(JoyTabWidget *widget, const QString &string) void JoyTabWidgetContainer::flash() { - Joystick *joystick = static_cast(sender()); + InputDevice *joystick = static_cast(sender()); tabBar()->setTabTextColor(joystick->getJoyNumber(), Qt::red); } void JoyTabWidgetContainer::unflash() { - Joystick *joystick = static_cast(sender()); + InputDevice *joystick = static_cast(sender()); tabBar()->setTabTextColor(joystick->getJoyNumber(), Qt::black); } -void JoyTabWidgetContainer::disableFlashes(Joystick *joystick) +void JoyTabWidgetContainer::disableFlashes(InputDevice *joystick) { disconnect(joystick, SIGNAL(clicked(int)), this, SLOT(flash())); disconnect(joystick, SIGNAL(released(int)), this, SLOT(unflash())); } -void JoyTabWidgetContainer::enableFlashes(Joystick *joystick) +void JoyTabWidgetContainer::enableFlashes(InputDevice *joystick) { connect(joystick, SIGNAL(clicked(int)), this, SLOT(flash())); connect(joystick, SIGNAL(released(int)), this, SLOT(unflash())); diff --git a/src/joytabwidgetcontainer.h b/src/joytabwidgetcontainer.h index e74bccdcd..0b9c5f4be 100644 --- a/src/joytabwidgetcontainer.h +++ b/src/joytabwidgetcontainer.h @@ -20,8 +20,8 @@ class JoyTabWidgetContainer : public QTabWidget signals: public slots: - void disableFlashes(Joystick *joystick); - void enableFlashes(Joystick *joystick); + void disableFlashes(InputDevice *joystick); + void enableFlashes(InputDevice *joystick); private slots: void flash(); diff --git a/src/main.cpp b/src/main.cpp index 7b6c8567e..7becb0320 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,13 +33,15 @@ #include "advancebuttondialog.h" #include "commandlineutility.h" #include "mainwindow.h" +#include "inputdevice.h" int main(int argc, char *argv[]) { qRegisterMetaType(); qRegisterMetaType(); - qRegisterMetaType(); + //qRegisterMetaType(); + qRegisterMetaType(); // If running Win version, check if an explicit style // was defined on the command-line. If so, make a note @@ -111,9 +113,9 @@ int main(int argc, char *argv[]) } #ifdef USE_SDL_2 - QHash *joysticks = new QHash(); + QHash *joysticks = new QHash(); #else - QHash *joysticks = new QHash(); + QHash *joysticks = new QHash(); #endif // Cross-platform way of performing IPC. Currently, @@ -141,14 +143,14 @@ int main(int argc, char *argv[]) socket.disconnectFromServer(); #ifdef USE_SDL_2 - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #else - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #endif while (iter.hasNext()) { - Joystick *joystick = iter.next().value(); + InputDevice *joystick = iter.next().value(); if (joystick) { delete joystick; @@ -171,16 +173,18 @@ int main(int argc, char *argv[]) w.startLocalServer(); #ifdef USE_SDL_2 - QObject::connect(joypad_worker, SIGNAL(joysticksRefreshed(QHash*)), &w, SLOT(fillButtons(QHash*))); + QObject::connect(joypad_worker, SIGNAL(joysticksRefreshed(QHash*)), &w, SLOT(fillButtons(QHash*))); #else - QObject::connect(joypad_worker, SIGNAL(joysticksRefreshed(QHash*)), &w, SLOT(fillButtons(QHash*))); + QObject::connect(joypad_worker, SIGNAL(joysticksRefreshed(QHash*)), &w, SLOT(fillButtons(QHash*))); #endif QObject::connect(&w, SIGNAL(joystickRefreshRequested()), joypad_worker, SLOT(refresh())); - QObject::connect(joypad_worker, SIGNAL(joystickRefreshed(Joystick*)), &w, SLOT(fillButtons(Joystick*))); + QObject::connect(joypad_worker, SIGNAL(joystickRefreshed(InputDevice*)), &w, SLOT(fillButtons(InputDevice*))); QObject::connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); QObject::connect(&a, SIGNAL(aboutToQuit()), &w, SLOT(saveAppConfig())); QObject::connect(&a, SIGNAL(aboutToQuit()), &w, SLOT(removeJoyTabs())); QObject::connect(&a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(quit())); + QObject::connect(&w, SIGNAL(mappingUpdated(QString,InputDevice*)), joypad_worker, SLOT(refreshMapping(QString,InputDevice*))); + QObject::connect(joypad_worker, SIGNAL(deviceUpdated(int,InputDevice*)), &w, SLOT(testMappingUpdateNow(int,InputDevice*))); if (!cmdutility.isHiddenRequested() && (!cmdutility.isLaunchInTrayEnabled() || !QSystemTrayIcon::isSystemTrayAvailable())) { @@ -190,14 +194,14 @@ int main(int argc, char *argv[]) int app_result = a.exec(); #ifdef USE_SDL_2 - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #else - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #endif while (iter.hasNext()) { - Joystick *joystick = iter.next().value(); + InputDevice *joystick = iter.next().value(); if (joystick) { delete joystick; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4bd6a133e..cee7a922a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -16,9 +16,13 @@ #include "common.h" #ifdef USE_SDL_2 -MainWindow::MainWindow(QHash *joysticks, CommandLineUtility *cmdutility, bool graphical, QWidget *parent) : +#include "gamecontrollermappingdialog.h" +#endif + +#ifdef USE_SDL_2 +MainWindow::MainWindow(QHash *joysticks, CommandLineUtility *cmdutility, bool graphical, QWidget *parent) : #else -MainWindow::MainWindow(QHash *joysticks, CommandLineUtility *cmdutility, bool graphical, QWidget *parent) : +MainWindow::MainWindow(QHash *joysticks, CommandLineUtility *cmdutility, bool graphical, QWidget *parent) : #endif QMainWindow(parent), ui(new Ui::MainWindow) @@ -64,6 +68,7 @@ MainWindow::MainWindow(QHash *joysticks, CommandLineUtility *cmd connect(ui->menuOptions, SIGNAL(aboutToShow()), this, SLOT(mainMenuChange())); connect(ui->actionAbout_Qt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); connect(ui->actionProperties, SIGNAL(triggered()), this, SLOT(openJoystickStatusWindow())); + connect(ui->actionGameController_Mapping, SIGNAL(triggered()), this, SLOT(openGameControllerMappingWindow())); } MainWindow::~MainWindow() @@ -71,7 +76,7 @@ MainWindow::~MainWindow() delete ui; } -void MainWindow::fillButtons(Joystick *joystick) +void MainWindow::fillButtons(InputDevice *joystick) { int joyindex = joystick->getJoyNumber(); JoyTabWidget *tabwidget = (JoyTabWidget*)ui->tabWidget->widget(joyindex); @@ -79,29 +84,29 @@ void MainWindow::fillButtons(Joystick *joystick) } #ifdef USE_SDL_2 -void MainWindow::fillButtons(QHash *joysticks) +void MainWindow::fillButtons(QHash *joysticks) #else -void MainWindow::fillButtons(QHash *joysticks) +void MainWindow::fillButtons(QHash *joysticks) #endif { ui->stackedWidget->setCurrentIndex(0); removeJoyTabs(); #ifdef USE_SDL_2 - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #else - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #endif while (iter.hasNext()) { iter.next(); - Joystick *joystick = iter.value(); + InputDevice *joystick = iter.value(); JoyTabWidget *tabwidget = new JoyTabWidget(joystick, this); QString joytabName = joystick->getSDLName(); - joytabName.append(" ").append(tr("(Joystick %1)").arg(joystick->getRealJoyNumber())); + joytabName.append(" ").append(tr("(%1)").arg(joystick->getName())); ui->tabWidget->addTab(tabwidget, joytabName); tabwidget->fillButtons(); //ui->tabWidget->addTab(tabwidget, QString(tr("Joystick %1")).arg(joystick->getRealJoyNumber())); @@ -148,7 +153,7 @@ void MainWindow::fillButtons(QHash *joysticks) ui->actionQuit->setEnabled(true); } -void MainWindow::joystickRefreshPropogate(Joystick *joystick) +void MainWindow::joystickRefreshPropogate(InputDevice *joystick) { emit joystickRefreshRequested(joystick); } @@ -172,15 +177,15 @@ void MainWindow::populateTrayIcon() if (joysticks->count() > 0) { #ifdef USE_SDL_2 - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #else - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); #endif int i = 0; while (iter.hasNext()) { iter.next(); - Joystick *current = iter.value(); + InputDevice *current = iter.value(); QMenu *joysticksub = trayIconMenu->addMenu(current->getName()); JoyTabWidget *widget = (JoyTabWidget*)ui->tabWidget->widget(i); @@ -326,6 +331,10 @@ void MainWindow::mainMenuChange() { ui->actionHide->setEnabled(false); } + +#ifndef USE_SDL_2 + ui->actionGameController_Mapping->setVisible(false); +#endif } void MainWindow::saveAppConfig() @@ -657,10 +666,48 @@ void MainWindow::openJoystickStatusWindow() { int index = ui->tabWidget->currentIndex(); JoyTabWidget *joyTab = static_cast(ui->tabWidget->widget(index)); - Joystick *joystick = joyTab->getJoystick(); + InputDevice *joystick = joyTab->getJoystick(); if (joystick) { JoystickStatusWindow *dialog = new JoystickStatusWindow(joystick, this); dialog->show(); } } + +#ifdef USE_SDL_2 +void MainWindow::openGameControllerMappingWindow() +{ + int index = ui->tabWidget->currentIndex(); + JoyTabWidget *joyTab = static_cast(ui->tabWidget->widget(index)); + InputDevice *joystick = joyTab->getJoystick(); + if (joystick) + { + GameControllerMappingDialog *dialog = new GameControllerMappingDialog(joystick, this); + dialog->show(); + connect(dialog, SIGNAL(mappingUpdate(QString,InputDevice*)), this, SLOT(propogateMappingUpdate(QString, InputDevice*))); + } +} + +void MainWindow::propogateMappingUpdate(QString mapping, InputDevice *device) +{ + emit mappingUpdated(mapping, device); +} + +void MainWindow::testMappingUpdateNow(int index, InputDevice *device) +{ + QWidget *tab = ui->tabWidget->widget(index); + if (tab) + { + ui->tabWidget->removeTab(index); + delete tab; + tab = 0; + } + + JoyTabWidget *tabwidget = new JoyTabWidget(device, this); + QString joytabName = device->getSDLName(); + joytabName.append(" ").append(tr("(%1)").arg(device->getName())); + ui->tabWidget->insertTab(index, tabwidget, joytabName); + tabwidget->fillButtons(); + ui->tabWidget->setCurrentIndex(index); +} +#endif diff --git a/src/mainwindow.h b/src/mainwindow.h index 4a97811c5..49a29cf64 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -29,9 +29,9 @@ class MainWindow : public QMainWindow public: #ifdef USE_SDL_2 - MainWindow(QHash *joysticks, CommandLineUtility *cmdutility, bool graphical=true, QWidget *parent = 0); + MainWindow(QHash *joysticks, CommandLineUtility *cmdutility, bool graphical=true, QWidget *parent = 0); #else - MainWindow(QHash *joysticks, CommandLineUtility *cmdutility, bool graphical=true, QWidget *parent = 0); + MainWindow(QHash *joysticks, CommandLineUtility *cmdutility, bool graphical=true, QWidget *parent = 0); #endif ~MainWindow(); @@ -41,9 +41,9 @@ class MainWindow : public QMainWindow void loadConfigFile(QString fileLocation, int joystickIndex=0); #ifdef USE_SDL_2 - QHash *joysticks; + QHash *joysticks; #else - QHash *joysticks; + QHash *joysticks; #endif QSystemTrayIcon *trayIcon; @@ -63,15 +63,16 @@ class MainWindow : public QMainWindow signals: void joystickRefreshRequested(); - void joystickRefreshRequested(Joystick *joystick); + void joystickRefreshRequested(InputDevice *joystick); void readConfig(int index); + void mappingUpdated(QString mapping, InputDevice *device); public slots: - void fillButtons(Joystick *joystick); + void fillButtons(InputDevice *joystick); #ifdef USE_SDL_2 - void fillButtons(QHash *joysticks); + void fillButtons(QHash *joysticks); #else - void fillButtons(QHash *joysticks); + void fillButtons(QHash *joysticks); #endif void startJoystickRefresh(); void hideWindow(); @@ -79,6 +80,9 @@ public slots: void loadAppConfig(bool forceRefresh=false); void removeJoyTabs(); void startLocalServer(); +#ifdef USE_SDL_2 + void testMappingUpdateNow(int index, InputDevice *device); +#endif private slots: void quitProgram(); @@ -87,7 +91,7 @@ private slots: void mainMenuChange(); void disableFlashActions(); void enableFlashActions(); - void joystickRefreshPropogate(Joystick *joystick); + void joystickRefreshPropogate(InputDevice *joystick); void trayMenuChangeJoyConfig(QAction *action); void joystickTrayShow(); void populateTrayIcon(); @@ -95,6 +99,10 @@ private slots: void handleOutsideConnection(); void handleSocketDisconnect(); void openJoystickStatusWindow(); +#ifdef USE_SDL_2 + void openGameControllerMappingWindow(); + void propogateMappingUpdate(QString mapping, InputDevice *device); +#endif }; #endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 0d001cd1f..f5938affc 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -3,7 +3,7 @@ MainWindow - Qt::NonModal + Qt::WindowModal @@ -581,6 +581,7 @@ QPushButton#namesPushButton[isDisplayingNames="true"] { + @@ -658,6 +659,11 @@ QPushButton#namesPushButton[isDisplayingNames="true"] { Properties + + + GameController Mapping + + diff --git a/src/quicksetdialog.cpp b/src/quicksetdialog.cpp index b1a8b98db..32e2122b8 100644 --- a/src/quicksetdialog.cpp +++ b/src/quicksetdialog.cpp @@ -7,7 +7,7 @@ #include "setjoystick.h" #include "buttoneditdialog.h" -QuickSetDialog::QuickSetDialog(Joystick *joystick, QWidget *parent) : +QuickSetDialog::QuickSetDialog(InputDevice *joystick, QWidget *parent) : QDialog(parent), ui(new Ui::QuickSetDialog) { diff --git a/src/quicksetdialog.h b/src/quicksetdialog.h index f56d4e378..b0cb9063e 100644 --- a/src/quicksetdialog.h +++ b/src/quicksetdialog.h @@ -3,7 +3,7 @@ #include -#include "joystick.h" +#include "inputdevice.h" namespace Ui { class QuickSetDialog; @@ -14,11 +14,11 @@ class QuickSetDialog : public QDialog Q_OBJECT public: - explicit QuickSetDialog(Joystick *joystick, QWidget *parent = 0); + explicit QuickSetDialog(InputDevice *joystick, QWidget *parent = 0); ~QuickSetDialog(); protected: - Joystick *joystick; + InputDevice *joystick; QDialog *currentButtonDialog; private: diff --git a/src/sdleventreader.cpp b/src/sdleventreader.cpp index 177aa4ff9..7566f587c 100644 --- a/src/sdleventreader.cpp +++ b/src/sdleventreader.cpp @@ -1,6 +1,10 @@ +#include +#include +#include + #include "sdleventreader.h" -SDLEventReader::SDLEventReader(QHash *joysticks, QObject *parent) : +SDLEventReader::SDLEventReader(QHash *joysticks, QObject *parent) : QObject(parent) { this->joysticks = joysticks; @@ -15,13 +19,32 @@ SDLEventReader::~SDLEventReader() void SDLEventReader::initSDL() { #ifdef USE_SDL_2 - SDL_Init(SDL_INIT_JOYSTICK); + SDL_Init(SDL_INIT_GAMECONTROLLER); #else SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK); #endif SDL_JoystickEventState(SDL_ENABLE); sdlIsOpen = true; +#ifdef USE_SDL_2 + QSettings settings(PadderCommon::controllerMappingFilePath, QSettings::IniFormat); + QStringList mappings = settings.allKeys(); + QStringListIterator iter(mappings); + while (iter.hasNext()) + { + QString tempstring = iter.next(); + QString mappingSetting = settings.value(tempstring, QString()).toString(); + if (!mappingSetting.isEmpty()) + { + QByteArray temparray = mappingSetting.toUtf8(); + char *mapping = temparray.data(); + SDL_GameControllerAddMapping(mapping); // Let SDL take care of validation + } + } + + //SDL_GameControllerAddMapping("03000000100800000100000010010000,Twin USB Joystick,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2"); +#endif + emit sdlStarted(); } @@ -29,22 +52,30 @@ void SDLEventReader::closeSDL() { SDL_Event event; #ifdef USE_SDL_2 - QHashIterator iter(*joysticks); + QHashIterator iter(*joysticks); while (iter.hasNext()) { iter.next(); //SDL_JoystickID currentSdlId = iter.key(); - Joystick *current = iter.value(); - SDL_Joystick *sdlHandle = current->getSDLHandle(); + InputDevice *current = iter.value(); + //SDL_Joystick *sdlHandle = current->getSDLHandle(); - if (sdlHandle && SDL_JoystickGetAttached(sdlHandle)) + /*if (sdlHandle && SDL_JoystickGetAttached(sdlHandle)) { SDL_JoystickClose(sdlHandle); - } + }*/ + current->closeSDLDevice(); } #else - for (int i=0; i < SDL_NumJoysticks(); i++) + QHashIterator iter(*joysticks); + while (iter.hasNext()) + { + iter.next(); + InputDevice *current = iter.value(); + current->closeSDLDevice(); + } + /*for (int i=0; i < SDL_NumJoysticks(); i++) { if (SDL_JoystickOpened(i) && joysticks->value(i)) @@ -52,7 +83,7 @@ void SDLEventReader::closeSDL() SDL_Joystick *handle = (joysticks->value(i))->getSDLHandle(); SDL_JoystickClose(handle); } - } + }*/ #endif // Clear any pending events diff --git a/src/sdleventreader.h b/src/sdleventreader.h index 2b421d208..4ad7cc4c4 100644 --- a/src/sdleventreader.h +++ b/src/sdleventreader.h @@ -10,12 +10,13 @@ #endif #include "joystick.h" +#include "inputdevice.h" class SDLEventReader : public QObject { Q_OBJECT public: - explicit SDLEventReader(QHash *joysticks, QObject *parent = 0); + explicit SDLEventReader(QHash *joysticks, QObject *parent = 0); ~SDLEventReader(); SDL_Event& getCurrentEvent(); bool isSDLOpen(); @@ -26,9 +27,9 @@ class SDLEventReader : public QObject void clearEvents(); #ifdef USE_SDL_2 - QHash *joysticks; + QHash *joysticks; #else - QHash *joysticks; + QHash *joysticks; #endif SDL_Event currentEvent; bool sdlIsOpen; diff --git a/src/setjoystick.cpp b/src/setjoystick.cpp index 52255062a..55933b538 100644 --- a/src/setjoystick.cpp +++ b/src/setjoystick.cpp @@ -2,13 +2,14 @@ #include #include "setjoystick.h" +#include "inputdevice.h" -SetJoystick::SetJoystick(SDL_Joystick *joyhandle, int index, QObject *parent) : +SetJoystick::SetJoystick(InputDevice *device, int index, QObject *parent) : QObject(parent) { - this->joyhandle = joyhandle; + this->device = device; this->index = index; - this->reset(); + reset(); } SetJoystick::~SetJoystick() @@ -49,15 +50,12 @@ void SetJoystick::refreshButtons() { deleteButtons(); - for (int i=0; i < SDL_JoystickNumButtons(joyhandle); i++) + //for (int i=0; i < SDL_JoystickNumButtons(joyhandle); i++) + for (int i=0; i < device->getNumberRawButtons(); i++) { JoyButton *button = new JoyButton (i, index, this); buttons.insert(i, button); - connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); - connect(button, SIGNAL(setAssignmentChanged(int,int,int)), this, SLOT(propogateSetButtonAssociation(int,int,int))); - connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetButtonClick(int))); - connect(button, SIGNAL(released(int)), this, SLOT(propogateSetButtonRelease(int))); - connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetButtonNameChange())); + enableButtonConnections(button); } } @@ -65,27 +63,12 @@ void SetJoystick::refreshAxes() { deleteAxes(); - for (int i=0; i < SDL_JoystickNumAxes(joyhandle); i++) + //for (int i=0; i < SDL_JoystickNumAxes(joyhandle); i++) + for (int i=0; i < device->getNumberRawAxes(); i++) { JoyAxis *axis = new JoyAxis(i, index, this); axes.insert(i, axis); - - connect(axis, SIGNAL(throttleChangePropogated(int)), this, SLOT(propogateSetAxisThrottleSetting(int))); - connect(axis, SIGNAL(axisNameChanged()), this, SLOT(propogateSetAxisNameChange())); - - JoyAxisButton *button = axis->getNAxisButton(); - connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); - connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetAxisButtonAssociation(int,int,int,int))); - connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetAxisButtonClick(int))); - connect(button, SIGNAL(released(int)), this, SLOT(propogateSetAxisButtonRelease(int))); - connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetAxisButtonNameChange())); - - button = axis->getPAxisButton(); - connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); - connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetAxisButtonAssociation(int,int,int,int))); - connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetAxisButtonClick(int))); - connect(button, SIGNAL(released(int)), this, SLOT(propogateSetAxisButtonRelease(int))); - connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetAxisButtonNameChange())); + enableAxisConnections(axis); } } @@ -93,23 +76,12 @@ void SetJoystick::refreshHats() { deleteHats(); - for (int i=0; i < SDL_JoystickNumHats(joyhandle); i++) + //for (int i=0; i < SDL_JoystickNumHats(joyhandle); i++) + for (int i=0; i < device->getNumberRawHats(); i++) { JoyDPad *dpad = new JoyDPad(i, index, this); - connect(dpad, SIGNAL(dpadNameChanged()), this, SLOT(propogateSetDPadNameChange())); hats.insert(i, dpad); - QHash *buttons = dpad->getJoyButtons(); - QHashIterator iter(*buttons); - while (iter.hasNext()) - { - JoyDPadButton *button = iter.next().value(); - connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); - connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetDPadButtonAssociation(int,int,int,int))); - - connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetDPadButtonClick(int))); - connect(button, SIGNAL(released(int)), this, SLOT(propogateSetDPadButtonRelease(int))); - connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetDPadButtonNameChange())); - } + enableHatConnections(dpad); } } @@ -227,11 +199,6 @@ void SetJoystick::reset() refreshHats(); } -SDL_Joystick* SetJoystick::getSDLHandle() -{ - return joyhandle; -} - void SetJoystick::propogateSetChange(int index) { emit setChangeActivated(index); @@ -795,3 +762,57 @@ void SetJoystick::setIgnoreEventState(bool ignore) } } + +void SetJoystick::propogateSetAxisActivated(int value) +{ + JoyAxis *axis = static_cast(sender()); + emit setAxisActivated(this->index, axis->getIndex(), value); +} + +void SetJoystick::enableButtonConnections(JoyButton *button) +{ + connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); + connect(button, SIGNAL(setAssignmentChanged(int,int,int)), this, SLOT(propogateSetButtonAssociation(int,int,int))); + connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetButtonClick(int))); + connect(button, SIGNAL(released(int)), this, SLOT(propogateSetButtonRelease(int))); + connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetButtonNameChange())); +} + +void SetJoystick::enableAxisConnections(JoyAxis *axis) +{ + connect(axis, SIGNAL(throttleChangePropogated(int)), this, SLOT(propogateSetAxisThrottleSetting(int))); + connect(axis, SIGNAL(axisNameChanged()), this, SLOT(propogateSetAxisNameChange())); + connect(axis, SIGNAL(active(int)), this, SLOT(propogateSetAxisActivated(int))); + + JoyAxisButton *button = axis->getNAxisButton(); + connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); + connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetAxisButtonAssociation(int,int,int,int))); + connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetAxisButtonClick(int))); + connect(button, SIGNAL(released(int)), this, SLOT(propogateSetAxisButtonRelease(int))); + connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetAxisButtonNameChange())); + + button = axis->getPAxisButton(); + connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); + connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetAxisButtonAssociation(int,int,int,int))); + connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetAxisButtonClick(int))); + connect(button, SIGNAL(released(int)), this, SLOT(propogateSetAxisButtonRelease(int))); + connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetAxisButtonNameChange())); +} + +void SetJoystick::enableHatConnections(JoyDPad *dpad) +{ + connect(dpad, SIGNAL(dpadNameChanged()), this, SLOT(propogateSetDPadNameChange())); + + QHash *buttons = dpad->getJoyButtons(); + QHashIterator iter(*buttons); + while (iter.hasNext()) + { + JoyDPadButton *button = iter.next().value(); + connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); + connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetDPadButtonAssociation(int,int,int,int))); + + connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetDPadButtonClick(int))); + connect(button, SIGNAL(released(int)), this, SLOT(propogateSetDPadButtonRelease(int))); + connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetDPadButtonNameChange())); + } +} diff --git a/src/setjoystick.h b/src/setjoystick.h index 3cffab09c..b7e02031b 100644 --- a/src/setjoystick.h +++ b/src/setjoystick.h @@ -18,14 +18,15 @@ #include "joybutton.h" #include "vdpad.h" +class InputDevice; + class SetJoystick : public QObject { Q_OBJECT public: - explicit SetJoystick(SDL_Joystick *joyhandle, int index, QObject *parent=0); + explicit SetJoystick(InputDevice *device, int index, QObject *parent=0); ~SetJoystick(); - SDL_Joystick* getSDLHandle (); JoyAxis* getJoyAxis(int index); JoyButton* getJoyButton(int index); JoyDPad* getJoyDPad(int index); @@ -39,9 +40,9 @@ class SetJoystick : public QObject int getNumberVDPads(); int getIndex(); - void refreshButtons (); - void refreshAxes(); - void refreshHats(); + virtual void refreshButtons (); + virtual void refreshAxes(); + virtual void refreshHats(); void release(); void addControlStick(int index, JoyControlStick *stick); void removeControlStick(int index); @@ -60,6 +61,10 @@ class SetJoystick : public QObject void deleteSticks(); void deleteVDpads(); + void enableButtonConnections(JoyButton *button); + void enableAxisConnections(JoyAxis *axis); + void enableHatConnections(JoyDPad *dpad); + QHash buttons; QHash axes; QHash hats; @@ -67,7 +72,8 @@ class SetJoystick : public QObject QHash vdpads; int index; - SDL_Joystick* joyhandle; + //SDL_Joystick* joyhandle; + InputDevice *device; signals: void setChangeActivated(int index); @@ -80,6 +86,7 @@ class SetJoystick : public QObject void setButtonRelease(int index, int button); void setAxisButtonClick(int setindex, int axis, int button); void setAxisButtonRelease(int setindex, int axis, int button); + void setAxisActivated(int setindex, int axis, int value); void setStickButtonClick(int setindex, int stick, int button); void setStickButtonRelease(int setindex, int stick, int button); void setDPadButtonClick(int setindex, int dpad, int button); @@ -97,14 +104,13 @@ class SetJoystick : public QObject void setVDPadNameChange(int vdpadIndex); public slots: - void reset(); + virtual void reset(); void propogateSetChange(int index); void propogateSetButtonAssociation(int button, int newset, int mode); void propogateSetAxisButtonAssociation(int button, int axis, int newset, int mode); void propogateSetStickButtonAssociation(int button, int stick, int newset, int mode); void propogateSetDPadButtonAssociation(int button, int dpad, int newset, int mode); - protected slots: void propogateSetAxisThrottleSetting(int index); void propogateSetButtonClick(int button); @@ -115,6 +121,7 @@ protected slots: void propogateSetStickButtonRelease(int button); void propogateSetDPadButtonClick(int button); void propogateSetDPadButtonRelease(int button); + void propogateSetAxisActivated(int value); void propogateSetButtonNameChange(); void propogateSetAxisButtonNameChange(); diff --git a/src/vdpad.cpp b/src/vdpad.cpp index e2b1873ff..267a8dc02 100644 --- a/src/vdpad.cpp +++ b/src/vdpad.cpp @@ -73,6 +73,14 @@ QString VDPad::getName(bool forceFullFormat, bool displayName) label.append(dpadName); } + else if (!defaultDPadName.isEmpty()) + { + if (forceFullFormat) + { + label.append(tr("VDPad")).append(" "); + } + label.append(defaultDPadName); + } else { label.append(tr("VDPad")).append(" "); diff --git a/src/xmlconfigreader.cpp b/src/xmlconfigreader.cpp index 93258a0ab..41a4204ce 100644 --- a/src/xmlconfigreader.cpp +++ b/src/xmlconfigreader.cpp @@ -31,7 +31,7 @@ XMLConfigReader::~XMLConfigReader() } } -void XMLConfigReader::setJoystick(Joystick *joystick) +void XMLConfigReader::setJoystick(InputDevice *joystick) { this->joystick = joystick; } @@ -50,7 +50,7 @@ void XMLConfigReader::setFileName(QString filename) } } -void XMLConfigReader::configJoystick(Joystick *joystick) +void XMLConfigReader::configJoystick(InputDevice *joystick) { this->joystick = joystick; read(); @@ -71,14 +71,14 @@ bool XMLConfigReader::read() } xml->readNextStartElement(); - if (xml->name() != "joystick") + if (xml->name() != joystick->getXmlName()) { xml->raiseError("Root node is not a joystick"); } while (!xml->atEnd()) { - if (xml->name() == "joystick" && xml->isStartElement()) + if (xml->name() == joystick->getXmlName() && xml->isStartElement()) { joystick->readConfig(xml); } diff --git a/src/xmlconfigreader.h b/src/xmlconfigreader.h index 67faecf18..a15dc0fd0 100644 --- a/src/xmlconfigreader.h +++ b/src/xmlconfigreader.h @@ -5,7 +5,7 @@ #include #include -#include "joystick.h" +#include "inputdevice.h" #include "common.h" class XMLConfigReader : public QObject @@ -14,7 +14,7 @@ class XMLConfigReader : public QObject public: explicit XMLConfigReader(QObject *parent = 0); ~XMLConfigReader(); - void setJoystick(Joystick *joystick); + void setJoystick(InputDevice *joystick); void setFileName(QString filename); bool read(); @@ -24,12 +24,12 @@ class XMLConfigReader : public QObject QXmlStreamReader *xml; QString fileName; QFile *configFile; - Joystick* joystick; + InputDevice* joystick; signals: public slots: - void configJoystick(Joystick *joystick); + void configJoystick(InputDevice *joystick); }; diff --git a/src/xmlconfigwriter.cpp b/src/xmlconfigwriter.cpp index c5d2b8466..aaeaa91c8 100644 --- a/src/xmlconfigwriter.cpp +++ b/src/xmlconfigwriter.cpp @@ -31,7 +31,7 @@ XMLConfigWriter::~XMLConfigWriter() } } -void XMLConfigWriter::write(Joystick *joystick) +void XMLConfigWriter::write(InputDevice *joystick) { if (!configFile->isOpen()) { diff --git a/src/xmlconfigwriter.h b/src/xmlconfigwriter.h index b3727acde..ef5555c96 100644 --- a/src/xmlconfigwriter.h +++ b/src/xmlconfigwriter.h @@ -5,7 +5,7 @@ #include #include -#include "joystick.h" +#include "inputdevice.h" #include "common.h" class XMLConfigWriter : public QObject @@ -20,12 +20,12 @@ class XMLConfigWriter : public QObject QXmlStreamWriter *xml; QString fileName; QFile *configFile; - Joystick* joystick; + InputDevice* joystick; signals: public slots: - void write(Joystick* joystick); + void write(InputDevice* joystick); };