More work for remappable controllers

This commit is contained in:
SimoneN64
2024-09-28 14:54:24 +02:00
parent 8e78102794
commit b6f795a4df
8 changed files with 129 additions and 29 deletions

View File

@@ -61,25 +61,35 @@ InputSettings::InputSettings(nlohmann::json &settings) : QWidget(nullptr), setti
kbButtons[17] = std::make_unique<QPushButton>(str.c_str()); kbButtons[17] = std::make_unique<QPushButton>(str.c_str());
for (int i = 0; i < 18; i++) { for (int i = 0; i < 18; i++) {
connect(kbButtons[i].get(), &QPushButton::pressed, this, [&, i]() { connect(kbButtons[i].get(), &QPushButton::pressed, this, [&, i] {
devices->setEnabled(false); devices->setEnabled(false);
for (const auto &kbButton : kbButtons) { for (const auto &kbButton : kbButtons) {
kbButton->setEnabled(false); kbButton->setEnabled(false);
} }
grabKeyboard();
grabbing = true; grabbing = true;
whichGrabbing = i; whichGrabbing = i;
if (devices->currentText() == "Keyboard/Mouse") {
grabKeyboard();
} else {
selectedDeviceIsNotKeyboard = true;
}
}); });
} }
connect(devices.get(), &QComboBox::currentTextChanged, this, [&](const QString &text) {
JSONSetField<std::string>(settings, "input", "Device", text.toStdString());
emit modified();
});
SDL_InitSubSystem(SDL_INIT_GAMEPAD); SDL_InitSubSystem(SDL_INIT_GAMEPAD);
if (SDL_AddGamepadMappingsFromFile("resources/gamecontrollerdb.txt") < 0) {
Util::warn("[SDL] Could not load game controller DB");
}
connect(&refresh, &QTimer::timeout, this, &InputSettings::QueryDevices); connect(&refresh, &QTimer::timeout, this, &InputSettings::QueryDevices);
refresh.start(1000); refresh.start(16);
connect(&pollGamepad, &QTimer::timeout, this, &InputSettings::PollGamepad);
pollGamepad.start(16);
devices->addItem("Keyboard/Mouse"); devices->addItem("Keyboard/Mouse");
deviceComboBoxLayout->addWidget(devicesLabel.get()); deviceComboBoxLayout->addWidget(devicesLabel.get());
@@ -138,17 +148,21 @@ InputSettings::InputSettings(nlohmann::json &settings) : QWidget(nullptr), setti
void InputSettings::keyPressEvent(QKeyEvent *e) { void InputSettings::keyPressEvent(QKeyEvent *e) {
if (grabbing) { if (grabbing) {
const auto k = QKeySequence(e->key()).toString(); const auto k = QKeySequence(e->key()).toString().toStdString();
JSONSetField<std::string>(settings, "input", buttonLabels[whichGrabbing]->text().toStdString(), k.toStdString()); JSONSetField<std::string>(settings, "input", buttonLabels[whichGrabbing]->text().toStdString(), k);
kbButtons[whichGrabbing]->setText(k); kbButtons[whichGrabbing]->setText(k.c_str());
grabbing = false;
whichGrabbing = -1;
devices->setEnabled(true); devices->setEnabled(true);
for (const auto &kbButton : kbButtons) { for (const auto &kbButton : kbButtons) {
kbButton->setEnabled(true); kbButton->setEnabled(true);
} }
releaseKeyboard();
emit modified(); grabbing = false;
whichGrabbing = -1;
if (devices->currentText() == "Keyboard/Mouse") {
releaseKeyboard();
emit modified();
}
} }
} }
@@ -210,3 +224,32 @@ void InputSettings::QueryDevices() noexcept {
} }
} }
} }
void InputSettings::PollGamepad() noexcept {
if (!selectedDeviceIsNotKeyboard)
return;
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
{
const auto k = SDL_GetGamepadStringForButton(static_cast<SDL_GamepadButton>(e.gbutton.button));
JSONSetField<std::string>(settings, "input", buttonLabels[whichGrabbing]->text().toStdString(), k);
kbButtons[whichGrabbing]->setText(k);
devices->setEnabled(true);
for (const auto &kbButton : kbButtons) {
kbButton->setEnabled(true);
}
grabbing = false;
whichGrabbing = -1;
emit modified();
}
break;
default:
break;
}
}
}

View File

