From b014fdf424c53e5b46dc7a431c4d556536c0d121 Mon Sep 17 00:00:00 2001 From: Rosalie Wanders Date: Thu, 30 Jan 2025 22:01:29 +0100 Subject: [PATCH] RMG-Input: detect devices using serial and path instead of device index --- Source/RMG-Input/Thread/SDLThread.cpp | 31 ++++- Source/RMG-Input/Thread/SDLThread.hpp | 2 +- Source/RMG-Input/UserInterface/MainDialog.cpp | 85 ++++++------- Source/RMG-Input/UserInterface/MainDialog.hpp | 30 ++--- .../UserInterface/Widget/ControllerWidget.cpp | 119 +++++++++++------- .../UserInterface/Widget/ControllerWidget.hpp | 8 +- Source/RMG-Input/Utilities/InputDevice.cpp | 38 ++++-- Source/RMG-Input/Utilities/InputDevice.hpp | 22 +--- Source/RMG-Input/common.hpp | 18 +++ Source/RMG-Input/main.cpp | 8 +- 10 files changed, 214 insertions(+), 147 deletions(-) diff --git a/Source/RMG-Input/Thread/SDLThread.cpp b/Source/RMG-Input/Thread/SDLThread.cpp index 7b012dec..2e4acf4f 100644 --- a/Source/RMG-Input/Thread/SDLThread.cpp +++ b/Source/RMG-Input/Thread/SDLThread.cpp @@ -63,22 +63,43 @@ void SDLThread::run(void) // force re-fresh joystick list SDL_JoystickUpdate(); + QString name; + QString path; + QString serial; + + SDL_GameController* controller; + SDL_Joystick* joystick; + for (int i = 0; i < SDL_NumJoysticks(); i++) { - const char* name; - if (SDL_IsGameController(i)) { - name = SDL_GameControllerNameForIndex(i); + controller = SDL_GameControllerOpen(i); + if (controller == nullptr) + { // skip invalid controllers + continue; + } + name = SDL_GameControllerName(controller); + path = SDL_GameControllerPath(controller); + serial = SDL_GameControllerGetSerial(controller); + SDL_GameControllerClose(controller); } else { - name = SDL_JoystickNameForIndex(i); + joystick = SDL_JoystickOpen(i); + if (joystick == nullptr) + { // skip invalid joysticks + continue; + } + name = SDL_JoystickName(joystick); + path = SDL_JoystickPath(joystick); + serial = SDL_JoystickGetSerial(joystick); + SDL_JoystickClose(joystick); } if (name != nullptr) { - emit this->OnInputDeviceFound(QString(name), i); + emit this->OnInputDeviceFound(name, path, serial, i); } } this->currentAction = SDLThreadAction::None; diff --git a/Source/RMG-Input/Thread/SDLThread.hpp b/Source/RMG-Input/Thread/SDLThread.hpp index 0a0a0e94..59d29d6a 100644 --- a/Source/RMG-Input/Thread/SDLThread.hpp +++ b/Source/RMG-Input/Thread/SDLThread.hpp @@ -40,7 +40,7 @@ private: SDLThreadAction currentAction = SDLThreadAction::None; signals: - void OnInputDeviceFound(QString, int); + void OnInputDeviceFound(QString name, QString path, QString serial, int number); void OnDeviceSearchFinished(void); }; } // namespace Thread diff --git a/Source/RMG-Input/UserInterface/MainDialog.cpp b/Source/RMG-Input/UserInterface/MainDialog.cpp index efcdfbec..f19aebc1 100644 --- a/Source/RMG-Input/UserInterface/MainDialog.cpp +++ b/Source/RMG-Input/UserInterface/MainDialog.cpp @@ -16,10 +16,14 @@ #include #include +Q_DECLARE_METATYPE(SDLDevice); + using namespace UserInterface; MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romConfig) : QDialog(parent) { + qRegisterMetaType(); + this->setupUi(this); this->setWindowIcon(QIcon(":Resource/RMG.png")); @@ -65,12 +69,12 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romCo // so we only have to expose it there if (controllerWidget == this->controllerWidgets.last()) { - controllerWidget->AddInputDevice("Voice Recognition Unit", (int)InputDeviceType::EmulateVRU); + controllerWidget->AddInputDevice({"Voice Recognition Unit", "", "", (int)InputDeviceType::EmulateVRU}); } #endif // VRU - controllerWidget->AddInputDevice("None", (int)InputDeviceType::None); - controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic); - controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard); + controllerWidget->AddInputDevice({"None", "", "", (int)InputDeviceType::None}); + controllerWidget->AddInputDevice({"Automatic", "", "", (int)InputDeviceType::Automatic}); + controllerWidget->AddInputDevice({"Keyboard", "", "", (int)InputDeviceType::Keyboard}); controllerWidget->SetInitialized(true); } @@ -87,73 +91,71 @@ MainDialog::~MainDialog() this->closeInputDevice(); } -void MainDialog::addInputDevice(QString deviceName, int deviceNum) +void MainDialog::addInputDevice(SDLDevice device) { for (auto& controllerWidget : this->controllerWidgets) { - controllerWidget->AddInputDevice(deviceName, deviceNum); + controllerWidget->AddInputDevice(device); } } -void MainDialog::removeInputDevice(QString deviceName, int deviceNum) +void MainDialog::removeInputDevice(SDLDevice device) { for (auto& controllerWidget : this->controllerWidgets) { - controllerWidget->RemoveInputDevice(deviceName, deviceNum); + controllerWidget->RemoveInputDevice(device); } } -void MainDialog::openInputDevice(QString deviceName, int deviceNum) +void MainDialog::openInputDevice(SDLDevice device) { SDL_JoystickID joystickId; Widget::ControllerWidget* controllerWidget; controllerWidget = this->controllerWidgets.at(this->tabWidget->currentIndex()); // we don't need to open a keyboard or VRU - if (deviceNum == (int)InputDeviceType::None || - deviceNum == (int)InputDeviceType::Keyboard || - deviceNum == (int)InputDeviceType::EmulateVRU) + if (device.number == (int)InputDeviceType::None || + device.number == (int)InputDeviceType::Keyboard || + device.number == (int)InputDeviceType::EmulateVRU) { - this->currentDeviceName = ""; - this->currentDeviceNum = deviceNum; - controllerWidget->SetCurrentJoystickID(this->currentDeviceNum); + this->currentDevice = { "", "", "", device.number }; + controllerWidget->SetCurrentJoystickID(this->currentDevice.number); controllerWidget->SetCurrentJoystick(nullptr, nullptr); return; } // handle automatic mode - if (deviceNum == (int)InputDeviceType::Automatic) + if (device.number == (int)InputDeviceType::Automatic) { int currentIndex = this->tabWidget->currentIndex(); if (currentIndex < this->inputDeviceList.size()) { // use device when there's one - deviceNum = this->inputDeviceList.at(currentIndex).deviceNum; + device.number = this->inputDeviceList.at(currentIndex).number; } else { // no device found, fallback to keyboard - this->currentDeviceName = ""; - this->currentDeviceNum = (int)InputDeviceType::Keyboard; - controllerWidget->SetCurrentJoystickID(this->currentDeviceNum); + this->currentDevice = { "", "", "", (int)InputDeviceType::Keyboard }; + controllerWidget->SetCurrentJoystickID(this->currentDevice.number); controllerWidget->SetCurrentJoystick(nullptr, nullptr); return; } } int controllerMode = CoreSettingsGetIntValue(SettingsID::Input_ControllerMode); - if ((controllerMode == 0 && SDL_IsGameController(deviceNum) == SDL_TRUE) || + if ((controllerMode == 0 && SDL_IsGameController(device.number) == SDL_TRUE) || (controllerMode == 2)) { this->currentJoystick = nullptr; - this->currentController = SDL_GameControllerOpen(deviceNum); + this->currentController = SDL_GameControllerOpen(device.number); } else if (controllerMode == 0 || controllerMode == 1) { - this->currentJoystick = SDL_JoystickOpen(deviceNum); + this->currentJoystick = SDL_JoystickOpen(device.number); this->currentController = nullptr; } - this->currentDeviceNum = deviceNum; - joystickId = SDL_JoystickGetDeviceInstanceID(deviceNum); + this->currentDevice = device; + joystickId = SDL_JoystickGetDeviceInstanceID(device.number); controllerWidget->SetCurrentJoystickID(joystickId); controllerWidget->SetIsCurrentJoystickGameController(currentController != nullptr); controllerWidget->SetCurrentJoystick(this->currentJoystick, this->currentController); @@ -208,7 +210,7 @@ void MainDialog::on_InputPollTimer_triggered() (this->currentController != nullptr && !SDL_GameControllerGetAttached(this->currentController))) { this->closeInputDevice(); - this->openInputDevice(this->currentDeviceName, this->currentDeviceNum); + this->openInputDevice(this->currentDevice); } // process SDL events @@ -221,7 +223,7 @@ void MainDialog::on_InputPollTimer_triggered() controllerWidget->on_MainDialog_SdlEventPollFinished(); } -void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget* widget, QString deviceName, int deviceNum) +void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget* widget, SDLDevice device) { Widget::ControllerWidget* currentWidget; currentWidget = controllerWidgets.at(this->tabWidget->currentIndex()); @@ -236,11 +238,11 @@ void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget* this->closeInputDevice(); // only open device when needed - if (deviceNum != (int)InputDeviceType::None && - deviceNum != (int)InputDeviceType::Keyboard && - deviceNum != (int)InputDeviceType::EmulateVRU) + if (device.number != (int)InputDeviceType::None && + device.number != (int)InputDeviceType::Keyboard && + device.number != (int)InputDeviceType::EmulateVRU) { - this->openInputDevice(deviceName, deviceNum); + this->openInputDevice(device); } } @@ -274,8 +276,7 @@ void MainDialog::on_ControllerWidget_UserProfileRemoved(QString name, QString se void MainDialog::on_tabWidget_currentChanged(int index) { - QString deviceName; - int deviceNum; + SDLDevice device; Widget::ControllerWidget* controllerWidget; // save previous tab's user profile @@ -299,20 +300,20 @@ void MainDialog::on_tabWidget_currentChanged(int index) controllerWidget->LoadUserProfileSettings(); // retrieve current input device - controllerWidget->GetCurrentInputDevice(deviceName, deviceNum); + controllerWidget->GetCurrentInputDevice(device); // only open device when needed - if (deviceNum != (int)InputDeviceType::None && - deviceNum != (int)InputDeviceType::Keyboard && - deviceNum != (int)InputDeviceType::EmulateVRU) + if (device.number != (int)InputDeviceType::None && + device.number != (int)InputDeviceType::Keyboard && + device.number != (int)InputDeviceType::EmulateVRU) { - this->openInputDevice(deviceName, deviceNum); + this->openInputDevice(device); } } -void MainDialog::on_SDLThread_DeviceFound(QString deviceName, int deviceNum) +void MainDialog::on_SDLThread_DeviceFound(QString name, QString path, QString serial, int number) { - inputDevice_t inputDevice = {deviceName, deviceNum}; + SDLDevice inputDevice = {name.toStdString(), path.toStdString(), serial.toStdString(), number}; this->inputDeviceList.append(inputDevice); } @@ -324,14 +325,14 @@ void MainDialog::on_SDLThread_DeviceSearchFinished(void) { if (!this->oldInputDeviceList.contains(inputDevice)) { - this->addInputDevice(inputDevice.deviceName, inputDevice.deviceNum); + this->addInputDevice(inputDevice); } } for (auto& inputDevice : this->oldInputDeviceList) { if (!this->inputDeviceList.contains(inputDevice)) { - this->removeInputDevice(inputDevice.deviceName, inputDevice.deviceNum); + this->removeInputDevice(inputDevice); } } diff --git a/Source/RMG-Input/UserInterface/MainDialog.hpp b/Source/RMG-Input/UserInterface/MainDialog.hpp index 8594fe28..41f88d7a 100644 --- a/Source/RMG-Input/UserInterface/MainDialog.hpp +++ b/Source/RMG-Input/UserInterface/MainDialog.hpp @@ -11,6 +11,7 @@ #define MAINDIALOG_HPP #include +#include "common.hpp" #include "ui_MainDialog.h" #include "Widget/ControllerWidget.hpp" @@ -23,39 +24,26 @@ class MainDialog : public QDialog, private Ui::MainDialog { Q_OBJECT private: - struct inputDevice_t - { - QString deviceName; - int deviceNum; - - bool operator== (inputDevice_t other) const - { - return other.deviceNum == deviceNum && - other.deviceName == deviceName; - } - }; - QTimer* inputPollTimer; Thread::SDLThread* sdlThread; - QList oldInputDeviceList; - QList inputDeviceList; + QList oldInputDeviceList; + QList inputDeviceList; bool updatingDeviceList = false; QList controllerWidgets; SDL_Joystick* currentJoystick = nullptr; SDL_GameController* currentController = nullptr; - QString currentDeviceName; - int currentDeviceNum = 0; + SDLDevice currentDevice; int previousTabWidgetIndex = 0; EventFilter* eventFilter; - void addInputDevice(QString, int); - void removeInputDevice(QString, int); + void addInputDevice(SDLDevice device); + void removeInputDevice(SDLDevice device); - void openInputDevice(QString, int); + void openInputDevice(SDLDevice device); void closeInputDevice(); public: @@ -65,7 +53,7 @@ public: public slots: void on_InputPollTimer_triggered(); - void on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*, QString, int); + void on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*, SDLDevice); void on_ControllerWidget_RefreshInputDevicesButtonClicked(); void on_ControllerWidget_UserProfileAdded(QString, QString); @@ -73,7 +61,7 @@ public slots: void on_tabWidget_currentChanged(int); - void on_SDLThread_DeviceFound(QString, int); + void on_SDLThread_DeviceFound(QString, QString, QString, int); void on_SDLThread_DeviceSearchFinished(void); private slots: diff --git a/Source/RMG-Input/UserInterface/Widget/ControllerWidget.cpp b/Source/RMG-Input/UserInterface/Widget/ControllerWidget.cpp index 601a91b6..75bb3278 100644 --- a/Source/RMG-Input/UserInterface/Widget/ControllerWidget.cpp +++ b/Source/RMG-Input/UserInterface/Widget/ControllerWidget.cpp @@ -243,10 +243,10 @@ void ControllerWidget::initializeMiscButtons() bool ControllerWidget::isCurrentDeviceKeyboard() { - int deviceNum = this->inputDeviceComboBox->currentData().toInt(); + SDLDevice device = this->inputDeviceComboBox->currentData().value(); - return deviceNum == (int)InputDeviceType::Automatic || - deviceNum == (int)InputDeviceType::Keyboard; + return device.number == (int)InputDeviceType::Automatic || + device.number == (int)InputDeviceType::Keyboard; } bool ControllerWidget::isCurrentDeviceNotFound() @@ -502,35 +502,30 @@ void ControllerWidget::showErrorMessage(QString text, QString details) msgBox.exec(); } -void ControllerWidget::AddInputDevice(QString deviceName, int deviceNum) +void ControllerWidget::AddInputDevice(SDLDevice device) { + QString deviceName = QString::fromStdString(device.name); QString name = deviceName; - if (deviceNum >= 0) + if (device.number >= 0) { name += " ("; - name += QString::number(deviceNum); + name += QString::number(device.number); name += ")"; } this->inputDeviceNameList.append(deviceName); - this->inputDeviceComboBox->addItem(name, deviceNum); + this->inputDeviceComboBox->addItem(name, QVariant::fromValue(device)); } -void ControllerWidget::RemoveInputDevice(QString deviceName, int deviceNum) +void ControllerWidget::RemoveInputDevice(SDLDevice device) { - inputDeviceNameList.removeOne(deviceName); + inputDeviceNameList.removeOne(QString::fromStdString(device.name)); - for (int i = 0; i < this->inputDeviceComboBox->count(); i++) + int index = this->inputDeviceComboBox->findData(QVariant::fromValue(device)); + if (index >= 0) { - int tmpNum = this->inputDeviceComboBox->itemData(i).toInt(); - QString tmpName = this->inputDeviceComboBox->itemText(i); - - if (tmpName.contains(deviceName) && deviceNum == tmpNum) - { - this->inputDeviceComboBox->removeItem(i); - break; - } + this->inputDeviceComboBox->removeItem(index); } } @@ -562,7 +557,10 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString) bool isPluggedIn = CoreSettingsGetBoolValue(SettingsID::Input_PluggedIn, section); std::string deviceName = CoreSettingsGetStringValue(SettingsID::Input_DeviceName, section); + std::string devicePath = CoreSettingsGetStringValue(SettingsID::Input_DevicePath, section); + std::string deviceSerial = CoreSettingsGetStringValue(SettingsID::Input_DeviceSerial, section); int deviceNum = CoreSettingsGetIntValue(SettingsID::Input_DeviceNum, section); + SDLDevice device = { deviceName, devicePath, deviceSerial, deviceNum }; // do nothing when input device combobox // is empty @@ -574,8 +572,7 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString) // account for old setting if (!isPluggedIn && deviceNum != (int)InputDeviceType::None) { - deviceName = "None"; - deviceNum = (int)InputDeviceType::None; + device = { "None", "", "", (int)InputDeviceType::None }; } // clear (not found) devices first @@ -587,19 +584,53 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString) } int deviceNameIndex = this->inputDeviceComboBox->findText(QString::fromStdString(deviceName), Qt::MatchFlag::MatchStartsWith); - int deviceNumIndex = this->inputDeviceComboBox->findData(deviceNum); + int deviceIndex = -1; + int deviceSerialIndex = -1; + bool needCompatibility = deviceNum >= 0 && devicePath.empty() && deviceSerial.empty(); - if ((deviceNumIndex != -1) && - (this->inputDeviceComboBox->itemText(deviceNumIndex).startsWith(QString::fromStdString(deviceName)))) + int count = this->inputDeviceComboBox->count(); + for (int i = 0; i < count; i++) + { + SDLDevice otherDevice = this->inputDeviceComboBox->itemData(i).value(); + if (needCompatibility) + { // backwards compatibility with inputDeviceComboBox->setCurrentIndex(deviceNumIndex); + this->inputDeviceComboBox->setCurrentIndex(deviceIndex); // force-refresh automatic input device if (deviceNum == (int)InputDeviceType::Automatic) { - this->on_inputDeviceComboBox_currentIndexChanged(deviceNumIndex); + this->on_inputDeviceComboBox_currentIndexChanged(deviceIndex); } } + else if (deviceSerialIndex != -1) + { // name and serial match + this->inputDeviceComboBox->setCurrentIndex(deviceSerialIndex); + } else if (deviceNameIndex != -1) { // name only match this->inputDeviceComboBox->setCurrentIndex(deviceNameIndex); @@ -609,7 +640,7 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString) QString title = QString::fromStdString(deviceName); title += " (not found)"; this->inputDeviceNameList.append(QString::fromStdString(deviceName)); - this->inputDeviceComboBox->addItem(title, deviceNum); + this->inputDeviceComboBox->addItem(title, QVariant::fromValue(device)); this->inputDeviceComboBox->setCurrentIndex(this->inputDeviceNameList.count() - 1); } } @@ -624,19 +655,17 @@ void ControllerWidget::ClearControllerImage() this->controllerImageWidget->ClearControllerState(); } -void ControllerWidget::GetCurrentInputDevice(QString& deviceName, int& deviceNum, bool ignoreDeviceNotFound) +void ControllerWidget::GetCurrentInputDevice(SDLDevice& device, bool ignoreDeviceNotFound) { int currentIndex = this->inputDeviceComboBox->currentIndex(); if (this->isCurrentDeviceNotFound() && !ignoreDeviceNotFound) { - deviceName = ""; - deviceNum = -1; + device = { "", "", "", -1 }; } else { - deviceName = this->inputDeviceNameList.at(currentIndex); - deviceNum = this->inputDeviceComboBox->itemData(currentIndex).toInt(); + device = this->inputDeviceComboBox->itemData(currentIndex).value(); } } @@ -691,22 +720,20 @@ void ControllerWidget::on_inputDeviceComboBox_currentIndexChanged(int value) return; } - QString deviceName = this->inputDeviceNameList.at(value); - int deviceNum = this->inputDeviceComboBox->itemData(value).toInt(); + SDLDevice device = this->inputDeviceComboBox->itemData(value).value(); this->ClearControllerImage(); if (this->isCurrentDeviceNotFound()) { - deviceName = ""; - deviceNum = -1; + device = { "", "", "", -1 }; } // set plugged in state - this->setPluggedIn(deviceNum != (int)InputDeviceType::None && - deviceNum != (int)InputDeviceType::EmulateVRU); + this->setPluggedIn(device.number != (int)InputDeviceType::None && + device.number != (int)InputDeviceType::EmulateVRU); - emit this->CurrentInputDeviceChanged(this, deviceName, deviceNum); + emit this->CurrentInputDeviceChanged(this, device); } void ControllerWidget::on_inputDeviceRefreshButton_clicked() @@ -853,7 +880,8 @@ void ControllerWidget::on_resetButton_clicked() void ControllerWidget::on_optionsButton_clicked() { - bool isKeyboard = this->inputDeviceComboBox->currentData().toInt() == (int)InputDeviceType::Keyboard; + SDLDevice device = this->inputDeviceComboBox->currentData().value(); + bool isKeyboard = device.number == (int)InputDeviceType::Keyboard; OptionsDialog dialog(this, this->optionsDialogSettings, isKeyboard ? nullptr : this->currentJoystick, @@ -1680,6 +1708,8 @@ void ControllerWidget::SaveDefaultSettings() CoreSettingsSetValue(SettingsID::Input_PluggedIn, section, false); CoreSettingsSetValue(SettingsID::Input_DeviceName, section, std::string("None")); CoreSettingsSetValue(SettingsID::Input_DeviceNum, section, (int)InputDeviceType::None); + CoreSettingsSetValue(SettingsID::Input_DevicePath, section, std::string("")); + CoreSettingsSetValue(SettingsID::Input_DeviceSerial, section, std::string("")); CoreSettingsSetValue(SettingsID::Input_Deadzone, section, 9); CoreSettingsSetValue(SettingsID::Input_Sensitivity, section, 100); CoreSettingsSetValue(SettingsID::Input_Pak, section, 0); @@ -1760,8 +1790,7 @@ void ControllerWidget::SaveUserProfileSettings() void ControllerWidget::SaveSettings(QString section) { - QString deviceName; - int deviceNum; + SDLDevice device; std::string mainSettingsSection = this->settingsSection.toStdString(); std::string sectionStr = section.toStdString(); @@ -1790,11 +1819,13 @@ void ControllerWidget::SaveSettings(QString section) CoreSettingsSetValue(SettingsID::Input_UseGameProfile, this->gameSection.toStdString(), false); } - this->GetCurrentInputDevice(deviceName, deviceNum, true); + this->GetCurrentInputDevice(device, true); CoreSettingsSetValue(SettingsID::Input_PluggedIn, sectionStr, this->IsPluggedIn()); - CoreSettingsSetValue(SettingsID::Input_DeviceName, sectionStr, deviceName.toStdString()); - CoreSettingsSetValue(SettingsID::Input_DeviceNum, sectionStr, deviceNum); + CoreSettingsSetValue(SettingsID::Input_DeviceName, sectionStr, device.name); + CoreSettingsSetValue(SettingsID::Input_DeviceNum, sectionStr, device.number); + CoreSettingsSetValue(SettingsID::Input_DevicePath, sectionStr, device.path); + CoreSettingsSetValue(SettingsID::Input_DeviceSerial, sectionStr, device.serial); CoreSettingsSetValue(SettingsID::Input_Deadzone, sectionStr, this->deadZoneSlider->value()); CoreSettingsSetValue(SettingsID::Input_Sensitivity, sectionStr, this->analogStickSensitivitySlider->value()); CoreSettingsSetValue(SettingsID::Input_Pak, sectionStr, this->optionsDialogSettings.ControllerPak); diff --git a/Source/RMG-Input/UserInterface/Widget/ControllerWidget.hpp b/Source/RMG-Input/UserInterface/Widget/ControllerWidget.hpp index fbd0193a..0f80ed65 100644 --- a/Source/RMG-Input/UserInterface/Widget/ControllerWidget.hpp +++ b/Source/RMG-Input/UserInterface/Widget/ControllerWidget.hpp @@ -117,15 +117,15 @@ public: ControllerWidget(QWidget* parent, EventFilter* eventFilter); ~ControllerWidget(); - void AddInputDevice(QString deviceName, int deviceNum); - void RemoveInputDevice(QString deviceName, int deviceNum); + void AddInputDevice(SDLDevice device); + void RemoveInputDevice(SDLDevice device); void CheckInputDeviceSettings(); void CheckInputDeviceSettings(QString section); void DrawControllerImage(); void ClearControllerImage(); - void GetCurrentInputDevice(QString& deviceName, int& deviceNum, bool ignoreDeviceNotFound = false); + void GetCurrentInputDevice(SDLDevice& device, bool ignoreDeviceNotFound = false); bool IsPluggedIn(); void SetOnlyLoadGameProfile(bool value); @@ -179,7 +179,7 @@ public slots: void on_MainDialog_SdlEventPollFinished(); signals: - void CurrentInputDeviceChanged(ControllerWidget* widget, QString deviceName, int deviceNum); + void CurrentInputDeviceChanged(ControllerWidget* widget, SDLDevice device); void RefreshInputDevicesButtonClicked(); void UserProfileAdded(QString name, QString section); diff --git a/Source/RMG-Input/Utilities/InputDevice.cpp b/Source/RMG-Input/Utilities/InputDevice.cpp index 1424e7aa..e50df448 100644 --- a/Source/RMG-Input/Utilities/InputDevice.cpp +++ b/Source/RMG-Input/Utilities/InputDevice.cpp @@ -78,7 +78,7 @@ bool InputDevice::HasOpenDevice() return this->hasOpenDevice; } -void InputDevice::OpenDevice(std::string name, int num) +void InputDevice::OpenDevice(std::string name, std::string path, std::string serial, int num) { // wait until SDLThread is done first while (this->sdlThread->GetCurrentAction() != SDLThreadAction::None) @@ -87,8 +87,7 @@ void InputDevice::OpenDevice(std::string name, int num) } this->foundDevicesWithNameMatch.clear(); - this->desiredDeviceName = name; - this->desiredDeviceNum = num; + this->desiredDevice = {name, path, serial, num}; this->isOpeningDevice = true; // tell SDLThread to query input devices @@ -117,16 +116,18 @@ bool InputDevice::CloseDevice() return true; } -void InputDevice::on_SDLThread_DeviceFound(QString name, int number) +void InputDevice::on_SDLThread_DeviceFound(QString name, QString path, QString serial, int number) { if ((!this->isOpeningDevice) || - (this->desiredDeviceName != name.toStdString())) + (this->desiredDevice.name != name.toStdString())) { return; } SDLDevice device; device.name = name.toStdString(); + device.path = path.toStdString(); + device.serial = serial.toStdString(); device.number = number; this->foundDevicesWithNameMatch.push_back(device); @@ -150,18 +151,35 @@ void InputDevice::on_SDLThread_DeviceSearchFinished(void) // try to find exact match SDLDevice device; - device.name = this->desiredDeviceName; - device.number = this->desiredDeviceNum; + bool hasDevice = false; - auto iter = std::find(this->foundDevicesWithNameMatch.begin(), this->foundDevicesWithNameMatch.end(), device); + auto iter = std::find(this->foundDevicesWithNameMatch.begin(), this->foundDevicesWithNameMatch.end(), this->desiredDevice); if (iter != this->foundDevicesWithNameMatch.end()) { // use exact match device.name = iter->name; + device.path = iter->path; + device.serial = iter->serial; device.number = iter->number; } else - { // no exact match, use first with name match - device = this->foundDevicesWithNameMatch.at(0); + { // no exact match, try to find name + serial match first + if (!this->desiredDevice.serial.empty()) + { // only try serial match when it's not empty + for (const auto& deviceNameMatch : this->foundDevicesWithNameMatch) + { + if (deviceNameMatch.serial == this->desiredDevice.serial) + { + device = deviceNameMatch; + hasDevice = true; + break; + } + } + } + + if (!hasDevice) + { // fallback to name only match + device = this->foundDevicesWithNameMatch.at(0); + } } this->joystick = SDL_JoystickOpen(device.number); diff --git a/Source/RMG-Input/Utilities/InputDevice.hpp b/Source/RMG-Input/Utilities/InputDevice.hpp index e4be10f2..50ccff1e 100644 --- a/Source/RMG-Input/Utilities/InputDevice.hpp +++ b/Source/RMG-Input/Utilities/InputDevice.hpp @@ -41,8 +41,8 @@ public: // returns whether a device has been opened bool HasOpenDevice(void); - // tries to open device with given name & num - void OpenDevice(std::string name, int num); + // tries to open device with given name, path, serial & num + void OpenDevice(std::string name, std::string path, std::string serial, int num); // returns whether we're still trying to open the device bool IsOpeningDevice(void); @@ -51,18 +51,6 @@ public: bool CloseDevice(void); private: - struct SDLDevice - { - std::string name; - int number; - - bool operator== (SDLDevice other) - { - return other.name == name && - other.number == number; - } - }; - SDL_Joystick* joystick = nullptr; SDL_GameController* gameController = nullptr; @@ -71,13 +59,11 @@ private: Thread::SDLThread* sdlThread = nullptr; - std::string desiredDeviceName; - int desiredDeviceNum; - + SDLDevice desiredDevice; std::vector foundDevicesWithNameMatch; private slots: - void on_SDLThread_DeviceFound(QString, int); + void on_SDLThread_DeviceFound(QString name, QString path, QString serial, int number); void on_SDLThread_DeviceSearchFinished(void); }; } // namespace Utilities diff --git a/Source/RMG-Input/common.hpp b/Source/RMG-Input/common.hpp index 76552ad4..b1d39b7e 100644 --- a/Source/RMG-Input/common.hpp +++ b/Source/RMG-Input/common.hpp @@ -10,6 +10,8 @@ #ifndef COMMON_HPP #define COMMON_HPP +#include + #define SDL_AXIS_PEAK 32767 enum class N64ControllerButton @@ -66,4 +68,20 @@ enum class N64ControllerPak None, }; +struct SDLDevice +{ + std::string name; + std::string path; + std::string serial; + int number; + + bool operator== (const SDLDevice& other) const + { + return other.name == name && + other.path == path && + other.serial == serial && + other.number == number; + } +}; + #endif // COMMON_HPP diff --git a/Source/RMG-Input/main.cpp b/Source/RMG-Input/main.cpp index 2d5ba7fd..d18ef1f0 100644 --- a/Source/RMG-Input/main.cpp +++ b/Source/RMG-Input/main.cpp @@ -72,6 +72,8 @@ struct InputProfile // input device information std::string DeviceName; + std::string DevicePath; + std::string DeviceSerial; int DeviceNum = -1; std::chrono::time_point LastDeviceCheckTime = std::chrono::high_resolution_clock::now(); @@ -294,6 +296,8 @@ static void load_settings(void) profile->DeadzoneValue = CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section); profile->ControllerPak = (N64ControllerPak)CoreSettingsGetIntValue(SettingsID::Input_Pak, section); profile->DeviceName = CoreSettingsGetStringValue(SettingsID::Input_DeviceName, section); + profile->DevicePath = CoreSettingsGetStringValue(SettingsID::Input_DevicePath, section); + profile->DeviceSerial = CoreSettingsGetStringValue(SettingsID::Input_DeviceSerial, section); profile->DeviceNum = CoreSettingsGetIntValue(SettingsID::Input_DeviceNum, section); profile->GameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section); profile->GameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section); @@ -564,7 +568,7 @@ static void open_controllers(void) if (profile->DeviceNum != (int)InputDeviceType::Keyboard) { - profile->InputDevice.OpenDevice(profile->DeviceName, profile->DeviceNum); + profile->InputDevice.OpenDevice(profile->DeviceName, profile->DevicePath, profile->DeviceSerial, profile->DeviceNum); } } } @@ -1236,7 +1240,7 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys) if (!profile->InputDevice.HasOpenDevice() || !profile->InputDevice.IsAttached()) { - profile->InputDevice.OpenDevice(profile->DeviceName, profile->DeviceNum); + profile->InputDevice.OpenDevice(profile->DeviceName, profile->DevicePath, profile->DeviceSerial, profile->DeviceNum); } } }