/* * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG * Copyright (C) 2020 Rosalie Wanders * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "MainDialog.hpp" #include "Widget/ControllerWidget.hpp" #include "Utilities/QtKeyToSdl2Key.hpp" #include #include #include using namespace UserInterface; MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romConfig) : QDialog(parent) { this->setupUi(this); this->setWindowIcon(QIcon(":Resource/RMG.png")); // setup SDL thread this->sdlThread = sdlThread; connect(this->sdlThread, &Thread::SDLThread::OnInputDeviceFound, this, &MainDialog::on_SDLThread_DeviceFound); connect(this->sdlThread, &Thread::SDLThread::OnDeviceSearchFinished, this, &MainDialog::on_SDLThread_DeviceSearchFinished); // setup EventFilter this->eventFilter = new EventFilter(this); connect(this->eventFilter, &EventFilter::on_EventFilter_KeyPressed, this, &MainDialog::on_EventFilter_KeyPressed); connect(this->eventFilter, &EventFilter::on_EventFilter_KeyReleased, this, &MainDialog::on_EventFilter_KeyReleased); // each tab needs its own ControllerWidget for (int i = 0; i < this->tabWidget->count(); i++) { Widget::ControllerWidget* widget = new Widget::ControllerWidget(this, this->eventFilter); widget->SetOnlyLoadGameProfile(romConfig); widget->SetSettingsSection("Player " + QString::number(i + 1), "Rosalie's Mupen GUI - Input Plugin Profile " + QString::number(i)); widget->LoadSettings(); this->tabWidget->widget(i)->layout()->addWidget(widget); controllerWidgets.push_back(widget); connect(widget, &Widget::ControllerWidget::CurrentInputDeviceChanged, this, &MainDialog::on_ControllerWidget_CurrentInputDeviceChanged); connect(widget, &Widget::ControllerWidget::RefreshInputDevicesButtonClicked, this, &MainDialog::on_ControllerWidget_RefreshInputDevicesButtonClicked); connect(widget, &Widget::ControllerWidget::UserProfileAdded, this, &MainDialog::on_ControllerWidget_UserProfileAdded); connect(widget, &Widget::ControllerWidget::UserProfileRemoved, this, &MainDialog::on_ControllerWidget_UserProfileRemoved); } // always add keyboard device for (auto& controllerWidget : this->controllerWidgets) { #ifdef VRU 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->SetInitialized(true); } // fill device list at least once this->on_ControllerWidget_RefreshInputDevicesButtonClicked(); this->inputPollTimer = new QTimer(this); connect(this->inputPollTimer, &QTimer::timeout, this, &MainDialog::on_InputPollTimer_triggered); this->inputPollTimer->start(50); } MainDialog::~MainDialog() { this->closeInputDevice(); } void MainDialog::addInputDevice(QString deviceName, int deviceNum) { for (auto& controllerWidget : this->controllerWidgets) { controllerWidget->AddInputDevice(deviceName, deviceNum); } } void MainDialog::removeInputDevice(QString deviceName, int deviceNum) { for (auto& controllerWidget : this->controllerWidgets) { controllerWidget->RemoveInputDevice(deviceName, deviceNum); } } void MainDialog::openInputDevice(QString deviceName, int deviceNum) { SDL_JoystickID joystickId; Widget::ControllerWidget* controllerWidget; controllerWidget = this->controllerWidgets.at(this->tabWidget->currentIndex()); // we don't need to open a keyboard if (deviceNum == (int)InputDeviceType::None || deviceNum == (int)InputDeviceType::Keyboard) { this->currentDeviceName = ""; this->currentDeviceNum = deviceNum; controllerWidget->SetCurrentJoystickID(this->currentDeviceNum); return; } // handle automatic mode if (deviceNum == (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; } else { // no device found, fallback to keyboard this->currentDeviceName = ""; this->currentDeviceNum = (int)InputDeviceType::Keyboard; controllerWidget->SetCurrentJoystickID(this->currentDeviceNum); return; } } if (SDL_IsGameController(deviceNum) == SDL_TRUE) { this->currentJoystick = nullptr; this->currentController = SDL_GameControllerOpen(deviceNum); } else { this->currentJoystick = SDL_JoystickOpen(deviceNum); this->currentController = nullptr; } this->currentDeviceNum = deviceNum; joystickId = SDL_JoystickGetDeviceInstanceID(deviceNum); controllerWidget->SetCurrentJoystickID(joystickId); controllerWidget->SetIsCurrentJoystickGameController(currentController != nullptr); } void MainDialog::closeInputDevice() { if (this->currentJoystick != nullptr) { SDL_JoystickClose(this->currentJoystick); this->currentJoystick = nullptr; } if (this->currentController != nullptr) { SDL_GameControllerClose(this->currentController); this->currentController = nullptr; } } void MainDialog::on_InputPollTimer_triggered() { Widget::ControllerWidget* controllerWidget; controllerWidget = controllerWidgets.at(this->tabWidget->currentIndex()); // if the current controller widget // is disabled (by the user), // we don't need to do anything if (!controllerWidget->IsPluggedIn()) { this->sdlThread->SetAction(SDLThreadAction::None); return; } // verify/update the SDL thread action state switch (this->sdlThread->GetCurrentAction()) { case SDLThreadAction::GetInputDevices: // don't do anything when we're querying the input devices return; case SDLThreadAction::None: // when the SDL thread is doing nothing, pump the sdl events instead sdlThread->SetAction(SDLThreadAction::SDLPumpEvents); break; default: break; } // check if controller has been disconnected, // if so, keep trying to re-open it if ((this->currentJoystick != nullptr && !SDL_JoystickGetAttached(this->currentJoystick)) || (this->currentController != nullptr && !SDL_GameControllerGetAttached(this->currentController))) { this->closeInputDevice(); this->openInputDevice(this->currentDeviceName, this->currentDeviceNum); } // process SDL events SDL_Event event; while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, 0, SDL_LASTEVENT) == 1) { controllerWidget->on_MainDialog_SdlEvent(&event); } controllerWidget->on_MainDialog_SdlEventPollFinished(); } void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget* widget, QString deviceName, int deviceNum) { Widget::ControllerWidget* currentWidget; currentWidget = controllerWidgets.at(this->tabWidget->currentIndex()); // ignore input device changes // when it's not the current controllerwidget if (widget != currentWidget) { return; } this->closeInputDevice(); // only open device, // when needed if (deviceNum != (int)InputDeviceType::None && deviceNum != (int)InputDeviceType::Keyboard) { this->openInputDevice(deviceName, deviceNum); } } void MainDialog::on_ControllerWidget_RefreshInputDevicesButtonClicked() { if (this->updatingDeviceList) { return; } this->updatingDeviceList = true; this->inputDeviceList.clear(); this->sdlThread->SetAction(SDLThreadAction::GetInputDevices); } void MainDialog::on_ControllerWidget_UserProfileAdded(QString name, QString section) { for (auto& controllerWidget : this->controllerWidgets) { controllerWidget->AddUserProfile(name, section); } } void MainDialog::on_ControllerWidget_UserProfileRemoved(QString name, QString section) { for (auto& controllerWidget : this->controllerWidgets) { controllerWidget->RemoveUserProfile(name, section); } } void MainDialog::on_tabWidget_currentChanged(int index) { QString deviceName; int deviceNum; Widget::ControllerWidget* controllerWidget; // save previous tab's user profile if (previousTabWidgetIndex != -1 && previousTabWidgetIndex != index) { controllerWidget = controllerWidgets.at(previousTabWidgetIndex); controllerWidget->SaveUserProfileSettings(); } // update previous index previousTabWidgetIndex = index; // prepare switched tab controllerWidget = controllerWidgets.at(index); controllerWidget->ClearControllerImage(); this->closeInputDevice(); // re-load user profile settings controllerWidget->LoadUserProfileSettings(); // retrieve current input device controllerWidget->GetCurrentInputDevice(deviceName, deviceNum); // only open device when needed if (deviceNum != (int)InputDeviceType::None && deviceNum != (int)InputDeviceType::Keyboard) { this->openInputDevice(deviceName, deviceNum); } } void MainDialog::on_SDLThread_DeviceFound(QString deviceName, int deviceNum) { inputDevice_t inputDevice = {deviceName, deviceNum}; this->inputDeviceList.append(inputDevice); } void MainDialog::on_SDLThread_DeviceSearchFinished(void) { // compare inputDeviceList with oldInputDeviceList // and signal the changes for (auto& inputDevice : this->inputDeviceList) { if (!this->oldInputDeviceList.contains(inputDevice)) { this->addInputDevice(inputDevice.deviceName, inputDevice.deviceNum); } } for (auto& inputDevice : this->oldInputDeviceList) { if (!this->inputDeviceList.contains(inputDevice)) { this->removeInputDevice(inputDevice.deviceName, inputDevice.deviceNum); } } // update old device list this->oldInputDeviceList = this->inputDeviceList; // we can refresh safely again this->updatingDeviceList = false; // device search has been completed, // signal that each widget can check device settings for (auto& controllerWidget : this->controllerWidgets) { controllerWidget->CheckInputDeviceSettings(); } } void MainDialog::on_EventFilter_KeyPressed(QKeyEvent *event) { int key = Utilities::QtKeyToSdl2Key(event->key()); int mod = Utilities::QtModKeyToSdl2ModKey(event->modifiers()); SDL_KeyboardEvent keyboardEvent; keyboardEvent.state = SDL_PRESSED; keyboardEvent.type = SDL_KEYDOWN; keyboardEvent.keysym.scancode = (SDL_Scancode)key; keyboardEvent.keysym.sym = (SDL_Keycode)key; keyboardEvent.keysym.mod = mod; SDL_Event sdlEvent; sdlEvent.key = keyboardEvent; sdlEvent.type = SDL_KEYDOWN; SDL_PeepEvents(&sdlEvent, 1, SDL_ADDEVENT, 0, 0); } void MainDialog::on_EventFilter_KeyReleased(QKeyEvent *event) { int key = Utilities::QtKeyToSdl2Key(event->key()); int mod = Utilities::QtModKeyToSdl2ModKey(event->modifiers()); SDL_KeyboardEvent keyboardEvent; keyboardEvent.state = SDL_RELEASED; keyboardEvent.type = SDL_KEYUP; keyboardEvent.keysym.scancode = (SDL_Scancode)key; keyboardEvent.keysym.sym = (SDL_Keycode)key; keyboardEvent.keysym.mod = mod; SDL_Event sdlEvent; sdlEvent.key = keyboardEvent; sdlEvent.type = SDL_KEYUP; SDL_PeepEvents(&sdlEvent, 1, SDL_ADDEVENT, 0, 0); } void MainDialog::accept(void) { Widget::ControllerWidget* controllerWidget; int currentIndex = this->tabWidget->currentIndex(); for (int i = 0; i < this->controllerWidgets.count(); i++) { if (i != currentIndex) { controllerWidget = this->controllerWidgets.at(i); controllerWidget->SaveSettings(); } } // the widget which has focus should be saved last controllerWidget = this->controllerWidgets.at(currentIndex); controllerWidget->SaveSettings(); CoreSettingsSave(); QDialog::accept(); } void MainDialog::reject(void) { for (auto& controllerWidget : this->controllerWidgets) { controllerWidget->RevertSettings(); } CoreSettingsSave(); QDialog::reject(); }