@@ -13,6 +13,7 @@ class InputSettings : public QWidget {
int whichGrabbing = -1; int whichGrabbing = -1;
void QueryDevices() noexcept; void QueryDevices() noexcept;
void PollGamepad() noexcept;
std::unordered_map<u32, std::string> gamepadIndexes{}; std::unordered_map<u32, std::string> gamepadIndexes{};
@@ -29,12 +30,13 @@ class InputSettings : public QWidget {
std::array<std::unique_ptr<QPushButton>, 18> kbButtons; std::array<std::unique_ptr<QPushButton>, 18> kbButtons;
std::array<std::unique_ptr<QLabel>, 18> buttonLabels; std::array<std::unique_ptr<QLabel>, 18> buttonLabels;
std::unique_ptr<QHBoxLayout> deviceComboBoxLayout = std::make_unique<QHBoxLayout>(); std::unique_ptr<QHBoxLayout> deviceComboBoxLayout = std::make_unique<QHBoxLayout>();
QTimer refresh; QTimer refresh, pollGamepad;
std::unique_ptr<QLabel> devicesLabel = std::make_unique<QLabel>("Device:"); std::unique_ptr<QLabel> devicesLabel = std::make_unique<QLabel>("Device:");
std::unique_ptr<QComboBox> devices = std::make_unique<QComboBox>(); std::unique_ptr<QComboBox> devices = std::make_unique<QComboBox>();
Q_OBJECT Q_OBJECT
public: public:
InputSettings(nlohmann::json &); bool selectedDeviceIsNotKeyboard = false;
explicit InputSettings(nlohmann::json &);
nlohmann::json &settings; nlohmann::json &settings;
void keyPressEvent(QKeyEvent *) override; void keyPressEvent(QKeyEvent *) override;
std::array<Qt::Key, 18> GetMappedKeys() const; std::array<Qt::Key, 18> GetMappedKeys() const;

View File

@@ -24,10 +24,17 @@ KaizenQt::KaizenQt() noexcept : QWidget(nullptr) {
mainWindow->show(); mainWindow->show();
debugger->hide(); debugger->hide();
settingsWindow->hide(); settingsWindow->hide();
connect(settingsWindow.get(), &SettingsWindow::regrabKeyboard, this, [&] { grabKeyboard(); });
} }
void KaizenQt::ConnectMainWindowSignalsToSlots() noexcept { void KaizenQt::ConnectMainWindowSignalsToSlots() noexcept {
connect(settingsWindow.get(), &SettingsWindow::regrabKeyboard, this, [&] { grabKeyboard(); });
connect(settingsWindow.get(), &SettingsWindow::gotClosed, this,
[&] { mainWindow->vulkanWidget->wsiPlatform->EnableEventPolling(); });
connect(settingsWindow.get(), &SettingsWindow::gotOpened, this,
[&] { mainWindow->vulkanWidget->wsiPlatform->DisableEventPolling(); });
connect(mainWindow.get(), &MainWindow::OpenSettings, this, [this] { settingsWindow->show(); }); connect(mainWindow.get(), &MainWindow::OpenSettings, this, [this] { settingsWindow->show(); });
connect(mainWindow.get(), &MainWindow::OpenDebugger, this, [this] { debugger->show(); }); connect(mainWindow.get(), &MainWindow::OpenDebugger, this, [this] { debugger->show(); });
connect(mainWindow.get(), &MainWindow::OpenROM, this, &KaizenQt::LoadROM); connect(mainWindow.get(), &MainWindow::OpenROM, this, &KaizenQt::LoadROM);
@@ -44,22 +51,22 @@ void KaizenQt::dragEnterEvent(QDragEnterEvent *event) {
} }
void KaizenQt::dropEvent(QDropEvent *event) { void KaizenQt::dropEvent(QDropEvent *event) {
auto path = event->mimeData()->urls()[0].toLocalFile(); const auto path = event->mimeData()->urls()[0].toLocalFile();
LoadROM(path); LoadROM(path);
} }
void KaizenQt::LoadROM(const QString &fileName) noexcept { void KaizenQt::LoadROM(const QString &path) const noexcept {
mainWindow->actionPause->setEnabled(true); mainWindow->actionPause->setEnabled(true);
mainWindow->actionReset->setEnabled(true); mainWindow->actionReset->setEnabled(true);
mainWindow->actionStop->setEnabled(true); mainWindow->actionStop->setEnabled(true);
emuThread->start(); emuThread->start();
emuThread->core->LoadROM(fileName.toStdString()); emuThread->core->LoadROM(path.toStdString());
auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB; const auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB;
mainWindow->setWindowTitle(emuThread->core->cpu->GetMem().rom.gameNameDB.c_str()); mainWindow->setWindowTitle(emuThread->core->cpu->GetMem().rom.gameNameDB.c_str());
Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB); Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB);
} }
void KaizenQt::Quit() noexcept { void KaizenQt::Quit() const noexcept {
if (emuThread) { if (emuThread) {
emuThread->requestInterruption(); emuThread->requestInterruption();
while (emuThread->isRunning()) while (emuThread->isRunning())
@@ -80,11 +87,14 @@ void KaizenQt::LoadTAS(const QString &fileName) const noexcept {
} }
void KaizenQt::keyPressEvent(QKeyEvent *e) { void KaizenQt::keyPressEvent(QKeyEvent *e) {
if (settingsWindow->inputSettings->selectedDeviceIsNotKeyboard)
return;
emuThread->core->pause = true; emuThread->core->pause = true;
n64::Mem &mem = emuThread->core->cpu->GetMem(); n64::Mem &mem = emuThread->core->cpu->GetMem();
n64::PIF &pif = mem.mmio.si.pif; n64::PIF &pif = mem.mmio.si.pif;
auto k = static_cast<Qt::Key>(e->key()); const auto k = static_cast<Qt::Key>(e->key());
for (int i = 0; i < 14; i++) { for (int i = 0; i < 14; i++) {
if (k == settingsWindow->keyMap[i]) if (k == settingsWindow->keyMap[i])
pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), true); pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), true);
@@ -104,11 +114,14 @@ void KaizenQt::keyPressEvent(QKeyEvent *e) {
} }
void KaizenQt::keyReleaseEvent(QKeyEvent *e) { void KaizenQt::keyReleaseEvent(QKeyEvent *e) {
if (settingsWindow->inputSettings->selectedDeviceIsNotKeyboard)
return;
emuThread->core->pause = true; emuThread->core->pause = true;
n64::Mem &mem = emuThread->core->cpu->GetMem(); n64::Mem &mem = emuThread->core->cpu->GetMem();
n64::PIF &pif = mem.mmio.si.pif; n64::PIF &pif = mem.mmio.si.pif;
auto k = static_cast<Qt::Key>(e->key()); const auto k = static_cast<Qt::Key>(e->key());
for (int i = 0; i < 14; i++) { for (int i = 0; i < 14; i++) {
if (k == settingsWindow->keyMap[i]) if (k == settingsWindow->keyMap[i])
pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), false); pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), false);

View File

@@ -27,14 +27,14 @@ class KaizenQt : public QWidget {
public: public:
KaizenQt() noexcept; KaizenQt() noexcept;
void LoadTAS(const QString &path) const noexcept; void LoadTAS(const QString &path) const noexcept;
void LoadROM(const QString &path) noexcept; void LoadROM(const QString &path) const noexcept;
void dropEvent(QDropEvent *) override; void dropEvent(QDropEvent *) override;
void dragEnterEvent(QDragEnterEvent *) override; void dragEnterEvent(QDragEnterEvent *) override;
void keyPressEvent(QKeyEvent *) override; void keyPressEvent(QKeyEvent *) override;
void keyReleaseEvent(QKeyEvent *) override; void keyReleaseEvent(QKeyEvent *) override;
private: private:
void Quit() noexcept; void Quit() const noexcept;
void ConnectMainWindowSignalsToSlots() noexcept; void ConnectMainWindowSignalsToSlots() noexcept;
std::unique_ptr<MainWindow> mainWindow; std::unique_ptr<MainWindow> mainWindow;
std::unique_ptr<SettingsWindow> settingsWindow; std::unique_ptr<SettingsWindow> settingsWindow;

View File

@@ -29,6 +29,39 @@ RenderWidget::RenderWidget(const std::shared_ptr<n64::Core> &core) : QWidget(nul
} }
void QtWSIPlatform::poll_input() { void QtWSIPlatform::poll_input() {
if (!canPollEvents)
return;
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_EVENT_GAMEPAD_ADDED:
{
const auto index = e.gdevice.which;
gamepad = SDL_OpenGamepad(index);
Util::info("Controller found!");
const auto serial = SDL_GetGamepadSerial(gamepad);
const auto name = SDL_GetGamepadName(gamepad);
const auto path = SDL_GetGamepadPath(gamepad);
Util::info("\tName: {}", name ? name : "Not available");
Util::info("\tSerial: {}", serial ? serial : "Not available");
Util::info("\tPath: {}", path ? path : "Not available");
gamepadConnected = true;
}
break;
case SDL_EVENT_GAMEPAD_REMOVED:
{
gamepadConnected = false;
SDL_CloseGamepad(gamepad);
}
break;
}
}
if (gamepadConnected) { if (gamepadConnected) {
n64::PIF &pif = core->cpu->GetMem().mmio.si.pif; n64::PIF &pif = core->cpu->GetMem().mmio.si.pif;
pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH)); pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH));

