More work for remappable controllers
This commit is contained in:
@@ -61,25 +61,35 @@ InputSettings::InputSettings(nlohmann::json &settings) : QWidget(nullptr), setti
|
||||
kbButtons[17] = std::make_unique<QPushButton>(str.c_str());
|
||||
|
||||
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);
|
||||
for (const auto &kbButton : kbButtons) {
|
||||
kbButton->setEnabled(false);
|
||||
}
|
||||
grabKeyboard();
|
||||
|
||||
grabbing = true;
|
||||
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);
|
||||
|
||||
if (SDL_AddGamepadMappingsFromFile("resources/gamecontrollerdb.txt") < 0) {
|
||||
Util::warn("[SDL] Could not load game controller DB");
|
||||
}
|
||||
|
||||
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");
|
||||
deviceComboBoxLayout->addWidget(devicesLabel.get());
|
||||
@@ -138,19 +148,23 @@ InputSettings::InputSettings(nlohmann::json &settings) : QWidget(nullptr), setti
|
||||
|
||||
void InputSettings::keyPressEvent(QKeyEvent *e) {
|
||||
if (grabbing) {
|
||||
const auto k = QKeySequence(e->key()).toString();
|
||||
JSONSetField<std::string>(settings, "input", buttonLabels[whichGrabbing]->text().toStdString(), k.toStdString());
|
||||
kbButtons[whichGrabbing]->setText(k);
|
||||
grabbing = false;
|
||||
whichGrabbing = -1;
|
||||
const auto k = QKeySequence(e->key()).toString().toStdString();
|
||||
JSONSetField<std::string>(settings, "input", buttonLabels[whichGrabbing]->text().toStdString(), k);
|
||||
kbButtons[whichGrabbing]->setText(k.c_str());
|
||||
devices->setEnabled(true);
|
||||
for (const auto &kbButton : kbButtons) {
|
||||
kbButton->setEnabled(true);
|
||||
}
|
||||
|
||||
grabbing = false;
|
||||
whichGrabbing = -1;
|
||||
|
||||
if (devices->currentText() == "Keyboard/Mouse") {
|
||||
releaseKeyboard();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::array<Qt::Key, 18> InputSettings::GetMappedKeys() const {
|
||||
std::array<Qt::Key, 18> ret{};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class InputSettings : public QWidget {
|
||||
int whichGrabbing = -1;
|
||||
|
||||
void QueryDevices() noexcept;
|
||||
void PollGamepad() noexcept;
|
||||
|
||||
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<QLabel>, 18> buttonLabels;
|
||||
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<QComboBox> devices = std::make_unique<QComboBox>();
|
||||
Q_OBJECT
|
||||
public:
|
||||
InputSettings(nlohmann::json &);
|
||||
bool selectedDeviceIsNotKeyboard = false;
|
||||
explicit InputSettings(nlohmann::json &);
|
||||
nlohmann::json &settings;
|
||||
void keyPressEvent(QKeyEvent *) override;
|
||||
std::array<Qt::Key, 18> GetMappedKeys() const;
|
||||
|
||||
@@ -24,10 +24,17 @@ KaizenQt::KaizenQt() noexcept : QWidget(nullptr) {
|
||||
mainWindow->show();
|
||||
debugger->hide();
|
||||
settingsWindow->hide();
|
||||
connect(settingsWindow.get(), &SettingsWindow::regrabKeyboard, this, [&] { grabKeyboard(); });
|
||||
}
|
||||
|
||||
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::OpenDebugger, this, [this] { debugger->show(); });
|
||||
connect(mainWindow.get(), &MainWindow::OpenROM, this, &KaizenQt::LoadROM);
|
||||
@@ -44,22 +51,22 @@ void KaizenQt::dragEnterEvent(QDragEnterEvent *event) {
|
||||
}
|
||||
|
||||
void KaizenQt::dropEvent(QDropEvent *event) {
|
||||
auto path = event->mimeData()->urls()[0].toLocalFile();
|
||||
const auto path = event->mimeData()->urls()[0].toLocalFile();
|
||||
LoadROM(path);
|
||||
}
|
||||
|
||||
void KaizenQt::LoadROM(const QString &fileName) noexcept {
|
||||
void KaizenQt::LoadROM(const QString &path) const noexcept {
|
||||
mainWindow->actionPause->setEnabled(true);
|
||||
mainWindow->actionReset->setEnabled(true);
|
||||
mainWindow->actionStop->setEnabled(true);
|
||||
emuThread->start();
|
||||
emuThread->core->LoadROM(fileName.toStdString());
|
||||
auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB;
|
||||
emuThread->core->LoadROM(path.toStdString());
|
||||
const auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB;
|
||||
mainWindow->setWindowTitle(emuThread->core->cpu->GetMem().rom.gameNameDB.c_str());
|
||||
Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB);
|
||||
}
|
||||
|
||||
void KaizenQt::Quit() noexcept {
|
||||
void KaizenQt::Quit() const noexcept {
|
||||
if (emuThread) {
|
||||
emuThread->requestInterruption();
|
||||
while (emuThread->isRunning())
|
||||
@@ -80,11 +87,14 @@ void KaizenQt::LoadTAS(const QString &fileName) const noexcept {
|
||||
}
|
||||
|
||||
void KaizenQt::keyPressEvent(QKeyEvent *e) {
|
||||
if (settingsWindow->inputSettings->selectedDeviceIsNotKeyboard)
|
||||
return;
|
||||
|
||||
emuThread->core->pause = true;
|
||||
n64::Mem &mem = emuThread->core->cpu->GetMem();
|
||||
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++) {
|
||||
if (k == settingsWindow->keyMap[i])
|
||||
pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), true);
|
||||
@@ -104,11 +114,14 @@ void KaizenQt::keyPressEvent(QKeyEvent *e) {
|
||||
}
|
||||
|
||||
void KaizenQt::keyReleaseEvent(QKeyEvent *e) {
|
||||
if (settingsWindow->inputSettings->selectedDeviceIsNotKeyboard)
|
||||
return;
|
||||
|
||||
emuThread->core->pause = true;
|
||||
n64::Mem &mem = emuThread->core->cpu->GetMem();
|
||||
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++) {
|
||||
if (k == settingsWindow->keyMap[i])
|
||||
pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), false);
|
||||
|
||||
@@ -27,14 +27,14 @@ class KaizenQt : public QWidget {
|
||||
public:
|
||||
KaizenQt() 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 dragEnterEvent(QDragEnterEvent *) override;
|
||||
void keyPressEvent(QKeyEvent *) override;
|
||||
void keyReleaseEvent(QKeyEvent *) override;
|
||||
|
||||
private:
|
||||
void Quit() noexcept;
|
||||
void Quit() const noexcept;
|
||||
void ConnectMainWindowSignalsToSlots() noexcept;
|
||||
std::unique_ptr<MainWindow> mainWindow;
|
||||
std::unique_ptr<SettingsWindow> settingsWindow;
|
||||
|
||||
@@ -29,6 +29,39 @@ RenderWidget::RenderWidget(const std::shared_ptr<n64::Core> &core) : QWidget(nul
|
||||
}
|
||||
|
||||
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) {
|
||||
n64::PIF &pif = core->cpu->GetMem().mmio.si.pif;
|
||||
pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH));
|
||||
|
||||
@@ -80,6 +80,9 @@ public:
|
||||
|
||||
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; }
|
||||
|
||||
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;
|
||||
SDL_Gamepad *gamepad{};
|
||||
bool gamepadConnected = false;
|
||||
bool canPollEvents = true;
|
||||
};
|
||||
|
||||
class RenderWidget : public QWidget {
|
||||
@@ -99,7 +103,7 @@ public:
|
||||
|
||||
[[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; }
|
||||
std::shared_ptr<ParallelRDP::WindowInfo> windowInfo;
|
||||
std::shared_ptr<Vulkan::WSIPlatform> wsiPlatform;
|
||||
std::shared_ptr<QtWSIPlatform> wsiPlatform;
|
||||
std::shared_ptr<QtInstanceFactory> qtVkInstanceFactory;
|
||||
Q_SIGNALS:
|
||||
void Show() { show(); }
|
||||
|
||||
@@ -52,7 +52,7 @@ SettingsWindow::SettingsWindow() : QWidget(nullptr) {
|
||||
|
||||
connect(apply.get(), &QPushButton::pressed, this, [&]() {
|
||||
auto newMap = inputSettings->GetMappedKeys();
|
||||
if (!std::equal(keyMap.begin(), keyMap.end(), newMap.begin(), newMap.end())) {
|
||||
if (!std::ranges::equal(keyMap, newMap)) {
|
||||
keyMap = newMap;
|
||||
emit regrabKeyboard();
|
||||
}
|
||||
|
||||
@@ -25,15 +25,20 @@ class SettingsWindow : public QWidget {
|
||||
std::unique_ptr<QHBoxLayout> buttonsLayout = std::make_unique<QHBoxLayout>();
|
||||
Q_OBJECT
|
||||
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 getVolumeR() { return float(audioSettings->volumeR->value()) / 100.f; }
|
||||
|
||||
std::array<Qt::Key, 18> keyMap{};
|
||||
SettingsWindow();
|
||||
nlohmann::json settings;
|
||||
std::unique_ptr<CPUSettings> cpuSettings{};
|
||||
std::unique_ptr<AudioSettings> audioSettings{};
|
||||
std::unique_ptr<InputSettings> inputSettings{};
|
||||
std::unique_ptr<QWidget> generalSettings{};
|
||||
Q_SIGNALS:
|
||||
void gotOpened();
|
||||
void gotClosed();
|
||||
void regrabKeyboard();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user