RMG-Input: migrate to SDL3

This commit is contained in:
Rosalie Wanders
2025-09-23 14:30:43 +02:00
parent fb7744625c
commit 40c8e117c1
20 changed files with 555 additions and 662 deletions
+3 -6
View File
@@ -10,8 +10,7 @@ set(CMAKE_SHARED_LIBRARY_PREFIX "")
find_package(Qt6 COMPONENTS Gui Widgets Core Svg REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
find_package(SDL3 REQUIRED)
set(RMG_INPUT_SOURCES
UserInterface/Widget/ControllerWidget.ui
@@ -29,8 +28,7 @@ set(RMG_INPUT_SOURCES
UserInterface/MainDialog.ui
UserInterface/MainDialog.cpp
UserInterface/UIResources.qrc
Utilities/QtKeyToSdl2Key.cpp
Utilities/InputDevice.cpp
Utilities/QtKeyToSdl3Key.cpp
Thread/SDLThread.cpp
Thread/HotkeysThread.cpp
main.cpp
@@ -46,13 +44,12 @@ endif(VRU)
add_library(RMG-Input SHARED ${RMG_INPUT_SOURCES})
target_link_libraries(RMG-Input RMG-Core ${SDL2_LIBRARIES})
target_link_libraries(RMG-Input RMG-Core SDL3::SDL3)
target_include_directories(RMG-Input PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../
${SDL2_INCLUDE_DIRS}
)
target_link_libraries(RMG-Input Qt6::Gui Qt6::Widgets Qt6::Svg)
+46 -16
View File
@@ -8,8 +8,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "SDLThread.hpp"
#include "main.hpp"
#include <SDL.h>
#include <RMG-Core/m64p/api/m64p_types.h>
#include <SDL3/SDL.h>
using namespace Thread;
@@ -61,49 +63,77 @@ void SDLThread::run(void)
case SDLThreadAction::GetInputDevices:
{
// force re-fresh joystick list
SDL_JoystickUpdate();
SDL_UpdateJoysticks();
QString name;
QString path;
QString serial;
QString errorMessage;
SDL_GameController* controller;
SDL_Gamepad* controller;
SDL_Joystick* joystick;
for (int i = 0; i < SDL_NumJoysticks(); i++)
int joysticksCount = 0;
SDL_JoystickID* joysticks = SDL_GetJoysticks(&joysticksCount);
if (joysticks == nullptr)
{
if (SDL_IsGameController(i))
errorMessage = "SDLThread::run() SDL_GetJoysticks Failed: ";
errorMessage += SDL_GetError();
PluginDebugMessage(M64MSG_ERROR, errorMessage.toStdString());
// ensure count is reset
joysticksCount = 0;
}
for (int i = 0; i < joysticksCount; i++)
{
SDL_JoystickID joystickId = joysticks[i];
if (SDL_IsGamepad(joystickId))
{
controller = SDL_GameControllerOpen(i);
controller = SDL_OpenGamepad(joystickId);
if (controller == nullptr)
{ // skip invalid controllers
errorMessage = "SDLThread::run(): SDL_OpenGamepad Failed: ";
errorMessage += SDL_GetError();
PluginDebugMessage(M64MSG_ERROR, errorMessage.toStdString());
continue;
}
name = SDL_GameControllerName(controller);
path = SDL_GameControllerPath(controller);
serial = SDL_GameControllerGetSerial(controller);
SDL_GameControllerClose(controller);
name = SDL_GetGamepadName(controller);
path = SDL_GetGamepadPath(controller);
serial = SDL_GetGamepadSerial(controller);
SDL_CloseGamepad(controller);
}
else
{
joystick = SDL_JoystickOpen(i);
joystick = SDL_OpenJoystick(joystickId);
if (joystick == nullptr)
{ // skip invalid joysticks
errorMessage = "SDLThread::run(): SDL_OpenJoystick Failed: ";
errorMessage += SDL_GetError();
PluginDebugMessage(M64MSG_ERROR, errorMessage.toStdString());
continue;
}
name = SDL_JoystickName(joystick);
path = SDL_JoystickPath(joystick);
serial = SDL_JoystickGetSerial(joystick);
SDL_JoystickClose(joystick);
name = SDL_GetJoystickName(joystick);
path = SDL_GetJoystickPath(joystick);
serial = SDL_GetJoystickSerial(joystick);
SDL_CloseJoystick(joystick);
}
if (name != nullptr)
{
emit this->OnInputDeviceFound(name, path, serial, i);
emit this->OnInputDeviceFound(name, path, serial, joystickId);
}
}
this->currentAction = SDLThreadAction::None;
emit this->OnDeviceSearchFinished();
if (joysticks != nullptr)
{
SDL_free(joysticks);
}
} break;
}
+2 -1
View File
@@ -10,6 +10,7 @@
#ifndef SDLTHREAD_HPP
#define SDLTHREAD_HPP
#include <SDL3/SDL.h>
#include <QThread>
enum class SDLThreadAction
@@ -40,7 +41,7 @@ private:
SDLThreadAction currentAction = SDLThreadAction::None;
signals:
void OnInputDeviceFound(QString name, QString path, QString serial, int number);
void OnInputDeviceFound(QString name, QString path, QString serial, SDL_JoystickID joystickId);
void OnDeviceSearchFinished(void);
};
} // namespace Thread
@@ -105,15 +105,15 @@ void HotkeysDialog::on_MainDialog_SdlEvent(SDL_Event* event)
default:
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_JOYBUTTONDOWN:
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
{
SDL_JoystickID joystickId = -1;
InputType inputType = InputType::Invalid;
int sdlButton = 0;
QString sdlButtonName;
if (event->type == SDL_CONTROLLERBUTTONDOWN)
if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN)
{ // gamepad button
if (!this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
@@ -121,10 +121,10 @@ void HotkeysDialog::on_MainDialog_SdlEvent(SDL_Event* event)
return;
}
joystickId = event->cbutton.which;
joystickId = event->gbutton.which;
inputType = InputType::GamepadButton;
sdlButton = event->cbutton.button;
sdlButtonName = SDL_GameControllerGetStringForButton((SDL_GameControllerButton)sdlButton);
sdlButton = event->gbutton.button;
sdlButtonName = SDL_GetGamepadStringForButton((SDL_GamepadButton)sdlButton);
}
else
{ // joystick button
@@ -157,12 +157,12 @@ void HotkeysDialog::on_MainDialog_SdlEvent(SDL_Event* event)
}
} break;
case SDL_CONTROLLERBUTTONUP:
case SDL_JOYBUTTONUP:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
{
SDL_JoystickID joystickId = -1;
if (event->type == SDL_CONTROLLERBUTTONUP)
if (event->type == SDL_EVENT_GAMEPAD_BUTTON_UP)
{ // gamepad button
if (!this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
@@ -170,7 +170,7 @@ void HotkeysDialog::on_MainDialog_SdlEvent(SDL_Event* event)
return;
}
joystickId = event->cbutton.which;
joystickId = event->gbutton.which;
}
else
{ // joystick button
@@ -198,8 +198,8 @@ void HotkeysDialog::on_MainDialog_SdlEvent(SDL_Event* event)
}
} break;
case SDL_CONTROLLERAXISMOTION:
case SDL_JOYAXISMOTION:
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
{ // gamepad & joystick axis
SDL_JoystickID joystickId = -1;
InputType inputType = InputType::Invalid;
@@ -207,7 +207,7 @@ void HotkeysDialog::on_MainDialog_SdlEvent(SDL_Event* event)
int sdlAxisValue = 0;
QString sdlAxisName;
if (event->type == SDL_CONTROLLERAXISMOTION)
if (event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION)
{ // gamepad axis
if (!this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
@@ -215,11 +215,11 @@ void HotkeysDialog::on_MainDialog_SdlEvent(SDL_Event* event)
return;
}
joystickId = event->caxis.which;
joystickId = event->gaxis.which;
inputType = InputType::GamepadAxis;
sdlAxis = event->caxis.axis;
sdlAxisValue = event->caxis.value;
sdlAxisName = SDL_GameControllerGetStringForAxis((SDL_GameControllerAxis)sdlAxis);
sdlAxis = event->gaxis.axis;
sdlAxisValue = event->gaxis.value;
sdlAxisName = SDL_GetGamepadStringForAxis((SDL_GamepadAxis)sdlAxis);
sdlAxisName += sdlAxisValue > 0 ? "+" : "-";
}
else
@@ -13,7 +13,7 @@
#include <QDialog>
#include <string>
#include <SDL.h>
#include <SDL3/SDL.h>
#include <RMG-Core/Settings.hpp>
+56 -58
View File
@@ -9,20 +9,20 @@
*/
#include "MainDialog.hpp"
#include "Widget/ControllerWidget.hpp"
#include "Utilities/QtKeyToSdl2Key.hpp"
#include "Utilities/QtKeyToSdl3Key.hpp"
#include <RMG-Core/Core.hpp>
#include <SDL.h>
#include <SDL3/SDL.h>
#include <QTimer>
Q_DECLARE_METATYPE(SDLDevice);
Q_DECLARE_METATYPE(InputDevice);
using namespace UserInterface;
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romConfig, CoreRomHeader romHeader, CoreRomSettings romSettings) : QDialog(parent)
{
qRegisterMetaType<SDLDevice>();
qRegisterMetaType<InputDevice>();
this->setupUi(this);
@@ -68,12 +68,14 @@ 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", "", "", static_cast<int>(InputDeviceType::EmulateVRU)});
controllerWidget->AddInputDevice({ InputDeviceType::EmulateVRU, "Voice Recognition Unit" });
}
#endif // VRU
controllerWidget->AddInputDevice({"None", "", "", static_cast<int>(InputDeviceType::None)});
controllerWidget->AddInputDevice({"Automatic", "", "", static_cast<int>(InputDeviceType::Automatic)});
controllerWidget->AddInputDevice({"Keyboard", "", "", static_cast<int>(InputDeviceType::Keyboard)});
controllerWidget->SetAllowKeyboardForAutomatic(controllerWidget == this->controllerWidgets.first());
controllerWidget->AddInputDevice({ InputDeviceType::None, "None" });
controllerWidget->AddInputDevice({ InputDeviceType::Automatic, "Automatic" });
controllerWidget->AddInputDevice({ InputDeviceType::Keyboard, "Keyboard" });
controllerWidget->SetInitialized(true);
}
@@ -90,7 +92,7 @@ MainDialog::~MainDialog()
this->closeInputDevice();
}
void MainDialog::addInputDevice(SDLDevice device)
void MainDialog::addInputDevice(const InputDevice& device)
{
for (auto& controllerWidget : this->controllerWidgets)
{
@@ -98,7 +100,7 @@ void MainDialog::addInputDevice(SDLDevice device)
}
}
void MainDialog::removeInputDevice(SDLDevice device)
void MainDialog::removeInputDevice(const InputDevice& device)
{
for (auto& controllerWidget : this->controllerWidgets)
{
@@ -106,56 +108,53 @@ void MainDialog::removeInputDevice(SDLDevice device)
}
}
void MainDialog::openInputDevice(SDLDevice device)
void MainDialog::openInputDevice(InputDevice 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 (device.number == static_cast<int>(InputDeviceType::None) ||
device.number == static_cast<int>(InputDeviceType::Keyboard) ||
device.number == static_cast<int>(InputDeviceType::EmulateVRU))
// we don't need to open a non-joystick device
if (device.type != InputDeviceType::Automatic &&
device.type != InputDeviceType::Joystick)
{
this->currentDevice = { "", "", "", device.number };
controllerWidget->SetCurrentJoystickID(this->currentDevice.number);
this->currentDevice = { };
controllerWidget->SetCurrentJoystickID(this->currentDevice.id);
controllerWidget->SetCurrentJoystick(nullptr, nullptr);
return;
}
// handle automatic mode
if (device.number == static_cast<int>(InputDeviceType::Automatic))
if (device.type == InputDeviceType::Automatic)
{
int currentIndex = this->tabWidget->currentIndex();
if (currentIndex < this->inputDeviceList.size())
{ // use device when there's one
device.number = this->inputDeviceList.at(currentIndex).number;
device.id = this->inputDeviceList.at(currentIndex).id;
}
else
{ // no device found, fallback to keyboard
this->currentDevice = { "", "", "", static_cast<int>(InputDeviceType::Keyboard) };
controllerWidget->SetCurrentJoystickID(this->currentDevice.number);
this->currentDevice = { InputDeviceType::Keyboard, "Keyboard" };
controllerWidget->SetCurrentJoystickID(this->currentDevice.id);
controllerWidget->SetCurrentJoystick(nullptr, nullptr);
return;
}
}
int controllerMode = CoreSettingsGetIntValue(SettingsID::Input_ControllerMode);
if ((controllerMode == 0 && SDL_IsGameController(device.number) == SDL_TRUE) ||
if ((controllerMode == 0 && SDL_IsGamepad(device.id)) ||
(controllerMode == 2))
{
this->currentJoystick = nullptr;
this->currentController = SDL_GameControllerOpen(device.number);
this->currentController = SDL_OpenGamepad(device.id);
}
else if (controllerMode == 0 || controllerMode == 1)
{
this->currentJoystick = SDL_JoystickOpen(device.number);
this->currentJoystick = SDL_OpenJoystick(device.id);
this->currentController = nullptr;
}
this->currentDevice = device;
joystickId = SDL_JoystickGetDeviceInstanceID(device.number);
controllerWidget->SetCurrentJoystickID(joystickId);
controllerWidget->SetCurrentJoystickID(device.id);
controllerWidget->SetIsCurrentJoystickGameController(currentController != nullptr);
controllerWidget->SetCurrentJoystick(this->currentJoystick, this->currentController);
}
@@ -164,13 +163,13 @@ void MainDialog::closeInputDevice()
{
if (this->currentJoystick != nullptr)
{
SDL_JoystickClose(this->currentJoystick);
SDL_CloseJoystick(this->currentJoystick);
this->currentJoystick = nullptr;
}
if (this->currentController != nullptr)
{
SDL_GameControllerClose(this->currentController);
SDL_CloseGamepad(this->currentController);
this->currentController = nullptr;
}
}
@@ -205,8 +204,8 @@ void MainDialog::on_InputPollTimer_triggered()
// 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)))
if ((this->currentJoystick != nullptr && !SDL_JoystickConnected(this->currentJoystick)) ||
(this->currentController != nullptr && !SDL_GamepadConnected(this->currentController)))
{
this->closeInputDevice();
this->openInputDevice(this->currentDevice);
@@ -214,7 +213,7 @@ void MainDialog::on_InputPollTimer_triggered()
// process SDL events
SDL_Event event;
while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, 0, SDL_LASTEVENT) == 1)
while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) == 1)
{
controllerWidget->on_MainDialog_SdlEvent(&event);
}
@@ -222,7 +221,7 @@ void MainDialog::on_InputPollTimer_triggered()
controllerWidget->on_MainDialog_SdlEventPollFinished();
}
void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget* widget, SDLDevice device)
void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget* widget, InputDevice device)
{
Widget::ControllerWidget* currentWidget;
currentWidget = controllerWidgets.at(this->tabWidget->currentIndex());
@@ -237,9 +236,8 @@ void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*
this->closeInputDevice();
// only open device when needed
if (device.number != static_cast<int>(InputDeviceType::None) &&
device.number != static_cast<int>(InputDeviceType::Keyboard) &&
device.number != static_cast<int>(InputDeviceType::EmulateVRU))
if (device.type == InputDeviceType::Automatic ||
device.type == InputDeviceType::Joystick)
{
this->openInputDevice(device);
}
@@ -275,7 +273,7 @@ void MainDialog::on_ControllerWidget_UserProfileRemoved(QString name, QString se
void MainDialog::on_tabWidget_currentChanged(int index)
{
SDLDevice device;
InputDevice device;
Widget::ControllerWidget* controllerWidget;
// save previous tab's user profile
@@ -302,17 +300,17 @@ void MainDialog::on_tabWidget_currentChanged(int index)
controllerWidget->GetCurrentInputDevice(device);
// only open device when needed
if (device.number != static_cast<int>(InputDeviceType::None) &&
device.number != static_cast<int>(InputDeviceType::Keyboard) &&
device.number != static_cast<int>(InputDeviceType::EmulateVRU))
if (device.type == InputDeviceType::Automatic ||
device.type == InputDeviceType::Joystick)
{
this->openInputDevice(device);
}
}
void MainDialog::on_SDLThread_DeviceFound(QString name, QString path, QString serial, int number)
void MainDialog::on_SDLThread_DeviceFound(QString name, QString path, QString serial, SDL_JoystickID joystickId)
{
SDLDevice inputDevice = {name.toStdString(), path.toStdString(), serial.toStdString(), number};
const InputDevice inputDevice = { InputDeviceType::Joystick, name.toStdString(),
path.toStdString(), serial.toStdString(), joystickId };
this->inputDeviceList.append(inputDevice);
}
@@ -351,38 +349,38 @@ void MainDialog::on_SDLThread_DeviceSearchFinished(void)
void MainDialog::on_EventFilter_KeyPressed(QKeyEvent *event)
{
int key = Utilities::QtKeyToSdl2Key(event->key());
int mod = Utilities::QtModKeyToSdl2ModKey(event->modifiers());
int key = Utilities::QtKeyToSdl3Key(event->key());
int mod = Utilities::QtModKeyToSdl3ModKey(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;
keyboardEvent.down = true;
keyboardEvent.type = SDL_EVENT_KEY_DOWN;
keyboardEvent.scancode = (SDL_Scancode)key;
keyboardEvent.key = (SDL_Keycode)key;
keyboardEvent.mod = mod;
SDL_Event sdlEvent;
sdlEvent.key = keyboardEvent;
sdlEvent.type = SDL_KEYDOWN;
sdlEvent.type = SDL_EVENT_KEY_DOWN;
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());
int key = Utilities::QtKeyToSdl3Key(event->key());
int mod = Utilities::QtModKeyToSdl3ModKey(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;
keyboardEvent.down = false;
keyboardEvent.type = SDL_EVENT_KEY_UP;
keyboardEvent.scancode = (SDL_Scancode)key;
keyboardEvent.key = (SDL_Keycode)key;
keyboardEvent.mod = mod;
SDL_Event sdlEvent;
sdlEvent.key = keyboardEvent;
sdlEvent.type = SDL_KEYUP;
sdlEvent.type = SDL_EVENT_KEY_UP;
SDL_PeepEvents(&sdlEvent, 1, SDL_ADDEVENT, 0, 0);
}
@@ -31,23 +31,23 @@ private:
QTimer* inputPollTimer;
Thread::SDLThread* sdlThread;
QList<SDLDevice> oldInputDeviceList;
QList<SDLDevice> inputDeviceList;
QList<InputDevice> oldInputDeviceList;
QList<InputDevice> inputDeviceList;
bool updatingDeviceList = false;
QList<Widget::ControllerWidget*> controllerWidgets;
SDL_Joystick* currentJoystick = nullptr;
SDL_GameController* currentController = nullptr;
SDLDevice currentDevice;
SDL_Gamepad* currentController = nullptr;
InputDevice currentDevice;
int previousTabWidgetIndex = 0;
EventFilter* eventFilter;
void addInputDevice(SDLDevice device);
void removeInputDevice(SDLDevice device);
void addInputDevice(const InputDevice& device);
void removeInputDevice(const InputDevice& device);
void openInputDevice(SDLDevice device);
void openInputDevice(InputDevice device);
void closeInputDevice();
public:
@@ -57,7 +57,7 @@ public:
public slots:
void on_InputPollTimer_triggered();
void on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*, SDLDevice);
void on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*, InputDevice);
void on_ControllerWidget_RefreshInputDevicesButtonClicked();
void on_ControllerWidget_UserProfileAdded(QString, QString);
@@ -65,7 +65,7 @@ public slots:
void on_tabWidget_currentChanged(int);
void on_SDLThread_DeviceFound(QString, QString, QString, int);
void on_SDLThread_DeviceFound(QString, QString, QString, SDL_JoystickID);
void on_SDLThread_DeviceSearchFinished(void);
private slots:
@@ -12,7 +12,7 @@
#include <QFileDialog>
#include <QMessageBox>
#include <SDL.h>
#include <SDL3/SDL.h>
#include <RMG-Core/Emulation.hpp>
#include <RMG-Core/Settings.hpp>
@@ -21,7 +21,7 @@
using namespace UserInterface;
OptionsDialog::OptionsDialog(QWidget* parent, OptionsDialogSettings settings,
SDL_Joystick* joystick, SDL_GameController* controller) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
SDL_Joystick* joystick, SDL_Gamepad* controller) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
{
this->setupUi(this);
@@ -123,9 +123,9 @@ void OptionsDialog::on_changeGameboySaveButton_clicked()
void OptionsDialog::on_testRumbleButton_clicked()
{
#if SDL_VERSION_ATLEAST(2,0,18)
if ((this->currentJoystick != nullptr && SDL_JoystickHasRumble(this->currentJoystick) != SDL_TRUE) ||
(this->currentController != nullptr && SDL_GameControllerHasRumble(this->currentController) != SDL_TRUE))
#if SDL_VERSION_ATLEAST(2,0,18) && !SDL_VERSION_ATLEAST(3,0,0) // TODO: port this to SDL3
if ((this->currentJoystick != nullptr && SDL_JoystickHasRumble(this->currentJoystick) != true) ||
(this->currentController != nullptr && SDL_GameControllerHasRumble(this->currentController) != true))
{
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Icon::Critical);
@@ -139,10 +139,10 @@ void OptionsDialog::on_testRumbleButton_clicked()
if (this->currentJoystick != nullptr)
{
SDL_JoystickRumble(this->currentJoystick, 0xFFFF, 0xFFFF, 1500);
SDL_RumbleJoystick(this->currentJoystick, 0xFFFF, 0xFFFF, 1500);
}
else
{
SDL_GameControllerRumble(this->currentController, 0xFFFF, 0xFFFF, 1500);
SDL_RumbleGamepad(this->currentController, 0xFFFF, 0xFFFF, 1500);
}
}
@@ -13,7 +13,7 @@
#include <QDialog>
#include <string>
#include <SDL.h>
#include <SDL3/SDL.h>
#include "ui_OptionsDialog.h"
@@ -38,7 +38,7 @@ Q_OBJECT
public:
OptionsDialog(QWidget *parent, OptionsDialogSettings settings,
SDL_Joystick* joystick, SDL_GameController* controller);
SDL_Joystick* joystick, SDL_Gamepad* controller);
OptionsDialogSettings GetSettings();
@@ -49,7 +49,7 @@ private:
OptionsDialogSettings settings;
SDL_Joystick* currentJoystick = nullptr;
SDL_GameController* currentController = nullptr;
SDL_Gamepad* currentController = nullptr;
void setIconsForEmulationInfoText(void);
void hideEmulationInfoText(void);
@@ -23,7 +23,7 @@
#include <QPainter>
#include <QPixmap>
#include <SDL.h>
#include <SDL3/SDL.h>
using namespace UserInterface::Widget;
@@ -245,10 +245,10 @@ void ControllerWidget::initializeMiscButtons()
bool ControllerWidget::isCurrentDeviceKeyboard()
{
SDLDevice device = this->inputDeviceComboBox->currentData().value<SDLDevice>();
const InputDevice device = this->inputDeviceComboBox->currentData().value<InputDevice>();
return device.number == static_cast<int>(InputDeviceType::Automatic) ||
device.number == static_cast<int>(InputDeviceType::Keyboard);
return device.type == InputDeviceType::Keyboard ||
(this->allowKeyboardForAutomatic && device.type == InputDeviceType::Automatic);
}
bool ControllerWidget::isCurrentDeviceNotFound()
@@ -410,15 +410,10 @@ bool ControllerWidget::hasAnySettingChanged(QString sectionQString)
// retrieve data from settings
bool settingsIsPluggedIn = CoreSettingsGetBoolValue(SettingsID::Input_PluggedIn, section);
int settingsDeadZone = CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section);
int settingsAnalogSensitivity = 100;
int settingsAnalogSensitivity = CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section);
int settingsPak = CoreSettingsGetIntValue(SettingsID::Input_Pak, section);
std::string settingsGameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section);
std::string settingsGameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section);
// account for profiles before v0.3.9
if (CoreSettingsKeyExists(section, "Sensitivity"))
{
settingsAnalogSensitivity = CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section);
}
// retrieve current data
bool currentIsPluggedIn = this->inputDeviceComboBox->currentText() != "None";
@@ -504,27 +499,27 @@ void ControllerWidget::showErrorMessage(QString text, QString details)
msgBox.exec();
}
void ControllerWidget::AddInputDevice(SDLDevice device)
void ControllerWidget::AddInputDevice(const InputDevice& device)
{
QString deviceName = QString::fromStdString(device.name);
QString name = deviceName;
if (device.number >= 0)
if (device.type == InputDeviceType::Joystick)
{
name += " (";
name += QString::number(device.number);
name += QString::number(device.id);
name += ")";
}
this->inputDeviceNameList.append(deviceName);
this->inputDeviceComboBox->addItem(name, QVariant::fromValue<SDLDevice>(device));
this->inputDeviceComboBox->addItem(name, QVariant::fromValue<InputDevice>(device));
}
void ControllerWidget::RemoveInputDevice(SDLDevice device)
void ControllerWidget::RemoveInputDevice(const InputDevice& device)
{
inputDeviceNameList.removeOne(QString::fromStdString(device.name));
int index = this->inputDeviceComboBox->findData(QVariant::fromValue<SDLDevice>(device));
int index = this->inputDeviceComboBox->findData(QVariant::fromValue<InputDevice>(device));
if (index >= 0)
{
this->inputDeviceComboBox->removeItem(index);
@@ -561,8 +556,37 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString)
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 };
InputDeviceType deviceType;
// keep compatibility with <v0.8.1
if (CoreSettingsKeyExists(section, "DeviceType"))
{
deviceType = static_cast<InputDeviceType>(CoreSettingsGetIntValue(SettingsID::Input_DeviceType, section));
}
else
{
int deviceNum = CoreSettingsGetIntValue(SettingsID::Input_DeviceNum, section);
switch (deviceNum)
{
case -4:
deviceType = InputDeviceType::EmulateVRU;
break;
case -3:
deviceType = InputDeviceType::None;
break;
case -2:
deviceType = InputDeviceType::Automatic;
break;
case -1:
deviceType = InputDeviceType::Keyboard;
break;
default:
deviceType = InputDeviceType::Joystick;
break;
}
}
InputDevice device = { deviceType, deviceName, devicePath, deviceSerial };
// do nothing when input device combobox
// is empty
@@ -571,12 +595,6 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString)
return;
}
// account for old setting
if (!isPluggedIn && deviceNum != static_cast<int>(InputDeviceType::None))
{
device = { "None", "", "", static_cast<int>(InputDeviceType::None) };
}
// clear (not found) devices first
int notFoundIndex = this->inputDeviceComboBox->findText("(not found)", Qt::MatchFlag::MatchEndsWith);
if (notFoundIndex != -1)
@@ -585,26 +603,14 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString)
this->inputDeviceComboBox->removeItem(notFoundIndex);
}
int deviceNameIndex = this->inputDeviceComboBox->findText(QString::fromStdString(deviceName), Qt::MatchFlag::MatchStartsWith);
int deviceIndex = -1;
int deviceSerialIndex = -1;
bool needCompatibility = deviceNum >= 0 && devicePath.empty() && deviceSerial.empty();
int count = this->inputDeviceComboBox->count();
for (int i = 0; i < count; i++)
for (int i = 0; i < this->inputDeviceComboBox->count(); i++)
{
SDLDevice otherDevice = this->inputDeviceComboBox->itemData(i).value<SDLDevice>();
if (needCompatibility)
{ // backwards compatibility with <v0.7.2
if (device.name == otherDevice.name &&
device.number == otherDevice.number)
{
deviceIndex = i;
break;
}
}
else if (device.name == otherDevice.name &&
device.serial == otherDevice.serial)
InputDevice otherDevice = this->inputDeviceComboBox->itemData(i).value<InputDevice>();
if (device.name == otherDevice.name &&
device.serial == otherDevice.serial)
{
if (!device.serial.empty())
{
@@ -624,7 +630,7 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString)
this->inputDeviceComboBox->setCurrentIndex(deviceIndex);
// force-refresh automatic input device
if (deviceNum == static_cast<int>(InputDeviceType::Automatic))
if (deviceType == InputDeviceType::Automatic)
{
this->on_inputDeviceComboBox_currentIndexChanged(deviceIndex);
}
@@ -633,16 +639,12 @@ void ControllerWidget::CheckInputDeviceSettings(QString sectionQString)
{ // name and serial match
this->inputDeviceComboBox->setCurrentIndex(deviceSerialIndex);
}
else if (deviceNameIndex != -1)
{ // name only match
this->inputDeviceComboBox->setCurrentIndex(deviceNameIndex);
}
else
{ // no match
QString title = QString::fromStdString(deviceName);
title += " (not found)";
this->inputDeviceNameList.append(QString::fromStdString(deviceName));
this->inputDeviceComboBox->addItem(title, QVariant::fromValue<SDLDevice>(device));
this->inputDeviceComboBox->addItem(title, QVariant::fromValue<InputDevice>(device));
this->inputDeviceComboBox->setCurrentIndex(this->inputDeviceNameList.count() - 1);
}
}
@@ -657,17 +659,17 @@ void ControllerWidget::ClearControllerImage()
this->controllerImageWidget->ClearControllerState();
}
void ControllerWidget::GetCurrentInputDevice(SDLDevice& device, bool ignoreDeviceNotFound)
void ControllerWidget::GetCurrentInputDevice(InputDevice& device, bool ignoreDeviceNotFound)
{
int currentIndex = this->inputDeviceComboBox->currentIndex();
if (this->isCurrentDeviceNotFound() && !ignoreDeviceNotFound)
{
device = { "", "", "", -1 };
device = { };
}
else
{
device = this->inputDeviceComboBox->itemData(currentIndex).value<SDLDevice>();
device = this->inputDeviceComboBox->itemData(currentIndex).value<InputDevice>();
}
}
@@ -722,18 +724,18 @@ void ControllerWidget::on_inputDeviceComboBox_currentIndexChanged(int value)
return;
}
SDLDevice device = this->inputDeviceComboBox->itemData(value).value<SDLDevice>();
InputDevice device = this->inputDeviceComboBox->itemData(value).value<InputDevice>();
this->ClearControllerImage();
if (this->isCurrentDeviceNotFound())
{
device = { "", "", "", -1 };
device = { };
}
// set plugged in state
this->setPluggedIn(device.number != static_cast<int>(InputDeviceType::None) &&
device.number != static_cast<int>(InputDeviceType::EmulateVRU));
this->setPluggedIn(device.type != InputDeviceType::None &&
device.type != InputDeviceType::EmulateVRU);
emit this->CurrentInputDeviceChanged(this, device);
}
@@ -869,12 +871,13 @@ void ControllerWidget::on_removeProfileButton_clicked()
void ControllerWidget::on_resetButton_clicked()
{
QString section = this->getCurrentSettingsSection();
const QString section = this->getCurrentSettingsSection();
const std::string sectionStr = section.toStdString();
// revert settings in current section when it exists
if (CoreSettingsSectionExists(section.toStdString()))
if (CoreSettingsSectionExists(sectionStr))
{
CoreSettingsRevertSection(section.toStdString());
CoreSettingsRevertSection(sectionStr);
}
this->LoadSettings(section);
@@ -882,8 +885,8 @@ void ControllerWidget::on_resetButton_clicked()
void ControllerWidget::on_optionsButton_clicked()
{
SDLDevice device = this->inputDeviceComboBox->currentData().value<SDLDevice>();
bool isKeyboard = device.number == static_cast<int>(InputDeviceType::Keyboard);
InputDevice device = this->inputDeviceComboBox->currentData().value<InputDevice>();
const bool isKeyboard = device.type == InputDeviceType::Keyboard;
OptionsDialog dialog(this, this->optionsDialogSettings,
isKeyboard ? nullptr : this->currentJoystick,
@@ -1022,10 +1025,10 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
switch (event->type)
{
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
{ // gamepad & joystick button
SDL_JoystickID joystickId = -1;
InputType inputType = InputType::Invalid;
@@ -1033,8 +1036,8 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
bool sdlButtonPressed = false;
QString sdlButtonName;
if ((event->type == SDL_CONTROLLERBUTTONDOWN) ||
(event->type == SDL_CONTROLLERBUTTONUP))
if ((event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) ||
(event->type == SDL_EVENT_GAMEPAD_BUTTON_UP))
{ // gamepad button
if (!this->isCurrentJoystickGameController &&
this->optionsDialogSettings.FilterEventsForButtons)
@@ -1042,14 +1045,14 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
return;
}
joystickId = event->cbutton.which;
joystickId = event->gbutton.which;
inputType = InputType::GamepadButton;
sdlButton = event->cbutton.button;
sdlButtonPressed = (event->type == SDL_CONTROLLERBUTTONDOWN);
sdlButtonName = SDL_GameControllerGetStringForButton((SDL_GameControllerButton)sdlButton);
sdlButton = event->gbutton.button;
sdlButtonPressed = (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
sdlButtonName = SDL_GetGamepadStringForButton((SDL_GamepadButton)sdlButton);
}
else if ((event->type == SDL_JOYBUTTONDOWN) ||
(event->type == SDL_JOYBUTTONUP))
else if ((event->type == SDL_EVENT_JOYSTICK_BUTTON_DOWN) ||
(event->type == SDL_EVENT_JOYSTICK_BUTTON_UP))
{ // joystick button
if (this->isCurrentJoystickGameController &&
this->optionsDialogSettings.FilterEventsForButtons)
@@ -1060,7 +1063,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
joystickId = event->jbutton.which;
inputType = InputType::JoystickButton;
sdlButton = event->jbutton.button;
sdlButtonPressed = (event->type == SDL_JOYBUTTONDOWN);
sdlButtonPressed = (event->type == SDL_EVENT_JOYSTICK_BUTTON_DOWN);
sdlButtonName = "button " + QString::number(sdlButton);
}
@@ -1142,7 +1145,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
}
} break;
case SDL_JOYHATMOTION:
case SDL_EVENT_JOYSTICK_HAT_MOTION:
{ // joystick hat
SDL_JoystickID joystickId = event->jhat.which;
InputType inputType = InputType::JoystickHat;
@@ -1279,8 +1282,8 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
}
} break;
case SDL_CONTROLLERAXISMOTION:
case SDL_JOYAXISMOTION:
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
{ // gamepad & joystick axis
SDL_JoystickID joystickId = -1;
InputType inputType = InputType::Invalid;
@@ -1288,7 +1291,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
int sdlAxisValue = 0;
QString sdlAxisName;
if (event->type == SDL_CONTROLLERAXISMOTION)
if (event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION)
{ // gamepad axis
if (!this->isCurrentJoystickGameController &&
this->optionsDialogSettings.FilterEventsForAxis)
@@ -1296,11 +1299,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
return;
}
joystickId = event->caxis.which;
joystickId = event->gaxis.which;
inputType = InputType::GamepadAxis;
sdlAxis = event->caxis.axis;
sdlAxisValue = event->caxis.value;
sdlAxisName = SDL_GameControllerGetStringForAxis((SDL_GameControllerAxis)sdlAxis);
sdlAxis = event->gaxis.axis;
sdlAxisValue = event->gaxis.value;
sdlAxisName = SDL_GetGamepadStringForAxis((SDL_GamepadAxis)sdlAxis);
sdlAxisName += sdlAxisValue > 0 ? "+" : "-";
}
else
@@ -1395,8 +1398,8 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
}
} break;
case SDL_KEYDOWN:
case SDL_KEYUP:
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
{ // keyboard button
// make sure a keyboard is selected
@@ -1405,8 +1408,8 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
break;
}
const SDL_Scancode sdlButton = (SDL_Scancode)event->key.keysym.scancode;
const bool sdlButtonPressed = (event->type == SDL_KEYDOWN);
const SDL_Scancode sdlButton = (SDL_Scancode)event->key.scancode;
const bool sdlButtonPressed = (event->type == SDL_EVENT_KEY_DOWN);
// handle button widget
if (this->currentButton != nullptr)
@@ -1494,7 +1497,8 @@ void ControllerWidget::on_MainDialog_SdlEventPollFinished()
bool ControllerWidget::IsPluggedIn()
{
return this->inputDeviceComboBox->currentData().toInt() != static_cast<int>(InputDeviceType::None);
const InputDevice device = this->inputDeviceComboBox->currentData().value<InputDevice>();
return device.type != InputDeviceType::None;
}
void ControllerWidget::SetOnlyLoadGameProfile(bool value, CoreRomHeader romHeader, CoreRomSettings romSettings)
@@ -1507,6 +1511,11 @@ void ControllerWidget::SetOnlyLoadGameProfile(bool value, CoreRomHeader romHeade
this->addProfileButton->setDisabled(value);
}
void ControllerWidget::SetAllowKeyboardForAutomatic(bool value)
{
this->allowKeyboardForAutomatic = value;
}
void ControllerWidget::SetSettingsSection(QString profile, QString section)
{
this->settingsSection = section;
@@ -1662,34 +1671,14 @@ void ControllerWidget::LoadSettings(QString sectionQString, bool loadUserProfile
}
}
// keep backwards compatibility with versions before v0.3.9
if (CoreSettingsKeyExists(section, "Sensitivity"))
{
this->analogStickSensitivitySlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section));
}
else
{
this->analogStickSensitivitySlider->setValue(100);
}
this->analogStickSensitivitySlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section));
this->deadZoneSlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section));
this->optionsDialogSettings.RemoveDuplicateMappings = CoreSettingsGetBoolValue(SettingsID::Input_RemoveDuplicateMappings, section);
this->optionsDialogSettings.ControllerPak = CoreSettingsGetIntValue(SettingsID::Input_Pak, section);
this->optionsDialogSettings.GameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section);
this->optionsDialogSettings.GameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section);
// keep backwards compatibility with old profiles
if (CoreSettingsKeyExists(section, "FilterEventsForButtons") &&
CoreSettingsKeyExists(section, "FilterEventsForAxis"))
{
this->optionsDialogSettings.FilterEventsForButtons = CoreSettingsGetBoolValue(SettingsID::Input_FilterEventsForButtons, section);
this->optionsDialogSettings.FilterEventsForAxis = CoreSettingsGetBoolValue(SettingsID::Input_FilterEventsForAxis, section);
}
else
{
this->optionsDialogSettings.FilterEventsForButtons = true;
this->optionsDialogSettings.FilterEventsForAxis = true;
}
this->optionsDialogSettings.FilterEventsForButtons = CoreSettingsGetBoolValue(SettingsID::Input_FilterEventsForButtons, section);
this->optionsDialogSettings.FilterEventsForAxis = CoreSettingsGetBoolValue(SettingsID::Input_FilterEventsForAxis, section);
for (auto& buttonSetting : this->buttonSettingMappings)
{
@@ -1755,7 +1744,7 @@ void ControllerWidget::SaveDefaultSettings()
CoreSettingsSetValue(SettingsID::Input_PluggedIn, section, false);
CoreSettingsSetValue(SettingsID::Input_DeviceName, section, std::string("None"));
CoreSettingsSetValue(SettingsID::Input_DeviceNum, section, static_cast<int>(InputDeviceType::None));
CoreSettingsSetValue(SettingsID::Input_DeviceType, section, static_cast<int>(InputDeviceType::None));
CoreSettingsSetValue(SettingsID::Input_DevicePath, section, std::string(""));
CoreSettingsSetValue(SettingsID::Input_DeviceSerial, section, std::string(""));
CoreSettingsSetValue(SettingsID::Input_Deadzone, section, 9);
@@ -1799,7 +1788,7 @@ void ControllerWidget::SaveSettings()
// when we're only loading the game profile,
// we should only save when anything has changed
if (this->onlyLoadGameProfile &&
if (this->onlyLoadGameProfile &&
!this->hasAnySettingChanged(this->gameSection))
{
return;
@@ -1838,7 +1827,7 @@ void ControllerWidget::SaveUserProfileSettings()
void ControllerWidget::SaveSettings(QString section)
{
SDLDevice device;
InputDevice device;
std::string mainSettingsSection = this->settingsSection.toStdString();
std::string sectionStr = section.toStdString();
@@ -1871,7 +1860,7 @@ void ControllerWidget::SaveSettings(QString section)
CoreSettingsSetValue(SettingsID::Input_PluggedIn, sectionStr, this->IsPluggedIn());
CoreSettingsSetValue(SettingsID::Input_DeviceName, sectionStr, device.name);
CoreSettingsSetValue(SettingsID::Input_DeviceNum, sectionStr, device.number);
CoreSettingsSetValue(SettingsID::Input_DeviceType, sectionStr, static_cast<int>(device.type));
CoreSettingsSetValue(SettingsID::Input_DevicePath, sectionStr, device.path);
CoreSettingsSetValue(SettingsID::Input_DeviceSerial, sectionStr, device.serial);
CoreSettingsSetValue(SettingsID::Input_Deadzone, sectionStr, this->deadZoneSlider->value());
@@ -1949,7 +1938,7 @@ void ControllerWidget::SetIsCurrentJoystickGameController(bool isGameController)
this->isCurrentJoystickGameController = isGameController;
}
void ControllerWidget::SetCurrentJoystick(SDL_Joystick* joystick, SDL_GameController* controller)
void ControllerWidget::SetCurrentJoystick(SDL_Joystick* joystick, SDL_Gamepad* controller)
{
this->currentJoystick = joystick;
this->currentController = controller;
@@ -22,7 +22,7 @@ using namespace UserInterface::Widget;
#include "ui_ControllerWidget.h"
#include "common.hpp"
#include <SDL.h>
#include <SDL3/SDL.h>
#include <RMG-Core/RomSettings.hpp>
#include <RMG-Core/RomHeader.hpp>
@@ -107,7 +107,7 @@ private:
bool isCurrentJoystickGameController = false;
SDL_Joystick* currentJoystick = nullptr;
SDL_GameController* currentController = nullptr;
SDL_Gamepad* currentController = nullptr;
int previousProfileComboBoxIndex = -1;
@@ -115,24 +115,27 @@ private:
CoreRomHeader gameRomHeader;
CoreRomSettings gameRomSettings;
bool allowKeyboardForAutomatic = false;
HotkeysDialog* currentHotkeysDialog = nullptr;
public:
ControllerWidget(QWidget* parent, EventFilter* eventFilter);
~ControllerWidget();
void AddInputDevice(SDLDevice device);
void RemoveInputDevice(SDLDevice device);
void AddInputDevice(const InputDevice& device);
void RemoveInputDevice(const InputDevice& device);
void CheckInputDeviceSettings();
void CheckInputDeviceSettings(QString section);
void DrawControllerImage();
void ClearControllerImage();
void GetCurrentInputDevice(SDLDevice& device, bool ignoreDeviceNotFound = false);
void GetCurrentInputDevice(InputDevice& device, bool ignoreDeviceNotFound = false);
bool IsPluggedIn();
void SetOnlyLoadGameProfile(bool value, CoreRomHeader romHeader, CoreRomSettings romSettings);
void SetAllowKeyboardForAutomatic(bool value);
void SetSettingsSection(QString profile, QString section);
void SetInitialized(bool value);
@@ -150,7 +153,7 @@ public:
void SetCurrentJoystickID(SDL_JoystickID joystickId);
void SetIsCurrentJoystickGameController(bool isGameController);
void SetCurrentJoystick(SDL_Joystick* joystick, SDL_GameController* controller);
void SetCurrentJoystick(SDL_Joystick* joystick, SDL_Gamepad* controller);
void AddUserProfile(QString name, QString section);
void RemoveUserProfile(QString name, QString section);
@@ -184,7 +187,7 @@ public slots:
void on_MainDialog_SdlEventPollFinished();
signals:
void CurrentInputDeviceChanged(ControllerWidget* widget, SDLDevice device);
void CurrentInputDeviceChanged(ControllerWidget* widget, InputDevice device);
void RefreshInputDevicesButtonClicked();
void UserProfileAdded(QString name, QString section);
-193
View File
@@ -1,193 +0,0 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020-2025 Rosalie Wanders <rosalie@mailbox.org>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "InputDevice.hpp"
using namespace Utilities;
InputDevice::InputDevice()
{
}
InputDevice::~InputDevice()
{
this->CloseDevice();
}
void InputDevice::SetSDLThread(Thread::SDLThread* sdlThread)
{
this->sdlThread = sdlThread;
connect(this->sdlThread, &Thread::SDLThread::OnInputDeviceFound, this,
&InputDevice::on_SDLThread_DeviceFound);
connect(this->sdlThread, &Thread::SDLThread::OnDeviceSearchFinished, this,
&InputDevice::on_SDLThread_DeviceSearchFinished);
}
SDL_Joystick* InputDevice::GetJoystickHandle()
{
return this->joystick;
}
SDL_GameController* InputDevice::GetGameControllerHandle()
{
return this->gameController;
}
bool InputDevice::StartRumble(void)
{
if (this->gameController != nullptr)
{
return SDL_GameControllerRumble(this->gameController, 0xFFFF, 0xFFFF, SDL_HAPTIC_INFINITY) == 0;
}
else if (this->joystick != nullptr)
{
return SDL_JoystickRumble(this->joystick, 0xFFFF, 0xFFFF, SDL_HAPTIC_INFINITY) == 0;
}
return false;
}
bool InputDevice::StopRumble(void)
{
if (this->gameController != nullptr)
{
return SDL_GameControllerRumble(this->gameController, 0, 0, 0) == 0;
}
else if (this->joystick != nullptr)
{
return SDL_JoystickRumble(this->joystick, 0, 0, 0) == 0;
}
return false;
}
bool InputDevice::IsAttached(void)
{
return SDL_JoystickGetAttached(this->joystick) == SDL_TRUE;
}
bool InputDevice::HasOpenDevice()
{
return this->hasOpenDevice;
}
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)
{
QThread::msleep(5);
}
this->foundDevicesWithNameMatch.clear();
this->desiredDevice = {name, path, serial, num};
this->isOpeningDevice = true;
// tell SDLThread to query input devices
this->sdlThread->SetAction(SDLThreadAction::GetInputDevices);
}
bool InputDevice::IsOpeningDevice(void)
{
return this->isOpeningDevice;
}
bool InputDevice::CloseDevice()
{
if (this->joystick != nullptr)
{
SDL_JoystickClose(this->joystick);
this->joystick = nullptr;
}
if (this->gameController != nullptr)
{
SDL_GameControllerClose(this->gameController);
this->gameController = nullptr;
}
return true;
}
void InputDevice::on_SDLThread_DeviceFound(QString name, QString path, QString serial, int number)
{
if ((!this->isOpeningDevice) ||
(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);
}
void InputDevice::on_SDLThread_DeviceSearchFinished(void)
{
if (!this->isOpeningDevice)
{
return;
}
this->CloseDevice();
if (this->foundDevicesWithNameMatch.empty())
{
this->isOpeningDevice = false;
this->hasOpenDevice = false;
return;
}
// try to find exact match
SDLDevice device;
bool hasDevice = false;
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, 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);
if (SDL_IsGameController(device.number))
{
this->gameController = SDL_GameControllerOpen(device.number);
}
this->isOpeningDevice = false;
this->hasOpenDevice = this->joystick != nullptr || this->gameController != nullptr;
}
@@ -1,71 +0,0 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020-2025 Rosalie Wanders <rosalie@mailbox.org>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef INPUTDEVICE_HPP
#define INPUTDEVICE_HPP
#include "common.hpp"
#include <QObject>
#include <string>
#include <SDL.h>
#include "Thread/SDLThread.hpp"
namespace Utilities
{
class InputDevice : public QObject
{
Q_OBJECT
public:
InputDevice();
~InputDevice();
void SetSDLThread(Thread::SDLThread* sdlThread);
SDL_Joystick* GetJoystickHandle(void);
SDL_GameController* GetGameControllerHandle(void);
bool StartRumble(void);
bool StopRumble(void);
// returns whether the device is attached
bool IsAttached(void);
// returns whether a device has been opened
bool HasOpenDevice(void);
// 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);
// tries to close opened device
bool CloseDevice(void);
private:
SDL_Joystick* joystick = nullptr;
SDL_GameController* gameController = nullptr;
bool hasOpenDevice = false;
bool isOpeningDevice = false;
Thread::SDLThread* sdlThread = nullptr;
SDLDevice desiredDevice;
std::vector<SDLDevice> foundDevicesWithNameMatch;
private slots:
void on_SDLThread_DeviceFound(QString name, QString path, QString serial, int number);
void on_SDLThread_DeviceSearchFinished(void);
};
} // namespace Utilities
#endif // INPUTDEVICE_HPP
@@ -1,12 +0,0 @@
#ifndef QTKEYTOSDL2KEY_HPP
#define QTKEYTOSDL2KEY_HPP
#include <QObject>
namespace Utilities
{
int QtKeyToSdl2Key(int);
int QtModKeyToSdl2ModKey(Qt::KeyboardModifiers);
} // namespace Utilities
#endif // QTKEYTOSDL2KEY_HPP
@@ -7,13 +7,13 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "QtKeyToSdl2Key.hpp"
#include "QtKeyToSdl3Key.hpp"
#include <SDL2/SDL.h>
#include <SDL3/SDL.h>
using namespace Utilities;
int Utilities::QtKeyToSdl2Key(int key)
int Utilities::QtKeyToSdl3Key(int key)
{
SDL_Scancode returnValue;
switch (key)
@@ -323,16 +323,16 @@ int Utilities::QtKeyToSdl2Key(int key)
return returnValue;
}
int Utilities::QtModKeyToSdl2ModKey(Qt::KeyboardModifiers modifiers)
int Utilities::QtModKeyToSdl3ModKey(Qt::KeyboardModifiers modifiers)
{
int value = 0;
if (modifiers & Qt::ShiftModifier)
value |= KMOD_SHIFT;
value |= SDL_KMOD_SHIFT;
if (modifiers & Qt::ControlModifier)
value |= KMOD_CTRL;
value |= SDL_KMOD_CTRL;
if (modifiers & Qt::AltModifier)
value |= KMOD_ALT;
value |= SDL_KMOD_ALT;
if (modifiers & Qt::MetaModifier)
value |= KMOD_GUI;
value |= SDL_KMOD_GUI;
return value;
}
@@ -0,0 +1,12 @@
#ifndef QTKEYTOSDL3KEY_HPP
#define QTKEYTOSDL3KEY_HPP
#include <QObject>
namespace Utilities
{
int QtKeyToSdl3Key(int);
int QtModKeyToSdl3ModKey(Qt::KeyboardModifiers);
} // namespace Utilities
#endif // QTKEYTOSDL3KEY_HPP
+38 -18
View File
@@ -27,7 +27,7 @@
#include <QByteArray>
#include <QJsonArray>
#include <SDL.h>
#include <SDL3/SDL.h>
#include "VRUwords.hpp"
#include "VRU.hpp"
@@ -85,8 +85,8 @@ static int l_WordListCount = 0;
static QStringList l_RegisteredWords;
static QList<int> l_RegisteredWordsIndex;
static SDL_AudioDeviceID l_AudioDevice = 0;
static SDL_AudioSpec l_AudioDeviceSpec;
static SDL_AudioStream* l_AudioStream = nullptr;
static bool l_HasInitSDL = false;
//
// Local Functions
@@ -260,14 +260,24 @@ static bool init_mic(void)
SDL_AudioSpec desiredAudioSpec;
desiredAudioSpec.freq = 44100;
desiredAudioSpec.format = AUDIO_S16SYS;
desiredAudioSpec.format = SDL_AUDIO_S16;
desiredAudioSpec.channels = 1;
desiredAudioSpec.samples = 1024;
desiredAudioSpec.callback = nullptr;
desiredAudioSpec.userdata = nullptr;
l_AudioDevice = SDL_OpenAudioDevice(nullptr, 1, &desiredAudioSpec, &l_AudioDeviceSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (l_AudioDevice == 0)
if (!SDL_WasInit(SDL_INIT_AUDIO))
{
if (!SDL_InitSubSystem(SDL_INIT_AUDIO))
{
debugMessage = "VRU: SDL_InitSubSystem Failed: ";
debugMessage += SDL_GetError();
PluginDebugMessage(M64MSG_ERROR, debugMessage);
return false;
}
l_HasInitSDL = true;
}
l_AudioStream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_RECORDING, &desiredAudioSpec, NULL, NULL);
if (l_AudioStream == nullptr)
{
debugMessage = "VRU: SDL_OpenAudioDevice Failed: ";
debugMessage += SDL_GetError();
@@ -280,9 +290,10 @@ static bool init_mic(void)
static void quit_mic(void)
{
if (l_AudioDevice != 0)
if (l_AudioStream != nullptr)
{
SDL_CloseAudioDevice(l_AudioDevice);
SDL_DestroyAudioStream(l_AudioStream);
l_AudioStream = nullptr;
}
}
@@ -379,6 +390,11 @@ bool QuitVRU(void)
return true;
}
bool HasVRUInitSDL(void)
{
return l_HasInitSDL;
}
int GetVRUMicState(void)
{
return l_MicState;
@@ -442,7 +458,7 @@ EXPORT void CALL SendVRUWord(uint16_t length, uint16_t* word, uint8_t lang)
}
// try to create a new recognizer
l_VoskRecognizer = l_vosk_recognizer_new_grm(l_VoskModel, static_cast<float>(l_AudioDeviceSpec.freq), json_document.toJson().constData());
l_VoskRecognizer = l_vosk_recognizer_new_grm(l_VoskModel, 44100.0f, json_document.toJson().constData());
if (l_VoskRecognizer != nullptr)
{
l_vosk_recognizer_set_max_alternatives(l_VoskRecognizer, 3);
@@ -459,12 +475,11 @@ EXPORT void CALL SetMicState(int state)
if (state)
{
SDL_ClearQueuedAudio(l_AudioDevice);
SDL_PauseAudioDevice(l_AudioDevice, 0);
SDL_ResumeAudioStreamDevice(l_AudioStream);
}
else
{
SDL_PauseAudioDevice(l_AudioDevice, 1);
SDL_PauseAudioStreamDevice(l_AudioStream);
}
l_MicState = state;
@@ -489,13 +504,18 @@ EXPORT void CALL ReadVRUResults(uint16_t* error_flags, uint16_t* num_results, ui
}
// retrieve audio data from device
SDL_PauseAudioDevice(l_AudioDevice, 1);
SDL_PauseAudioStreamDevice(l_AudioStream);
int audio_size = SDL_GetAudioStreamAvailable(l_AudioStream);
if (audio_size == -1)
{
return;
}
uint32_t audio_size = SDL_GetQueuedAudioSize(l_AudioDevice);
std::vector<char> audio_buf(audio_size);
// read audio
audio_size = SDL_DequeueAudio(l_AudioDevice, audio_buf.data(), audio_buf.size());
audio_size = SDL_GetAudioStreamData(l_AudioStream, audio_buf.data(), audio_buf.size());
// hand audio data to vosk and retrieve results
int ret = l_vosk_recognizer_accept_waveform(l_VoskRecognizer, audio_buf.data(), audio_size);
+3
View File
@@ -19,6 +19,9 @@ bool IsVRUInit(void);
// attempts to de-initialize VRY capabilities
bool QuitVRU(void);
// returns whether VRU has initialized SDL audio
bool HasVRUInitSDL(void);
int GetVRUMicState(void);
#endif // VRU_HPP
+16 -9
View File
@@ -12,6 +12,8 @@
#include <string>
#include <SDL3/SDL.h>
#define SDL_AXIS_PEAK 32767
enum class N64ControllerButton
@@ -35,10 +37,12 @@ enum class N64ControllerButton
enum class InputDeviceType
{
EmulateVRU = -4,
None = -3,
Automatic = -2,
Keyboard = -1,
None = 0,
EmulateVRU,
Automatic,
Keyboard,
Joystick,
Invalid
};
enum class InputType
@@ -68,19 +72,22 @@ enum class N64ControllerPak
None,
};
struct SDLDevice
struct InputDevice
{
InputDeviceType type = InputDeviceType::Invalid;
std::string name;
std::string path;
std::string serial;
int number;
SDL_JoystickID id = 0;
bool operator== (const SDLDevice& other) const
bool operator== (const InputDevice& other) const
{
return other.name == name &&
return other.type == type &&
other.name == name &&
other.path == path &&
other.serial == serial &&
other.number == number;
other.id == id;
}
};
+223 -114
View File
@@ -12,7 +12,6 @@
#define INPUT_PLUGIN_API_VERSION 0x020100
#include "UserInterface/MainDialog.hpp"
#include "Utilities/InputDevice.hpp"
#include "Thread/HotkeysThread.hpp"
#include "Thread/SDLThread.hpp"
#include "common.hpp"
@@ -40,7 +39,7 @@
#include <QGuiApplication>
#include <QApplication>
#include <SDL.h>
#include <SDL3/SDL.h>
#include <algorithm>
#include <chrono>
@@ -89,7 +88,7 @@ struct InputProfile
std::string DeviceName;
std::string DevicePath;
std::string DeviceSerial;
int DeviceNum = -1;
InputDeviceType DeviceType = InputDeviceType::Invalid;
std::chrono::time_point<std::chrono::high_resolution_clock> LastDeviceCheckTime = std::chrono::high_resolution_clock::now();
// Gameboy information
@@ -97,7 +96,8 @@ struct InputProfile
std::string GameboySave;
// input device
Utilities::InputDevice InputDevice;
SDL_Joystick* SDLJoystick = nullptr;
SDL_Gamepad* SDLGamepad = nullptr;
// buttons
InputMapping Button_A;
@@ -204,7 +204,7 @@ static void (*l_DebugCallback)(void *, int, const char *) = nullptr;
static void *l_DebugCallContext = nullptr;
// keyboard state
static bool l_KeyboardState[SDL_NUM_SCANCODES];
static bool l_KeyboardState[SDL_SCANCODE_COUNT];
// config GUI state
static bool l_IsConfigGuiOpen = false;
@@ -309,23 +309,14 @@ static void load_settings(void)
profile->PluggedIn = CoreSettingsGetBoolValue(SettingsID::Input_PluggedIn, section);
profile->DeadzoneValue = CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section);
profile->ControllerPak = (N64ControllerPak)CoreSettingsGetIntValue(SettingsID::Input_Pak, section);
profile->ControllerPak = static_cast<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->DeviceType = static_cast<InputDeviceType>(CoreSettingsGetIntValue(SettingsID::Input_DeviceType, section));
profile->GameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section);
profile->GameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section);
// keep compatibility with profiles before version v0.3.9
if (CoreSettingsKeyExists(section, "Sensitivity"))
{
profile->SensitivityValue = CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section);
}
else
{
profile->SensitivityValue = 100;
}
profile->SensitivityValue = CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section);
#define LOAD_INPUT_MAPPING(mapping, setting) \
load_inputmapping_settings(&profile->mapping, section, SettingsID::setting##_Name, SettingsID::setting##_InputType, SettingsID::setting##_Data, SettingsID::setting##_ExtraData)
@@ -407,7 +398,7 @@ static void apply_controller_profiles(void)
{
InputProfile* profile = &l_InputProfiles[i];
int plugin = PLUGIN_NONE;
bool emulateVRU = (profile->DeviceNum == static_cast<int>(InputDeviceType::EmulateVRU));
bool emulateVRU = (profile->DeviceType == InputDeviceType::EmulateVRU);
switch (profile->ControllerPak)
{
@@ -448,6 +439,8 @@ static void apply_controller_profiles(void)
}
}
static void controller_rumble_stop(InputProfile* profile); // forward declaration
static void switch_controller_pak(InputProfile* profile, const int Control, const int pak)
{
const int currentPak = l_ControlInfo.Controls[Control].Plugin;
@@ -465,7 +458,7 @@ static void switch_controller_pak(InputProfile* profile, const int Control, cons
// ensure that we stop the controller's rumble
if (currentPak == PLUGIN_RAW)
{
profile->InputDevice.StopRumble();
controller_rumble_stop(profile);
}
}
@@ -498,93 +491,232 @@ static void apply_gameboy_settings(void)
CoreSettingsSave();
}
static void setup_device_automatic(int num, InputProfile* profile)
static std::string string_from_const_char(const char* str)
{
static int previousSdlDeviceNum = -1;
// reset variable when needed
if (num == 0)
std::string string;
if (str != nullptr)
{
previousSdlDeviceNum = -1;
string = str;
}
return string;
}
bool foundSdlDevice = false;
SDL_GameController* sdlGameController = nullptr;
SDL_Joystick* sdlJoystick = nullptr;
std::string sdlDeviceName;
static void open_controller_automatic(int index, InputProfile* profile, SDL_JoystickID* joysticks, int joysticksCount)
{
bool foundJoystick = false;
SDL_JoystickID joystickId;
std::string debugMessage;
for (int i = (previousSdlDeviceNum + 1); i < SDL_NumJoysticks(); i++)
std::string debugMessageBase;
debugMessageBase = "setup_device_automatic(";
debugMessageBase += std::to_string(index);
debugMessageBase += "): ";
for (int i = index; i < joysticksCount; i++)
{
if (SDL_IsGameController(i))
joystickId = joysticks[i];
if (SDL_IsGamepad(joystickId))
{
sdlGameController = SDL_GameControllerOpen(i);
if (sdlGameController != nullptr)
profile->SDLJoystick = SDL_OpenJoystick(joystickId);
profile->SDLGamepad = SDL_OpenGamepad(joystickId);
if (profile->SDLGamepad == nullptr)
{
sdlDeviceName = SDL_GameControllerName(sdlGameController);
SDL_GameControllerClose(sdlGameController);
profile->DeviceNum = i;
profile->DeviceName = sdlDeviceName;
previousSdlDeviceNum = i;
foundSdlDevice = true;
break;
debugMessage = debugMessageBase + "SDL_OpenGamepad Failed: ";
debugMessage += SDL_GetError();
PluginDebugMessage(M64MSG_ERROR, debugMessage);
continue;
}
debugMessage = debugMessageBase + "found gamepad: ";
debugMessage += string_from_const_char(SDL_GetGamepadName(profile->SDLGamepad));
PluginDebugMessage(M64MSG_VERBOSE, debugMessage);
foundJoystick = true;
break;
}
else
{
sdlJoystick = SDL_JoystickOpen(i);
if (sdlJoystick != nullptr)
profile->SDLJoystick = SDL_OpenJoystick(joystickId);
profile->SDLGamepad = nullptr;
if (profile->SDLJoystick == nullptr)
{
sdlDeviceName = SDL_JoystickName(sdlJoystick);
SDL_JoystickClose(sdlJoystick);
profile->DeviceNum = i;
profile->DeviceName = sdlDeviceName;
previousSdlDeviceNum = i;
foundSdlDevice = true;
break;
debugMessage = debugMessageBase + "SDL_OpenJoystick Failed: ";
debugMessage += SDL_GetError();
PluginDebugMessage(M64MSG_ERROR, debugMessage);
continue;
}
debugMessage = debugMessageBase + "found joystick: ";
debugMessage += string_from_const_char(SDL_GetJoystickName(profile->SDLJoystick));
PluginDebugMessage(M64MSG_VERBOSE, debugMessage);
foundJoystick = true;
break;
}
}
if (!foundSdlDevice)
if (!foundJoystick)
{ // fallback to keyboard
if (num == 0)
if (index == 0)
{
profile->DeviceNum = static_cast<int>(InputDeviceType::Keyboard);
debugMessage = debugMessageBase + "falling back to keyboard";
PluginDebugMessage(M64MSG_VERBOSE, debugMessage);
profile->DeviceType = InputDeviceType::Keyboard;
}
else
{
debugMessage = debugMessageBase + "no device found";
PluginDebugMessage(M64MSG_VERBOSE, debugMessage);
profile->PluggedIn = false;
// only override present in core
// when we have the control info
if (l_HasControlInfo)
{
l_ControlInfo.Controls[num].Present = 0;
l_ControlInfo.Controls[index].Present = 0;
}
}
}
}
static void open_controller(InputProfile* profile, SDL_JoystickID* joysticks, int joysticksCount)
{
SDL_JoystickID joystickId;
SDL_Joystick* joystick = nullptr;
SDL_Gamepad* gamepad = nullptr;
std::string errorMessage;
std::string deviceName;
std::string devicePath;
std::string deviceSerial;
for (int i = 0; i < joysticksCount; i++)
{
joystickId = joysticks[i];
if (SDL_IsGamepad(joystickId))
{
joystick = SDL_OpenJoystick(joystickId);
gamepad = SDL_OpenGamepad(joystickId);
if (gamepad == nullptr)
{
errorMessage = "open_controller(): SDL_OpenGamepad Failed: ";
errorMessage += SDL_GetError();
PluginDebugMessage(M64MSG_ERROR, errorMessage);
continue;
}
deviceName = string_from_const_char(SDL_GetGamepadName(gamepad));
devicePath = string_from_const_char(SDL_GetGamepadPath(gamepad));
deviceSerial = string_from_const_char(SDL_GetGamepadSerial(gamepad));
}
else
{
gamepad = nullptr;
joystick = SDL_OpenJoystick(joystickId);
if (joystick == nullptr)
{
errorMessage = "open_controller(): SDL_OpenJoystick Failed: ";
errorMessage += SDL_GetError();
PluginDebugMessage(M64MSG_ERROR, errorMessage);
continue;
}
deviceName = string_from_const_char(SDL_GetJoystickName(joystick));
devicePath = string_from_const_char(SDL_GetJoystickPath(joystick));
deviceSerial = string_from_const_char(SDL_GetJoystickSerial(joystick));
}
if (deviceName == profile->DeviceName &&
devicePath == profile->DevicePath &&
deviceSerial == profile->DeviceSerial)
{
profile->SDLJoystick = joystick;
profile->SDLGamepad = gamepad;
return;
}
if (joystick != nullptr)
{
SDL_CloseJoystick(joystick);
joystick = nullptr;
}
if (gamepad != nullptr)
{
SDL_CloseGamepad(gamepad);
gamepad = nullptr;
}
}
}
static void close_controller(InputProfile* profile)
{
if (profile->SDLJoystick != nullptr)
{
SDL_CloseJoystick(profile->SDLJoystick);
profile->SDLJoystick = nullptr;
}
if (profile->SDLGamepad != nullptr)
{
SDL_CloseGamepad(profile->SDLGamepad);
profile->SDLGamepad = nullptr;
}
}
static void controller_rumble_start(InputProfile* profile)
{
if (profile->SDLGamepad != nullptr)
{
SDL_RumbleGamepad(profile->SDLGamepad, 0xFFFF, 0xFFFF, SDL_HAPTIC_INFINITY);
}
else if (profile->SDLJoystick != nullptr)
{
SDL_RumbleJoystick(profile->SDLJoystick, 0xFFFF, 0xFFFF, SDL_HAPTIC_INFINITY);
}
}
static void controller_rumble_stop(InputProfile* profile)
{
if (profile->SDLGamepad != nullptr)
{
SDL_RumbleGamepad(profile->SDLGamepad, 0, 0, 0);
}
else if (profile->SDLJoystick != nullptr)
{
SDL_RumbleJoystick(profile->SDLJoystick, 0, 0, 0);
}
}
static void open_controllers(void)
{
// force re-fresh joystick list
SDL_JoystickUpdate();
SDL_UpdateJoysticks();
int joysticksCount = 0;
SDL_JoystickID* joysticks = SDL_GetJoysticks(&joysticksCount);
for (int i = 0; i < NUM_CONTROLLERS; i++)
{
InputProfile* profile = &l_InputProfiles[i];
profile->InputDevice.CloseDevice();
close_controller(profile);
if (profile->DeviceNum == static_cast<int>(InputDeviceType::Automatic))
if (profile->DeviceType == InputDeviceType::Automatic)
{
setup_device_automatic(i, profile);
open_controller_automatic(i, profile, joysticks, joysticksCount);
}
else if (profile->DeviceType == InputDeviceType::Joystick)
{
open_controller(profile, joysticks, joysticksCount);
}
}
if (profile->DeviceNum != static_cast<int>(InputDeviceType::Keyboard))
{
profile->InputDevice.OpenDevice(profile->DeviceName, profile->DevicePath, profile->DeviceSerial, profile->DeviceNum);
}
if (joysticks != nullptr)
{
SDL_free(joysticks);
}
}
@@ -594,7 +726,7 @@ static void close_controllers(void)
{
InputProfile* profile = &l_InputProfiles[i];
profile->InputDevice.CloseDevice();
close_controller(profile);
}
}
@@ -613,16 +745,16 @@ static int get_button_state(InputProfile* profile, const InputMapping* inputMapp
{
if (allPressed && i > 0)
{
state &= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
state &= SDL_GetGamepadButton(profile->SDLGamepad, (SDL_GamepadButton)data);
}
else
{
state |= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
state |= SDL_GetGamepadButton(profile->SDLGamepad, (SDL_GamepadButton)data);
}
} break;
case InputType::GamepadAxis:
{
int axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)data);
int axis_value = SDL_GetGamepadAxis(profile->SDLGamepad, (SDL_GamepadAxis)data);
if (allPressed && i > 0)
{
state &= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
@@ -636,27 +768,27 @@ static int get_button_state(InputProfile* profile, const InputMapping* inputMapp
{
if (allPressed && i > 0)
{
state &= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
state &= SDL_GetJoystickButton(profile->SDLJoystick, data);
}
else
{
state |= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
state |= SDL_GetJoystickButton(profile->SDLJoystick, data);
}
} break;
case InputType::JoystickHat:
{
if (allPressed && i > 0)
{
state &= (SDL_JoystickGetHat(profile->InputDevice.GetJoystickHandle(), data) & extraData) ? 1 : 0;
state &= (SDL_GetJoystickHat(profile->SDLJoystick, data) & extraData) ? 1 : 0;
}
else
{
state |= (SDL_JoystickGetHat(profile->InputDevice.GetJoystickHandle(), data) & extraData) ? 1 : 0;
state |= (SDL_GetJoystickHat(profile->SDLJoystick, data) & extraData) ? 1 : 0;
}
} break;
case InputType::JoystickAxis:
{
int axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), data);
int axis_value = SDL_GetJoystickAxis(profile->SDLJoystick, data);
if (allPressed && i > 0)
{
state &= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
@@ -706,11 +838,11 @@ static double get_axis_state(InputProfile* profile, const InputMapping* inputMap
{
case InputType::GamepadButton:
{
button_state |= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
button_state |= SDL_GetGamepadButton(profile->SDLGamepad, (SDL_GamepadButton)data);
} break;
case InputType::GamepadAxis:
{
double axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)data);
double axis_value = SDL_GetGamepadAxis(profile->SDLGamepad, (SDL_GamepadAxis)data);
if (axis_value < -32767.0) axis_value = -32767.0;
if (extraData ? axis_value > 0 : axis_value < 0)
{
@@ -721,15 +853,15 @@ static double get_axis_state(InputProfile* profile, const InputMapping* inputMap
} break;
case InputType::JoystickButton:
{
button_state |= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
button_state |= SDL_GetJoystickButton(profile->SDLJoystick, data);
} break;
case InputType::JoystickHat:
{
button_state |= (SDL_JoystickGetHat(profile->InputDevice.GetJoystickHandle(), data) & extraData) ? 1 : 0;
button_state |= (SDL_GetJoystickHat(profile->SDLJoystick, data) & extraData) ? 1 : 0;
} break;
case InputType::JoystickAxis:
{
double axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), data);
double axis_value = SDL_GetJoystickAxis(profile->SDLJoystick, data);
if (axis_value < -32767.0) axis_value = -32767.0;
if (extraData ? axis_value > 0 : axis_value < 0)
{
@@ -866,7 +998,7 @@ static bool check_hotkeys(int Control)
// we only have to check for hotkeys
// when there's a controller opened
if (!profile->InputDevice.HasOpenDevice())
if (profile->SDLJoystick == nullptr)
{
return false;
}
@@ -936,7 +1068,7 @@ static void sdl_init()
std::string debugMessage;
int ret = -1;
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_AUDIO, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
for (const int subsystem : {SDL_INIT_GAMEPAD, SDL_INIT_HAPTIC})
{
if (!SDL_WasInit(subsystem))
{
@@ -950,10 +1082,10 @@ static void sdl_init()
// try to load SDL_GameControllerDB when the file exists
if (std::filesystem::is_regular_file(gameControllerDbPath))
{
ret = SDL_GameControllerAddMappingsFromFile(gameControllerDbPath.string().c_str());
ret = SDL_AddGamepadMappingsFromFile(gameControllerDbPath.string().c_str());
if (ret == -1)
{
debugMessage = "sdl_init(): SDL_GameControllerAddMappingsFromFile Failed: ";
debugMessage = "sdl_init(): SDL_AddGamepadMappingsFromFile Failed: ";
debugMessage += SDL_GetError();
PluginDebugMessage(M64MSG_WARNING, debugMessage);
}
@@ -969,13 +1101,20 @@ static void sdl_init()
static void sdl_quit()
{
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_HAPTIC})
for (const int subsystem : {SDL_INIT_GAMEPAD, SDL_INIT_HAPTIC})
{
if (SDL_WasInit(subsystem))
{
SDL_QuitSubSystem(subsystem);
}
}
#ifdef VRU
if (HasVRUInitSDL() && SDL_WasInit(SDL_INIT_AUDIO))
{
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
#endif
}
//
@@ -998,11 +1137,6 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Con
l_SDLThread = new Thread::SDLThread(nullptr);
l_SDLThread->start();
for (int i = 0; i < NUM_CONTROLLERS; i++)
{
l_InputProfiles[i].InputDevice.SetSDLThread(l_SDLThread);
}
l_HotkeysThread = new Thread::HotkeysThread(check_hotkeys, nullptr);
l_HotkeysThread->start();
@@ -1184,11 +1318,11 @@ EXPORT void CALL ControllerCommand(int Control, unsigned char* Command)
{
if (*data)
{
profile->InputDevice.StartRumble();
controller_rumble_start(profile);
}
else
{
profile->InputDevice.StopRumble();
controller_rumble_stop(profile);
}
}
data[32] = data_crc( data, 32 );
@@ -1213,7 +1347,7 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
#ifdef VRU
// when we're emulating the VRU,
// we need to check the mic state
if (profile->DeviceNum == static_cast<int>(InputDeviceType::EmulateVRU))
if (profile->DeviceType == InputDeviceType::EmulateVRU)
{
if (GetVRUMicState())
{
@@ -1227,31 +1361,6 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
}
#endif // VRU
#if 0 // TODO: fix hotplug support
// check if device has been disconnected,
// if it has, try to open it again,
// only do this every 2 seconds to prevent lag
const auto currentTime = std::chrono::high_resolution_clock::now();
const int secondsPassed = std::chrono::duration_cast<std::chrono::seconds>(currentTime - profile->LastDeviceCheckTime).count();
if (secondsPassed >= 2)
{
profile->LastDeviceCheckTime = currentTime;
if (profile->DeviceNum != static_cast<int>(InputDeviceType::Keyboard))
{
if (profile->InputDevice.IsOpeningDevice())
{
return;
}
if (!profile->InputDevice.HasOpenDevice() || !profile->InputDevice.IsAttached())
{
profile->InputDevice.OpenDevice(profile->DeviceName, profile->DevicePath, profile->DeviceSerial, profile->DeviceNum);
}
}
}
#endif
// when we've matched a hotkey,
// we don't need to check anything
// else
@@ -1309,7 +1418,7 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)
{
for (int i = 0; i < SDL_NUM_SCANCODES; i++)
for (int i = 0; i < SDL_SCANCODE_COUNT; i++)
{
l_KeyboardState[i] = 0;
}