View File

@@ -80,6 +80,9 @@ public:
void event_frame_tick(double frame, double elapsed) override {} void event_frame_tick(double frame, double elapsed) override {}
void EnableEventPolling() { canPollEvents = true; }
void DisableEventPolling() { canPollEvents = false; }
const VkApplicationInfo *get_application_info() override { return &appInfo; } const VkApplicationInfo *get_application_info() override { return &appInfo; }
VkApplicationInfo appInfo{.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .apiVersion = VK_API_VERSION_1_3}; VkApplicationInfo appInfo{.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .apiVersion = VK_API_VERSION_1_3};
@@ -90,6 +93,7 @@ private:
std::shared_ptr<n64::Core> core; std::shared_ptr<n64::Core> core;
SDL_Gamepad *gamepad{}; SDL_Gamepad *gamepad{};
bool gamepadConnected = false; bool gamepadConnected = false;
bool canPollEvents = true;
}; };
class RenderWidget : public QWidget { class RenderWidget : public QWidget {
@@ -99,7 +103,7 @@ public:
[[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; } [[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; }
std::shared_ptr<ParallelRDP::WindowInfo> windowInfo; std::shared_ptr<ParallelRDP::WindowInfo> windowInfo;
std::shared_ptr<Vulkan::WSIPlatform> wsiPlatform; std::shared_ptr<QtWSIPlatform> wsiPlatform;
std::shared_ptr<QtInstanceFactory> qtVkInstanceFactory; std::shared_ptr<QtInstanceFactory> qtVkInstanceFactory;
Q_SIGNALS: Q_SIGNALS:
void Show() { show(); } void Show() { show(); }

View File

@@ -52,7 +52,7 @@ SettingsWindow::SettingsWindow() : QWidget(nullptr) {
connect(apply.get(), &QPushButton::pressed, this, [&]() { connect(apply.get(), &QPushButton::pressed, this, [&]() {
auto newMap = inputSettings->GetMappedKeys(); auto newMap = inputSettings->GetMappedKeys();
if (!std::equal(keyMap.begin(), keyMap.end(), newMap.begin(), newMap.end())) { if (!std::ranges::equal(keyMap, newMap)) {
keyMap = newMap; keyMap = newMap;
emit regrabKeyboard(); emit regrabKeyboard();
} }

View File

@@ -25,15 +25,20 @@ class SettingsWindow : public QWidget {
std::unique_ptr<QHBoxLayout> buttonsLayout = std::make_unique<QHBoxLayout>(); std::unique_ptr<QHBoxLayout> buttonsLayout = std::make_unique<QHBoxLayout>();
Q_OBJECT Q_OBJECT
public: public:
SettingsWindow();
void hideEvent(QHideEvent *event) override { emit gotClosed(); }
void showEvent(QShowEvent *event) override { emit gotOpened(); }
float getVolumeL() { return float(audioSettings->volumeL->value()) / 100.f; } float getVolumeL() { return float(audioSettings->volumeL->value()) / 100.f; }
float getVolumeR() { return float(audioSettings->volumeR->value()) / 100.f; } float getVolumeR() { return float(audioSettings->volumeR->value()) / 100.f; }
std::array<Qt::Key, 18> keyMap{}; std::array<Qt::Key, 18> keyMap{};
SettingsWindow();
nlohmann::json settings; nlohmann::json settings;
std::unique_ptr<CPUSettings> cpuSettings{}; std::unique_ptr<CPUSettings> cpuSettings{};
std::unique_ptr<AudioSettings> audioSettings{}; std::unique_ptr<AudioSettings> audioSettings{};
std::unique_ptr<InputSettings> inputSettings{}; std::unique_ptr<InputSettings> inputSettings{};
std::unique_ptr<QWidget> generalSettings{}; std::unique_ptr<QWidget> generalSettings{};
Q_SIGNALS: Q_SIGNALS:
void gotOpened();
void gotClosed();
void regrabKeyboard(); void regrabKeyboard();
}; };