From 796d6033322fbd5870649c2d7a856abf81ca6b65 Mon Sep 17 00:00:00 2001 From: Rayyan Ansari <68647953+RayyanAnsari@users.noreply.github.com> Date: Thu, 30 Sep 2021 17:23:25 +0000 Subject: Redesign the Input dialog (#1226) --- .../qt_sdl/InputConfig/InputConfigDialog.cpp | 253 +++ .../qt_sdl/InputConfig/InputConfigDialog.h | 74 + .../qt_sdl/InputConfig/InputConfigDialog.ui | 2123 ++++++++++++++++++++ src/frontend/qt_sdl/InputConfig/MapButton.h | 355 ++++ .../qt_sdl/InputConfig/resources/LICENSE.md | 6 + src/frontend/qt_sdl/InputConfig/resources/ds.qrc | 6 + .../qt_sdl/InputConfig/resources/ds_back.svg | 182 ++ .../qt_sdl/InputConfig/resources/ds_open.svg | 169 ++ 8 files changed, 3168 insertions(+) create mode 100644 src/frontend/qt_sdl/InputConfig/InputConfigDialog.cpp create mode 100644 src/frontend/qt_sdl/InputConfig/InputConfigDialog.h create mode 100644 src/frontend/qt_sdl/InputConfig/InputConfigDialog.ui create mode 100644 src/frontend/qt_sdl/InputConfig/MapButton.h create mode 100644 src/frontend/qt_sdl/InputConfig/resources/LICENSE.md create mode 100644 src/frontend/qt_sdl/InputConfig/resources/ds.qrc create mode 100644 src/frontend/qt_sdl/InputConfig/resources/ds_back.svg create mode 100644 src/frontend/qt_sdl/InputConfig/resources/ds_open.svg (limited to 'src/frontend/qt_sdl/InputConfig') diff --git a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.cpp b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.cpp new file mode 100644 index 0000000..4ed843e --- /dev/null +++ b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.cpp @@ -0,0 +1,253 @@ +/* + Copyright 2016-2021 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include +#include +#include +#include + +#include + +#include "types.h" +#include "Config.h" +#include "PlatformConfig.h" + +#include "MapButton.h" +#include "Input.h" +#include "InputConfigDialog.h" +#include "ui_InputConfigDialog.h" + + +InputConfigDialog* InputConfigDialog::currentDlg = nullptr; + +const int dskeyorder[12] = {0, 1, 10, 11, 5, 4, 6, 7, 9, 8, 2, 3}; +const char* dskeylabels[12] = {"A", "B", "X", "Y", "Left", "Right", "Up", "Down", "L", "R", "Select", "Start"}; + +const int hk_addons[] = +{ + HK_SolarSensorIncrease, + HK_SolarSensorDecrease, +}; + +const char* hk_addons_labels[] = +{ + "[Boktai] Sunlight + ", + "[Boktai] Sunlight - ", +}; + +const int hk_general[] = +{ + HK_Pause, + HK_Reset, + HK_FrameStep, + HK_FastForward, + HK_FastForwardToggle, + HK_FullscreenToggle, + HK_Lid, + HK_Mic, + HK_SwapScreens +}; + +const char* hk_general_labels[] = +{ + "Pause/resume", + "Reset", + "Frame step", + "Fast forward", + "Toggle FPS limit", + "Toggle Fullscreen", + "Close/open lid", + "Microphone", + "Swap screens" +}; + +const int keypad_num = 12; +const int hk_addons_num = 2; +const int hk_general_num = 9; + + +InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new Ui::InputConfigDialog) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + + for (int i = 0; i < keypad_num; i++) + { + keypadKeyMap[i] = Config::KeyMapping[dskeyorder[i]]; + keypadJoyMap[i] = Config::JoyMapping[dskeyorder[i]]; + } + + for (int i = 0; i < hk_addons_num; i++) + { + addonsKeyMap[i] = Config::HKKeyMapping[hk_addons[i]]; + addonsJoyMap[i] = Config::HKJoyMapping[hk_addons[i]]; + } + + for (int i = 0; i < hk_general_num; i++) + { + hkGeneralKeyMap[i] = Config::HKKeyMapping[hk_general[i]]; + hkGeneralJoyMap[i] = Config::HKJoyMapping[hk_general[i]]; + } + + populatePage(ui->tabAddons, hk_addons_num, hk_addons_labels, addonsKeyMap, addonsJoyMap); + populatePage(ui->tabHotkeysGeneral, hk_general_num, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap); + + int njoy = SDL_NumJoysticks(); + if (njoy > 0) + { + for (int i = 0; i < njoy; i++) + { + const char* name = SDL_JoystickNameForIndex(i); + ui->cbxJoystick->addItem(QString(name)); + } + ui->cbxJoystick->setCurrentIndex(Input::JoystickID); + } + else + { + ui->cbxJoystick->addItem("(no joysticks available)"); + ui->cbxJoystick->setEnabled(false); + } + + setupKeypadPage(); +} + +InputConfigDialog::~InputConfigDialog() +{ + delete ui; +} + +void InputConfigDialog::setupKeypadPage() +{ + for (int i = 0; i < keypad_num; i++) + { + QPushButton* pushButtonKey = this->findChild(QStringLiteral("btnKey") + dskeylabels[i]); + QPushButton* pushButtonJoy = this->findChild(QStringLiteral("btnJoy") + dskeylabels[i]); + + KeyMapButton* keyMapButtonKey = new KeyMapButton(&keypadKeyMap[i], false); + JoyMapButton* keyMapButtonJoy = new JoyMapButton(&keypadJoyMap[i], false); + + pushButtonKey->parentWidget()->layout()->replaceWidget(pushButtonKey, keyMapButtonKey); + pushButtonJoy->parentWidget()->layout()->replaceWidget(pushButtonJoy, keyMapButtonJoy); + + delete pushButtonKey; + delete pushButtonJoy; + + if (ui->cbxJoystick->isEnabled()) + { + ui->stackMapping->setCurrentIndex(1); + } + } +} + +void InputConfigDialog::populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap) +{ + // kind of a hack + bool ishotkey = (page != ui->tabInput); + + QHBoxLayout* main_layout = new QHBoxLayout(); + + QGroupBox* group; + QGridLayout* group_layout; + + group = new QGroupBox("Keyboard mappings:"); + main_layout->addWidget(group); + group_layout = new QGridLayout(); + group_layout->setSpacing(1); + for (int i = 0; i < num; i++) + { + QLabel* label = new QLabel(QString(labels[i])+":"); + KeyMapButton* btn = new KeyMapButton(&keymap[i], ishotkey); + + group_layout->addWidget(label, i, 0); + group_layout->addWidget(btn, i, 1); + } + group_layout->setRowStretch(num, 1); + group->setLayout(group_layout); + group->setMinimumWidth(275); + + group = new QGroupBox("Joystick mappings:"); + main_layout->addWidget(group); + group_layout = new QGridLayout(); + group_layout->setSpacing(1); + for (int i = 0; i < num; i++) + { + QLabel* label = new QLabel(QString(labels[i])+":"); + JoyMapButton* btn = new JoyMapButton(&joymap[i], ishotkey); + + group_layout->addWidget(label, i, 0); + group_layout->addWidget(btn, i, 1); + } + group_layout->setRowStretch(num, 1); + group->setLayout(group_layout); + group->setMinimumWidth(275); + + page->setLayout(main_layout); +} + +void InputConfigDialog::on_InputConfigDialog_accepted() +{ + for (int i = 0; i < 12; i++) + { + Config::KeyMapping[dskeyorder[i]] = keypadKeyMap[i]; + Config::JoyMapping[dskeyorder[i]] = keypadJoyMap[i]; + } + + for (int i = 0; i < 2; i++) + { + Config::HKKeyMapping[hk_addons[i]] = addonsKeyMap[i]; + Config::HKJoyMapping[hk_addons[i]] = addonsJoyMap[i]; + } + + for (int i = 0; i < 9; i++) + { + Config::HKKeyMapping[hk_general[i]] = hkGeneralKeyMap[i]; + Config::HKJoyMapping[hk_general[i]] = hkGeneralJoyMap[i]; + } + + Config::JoystickID = Input::JoystickID; + Config::Save(); + + closeDlg(); +} + +void InputConfigDialog::on_InputConfigDialog_rejected() +{ + Input::JoystickID = Config::JoystickID; + Input::OpenJoystick(); + + closeDlg(); +} + +void InputConfigDialog::on_btnKeyMapSwitch_clicked() +{ + ui->stackMapping->setCurrentIndex(0); +} + +void InputConfigDialog::on_btnJoyMapSwitch_clicked() +{ + ui->stackMapping->setCurrentIndex(1); +} + +void InputConfigDialog::on_cbxJoystick_currentIndexChanged(int id) +{ + // prevent a spurious change + if (ui->cbxJoystick->count() < 2) return; + + Input::JoystickID = id; + Input::OpenJoystick(); +} diff --git a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h new file mode 100644 index 0000000..069dfcb --- /dev/null +++ b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h @@ -0,0 +1,74 @@ +/* + Copyright 2016-2021 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef INPUTCONFIGDIALOG_H +#define INPUTCONFIGDIALOG_H + +#include +#include + +namespace Ui { class InputConfigDialog; } +class InputConfigDialog; + +class InputConfigDialog : public QDialog +{ + Q_OBJECT + +public: + explicit InputConfigDialog(QWidget* parent); + ~InputConfigDialog(); + + static InputConfigDialog* currentDlg; + static InputConfigDialog* openDlg(QWidget* parent) + { + if (currentDlg) + { + currentDlg->activateWindow(); + return currentDlg; + } + + currentDlg = new InputConfigDialog(parent); + currentDlg->open(); + return currentDlg; + } + static void closeDlg() + { + currentDlg = nullptr; + } + +private slots: + void on_InputConfigDialog_accepted(); + void on_InputConfigDialog_rejected(); + + void on_btnKeyMapSwitch_clicked(); + void on_btnJoyMapSwitch_clicked(); + void on_cbxJoystick_currentIndexChanged(int id); + +private: + void populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap); + void setupKeypadPage(); + + Ui::InputConfigDialog* ui; + + int keypadKeyMap[12], keypadJoyMap[12]; + int addonsKeyMap[2], addonsJoyMap[2]; + int hkGeneralKeyMap[9], hkGeneralJoyMap[9]; +}; + + +#endif // INPUTCONFIGDIALOG_H diff --git a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.ui b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.ui new file mode 100644 index 0000000..6f4bb5d --- /dev/null +++ b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.ui @@ -0,0 +1,2123 @@ + + + InputConfigDialog + + + + 0 + 0 + 710 + 709 + + + + Input and hotkeys - melonDS + + + #grp_ControlPad, #grp_ABXY, #grp_ControlPad_2, #grp_ABXY_2 { border: none } + + + + QLayout::SetFixedSize + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Joystick: + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Selects which joystick will be used for joystick input, if any is present.</p></body></html> + + + + + + + + + 0 + + + + DS keypad + + + + + + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + L + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + L + + + + + + + + + + + + + + + + :/ds/ds_back.svg + + + false + + + + + + + + + + :/ds/ds_open.svg + + + false + + + + + + + + 0 + 0 + + + + + + + false + + + false + + + + 0 + + + 3 + + + 0 + + + 3 + + + 3 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + X + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + X + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Y + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Y + + + + + + + + + + A + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + A + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + B + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + B + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + + + + + 0 + 0 + + + + + + + false + + + false + + + + 0 + + + 3 + + + 0 + + + 3 + + + 3 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Up + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Up + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Left + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Left + + + + + + + + + + Right + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Right + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Down + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Down + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + + + + + 15 + + + + Keyboard mappings + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Switch to Joystick mappings + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 3 + + + + + Select + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Select + + + + + + + + + + Start + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Start + + + + + + + + + + + + + + + R + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + R + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + L + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + L + + + + + + + + + + + + + + 0 + 0 + + + + + + + false + + + false + + + + 0 + + + 3 + + + 0 + + + 3 + + + 3 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + X + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + X + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Y + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Y + + + + + + + + + + A + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + A + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + B + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + B + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + + + + + 0 + 0 + + + + + + + false + + + false + + + + 0 + + + 3 + + + 0 + + + 3 + + + 3 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Up + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Up + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Left + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Left + + + + + + + + + + Right + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Right + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Down + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Down + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + + + + + + + :/ds/ds_open.svg + + + false + + + + + + + + 15 + + + + Joystick mappings + + + Qt::AlignCenter + + + + + + + + + + :/ds/ds_back.svg + + + false + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Switch to Keyboard mappings + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 3 + + + + + Select + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Select + + + + + + + + + + Start + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Start + + + + + + + + + + + + + + + R + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 72 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + R + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + Add-ons + + + + + General hotkeys + + + + + + + + + + + + buttonBox + accepted() + InputConfigDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + InputConfigDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/frontend/qt_sdl/InputConfig/MapButton.h b/src/frontend/qt_sdl/InputConfig/MapButton.h new file mode 100644 index 0000000..a1b1a16 --- /dev/null +++ b/src/frontend/qt_sdl/InputConfig/MapButton.h @@ -0,0 +1,355 @@ +/* + Copyright 2016-2021 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef MAPBUTTON_H +#define MAPBUTTON_H + +#include + +#include + +#include "Input.h" + +class KeyMapButton : public QPushButton +{ + Q_OBJECT + +public: + KeyMapButton(int* mapping, bool hotkey) : QPushButton() + { + this->mapping = mapping; + this->isHotkey = hotkey; + + setCheckable(true); + setText(mappingText()); + setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS + + connect(this, &KeyMapButton::clicked, this, &KeyMapButton::onClick); + } + + ~KeyMapButton() + { + } + +protected: + void keyPressEvent(QKeyEvent* event) override + { + if (!isChecked()) return QPushButton::keyPressEvent(event); + + printf("KEY PRESSED = %08X %08X | %08X %08X %08X\n", event->key(), (int)event->modifiers(), event->nativeVirtualKey(), event->nativeModifiers(), event->nativeScanCode()); + + int key = event->key(); + int mod = event->modifiers(); + bool ismod = (key == Qt::Key_Control || + key == Qt::Key_Alt || + key == Qt::Key_AltGr || + key == Qt::Key_Shift || + key == Qt::Key_Meta); + + if (!mod) + { + if (key == Qt::Key_Escape) { click(); return; } + if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; } + } + + if (isHotkey) + { + if (ismod) + return; + } + + if (!ismod) + key |= mod; + else if (Input::IsRightModKey(event)) + key |= (1<<31); + + *mapping = key; + click(); + } + + void focusOutEvent(QFocusEvent* event) override + { + if (isChecked()) + { + // if we lost the focus while mapping, consider it 'done' + click(); + } + + QPushButton::focusOutEvent(event); + } + + bool focusNextPrevChild(bool next) override { return false; } + +private slots: + void onClick() + { + if (isChecked()) + { + setText("[press key]"); + } + else + { + setText(mappingText()); + } + } + +private: + QString mappingText() + { + int key = *mapping; + + if (key == -1) return "None"; + + QString isright = (key & (1<<31)) ? "Right " : "Left "; + key &= ~(1<<31); + + #ifndef __APPLE__ + switch (key) + { + case Qt::Key_Control: return isright + "Ctrl"; + case Qt::Key_Alt: return "Alt"; + case Qt::Key_AltGr: return "AltGr"; + case Qt::Key_Shift: return isright + "Shift"; + case Qt::Key_Meta: return "Meta"; + } + #else + switch (key) + { + case Qt::Key_Control: return isright + "⌘"; + case Qt::Key_Alt: return isright + "⌥"; + case Qt::Key_Shift: return isright + "⇧"; + case Qt::Key_Meta: return isright + "⌃"; + } + #endif + + QKeySequence seq(key); + QString ret = seq.toString(QKeySequence::NativeText); + + // weak attempt at detecting garbage key names + //if (ret.length() == 2 && ret[0].unicode() > 0xFF) + // return QString("[%1]").arg(key, 8, 16); + + return ret.replace("&", "&&"); + } + + int* mapping; + bool isHotkey; +}; + +class JoyMapButton : public QPushButton +{ + Q_OBJECT + +public: + JoyMapButton(int* mapping, bool hotkey) : QPushButton() + { + this->mapping = mapping; + this->isHotkey = hotkey; + + setCheckable(true); + setText(mappingText()); + + connect(this, &JoyMapButton::clicked, this, &JoyMapButton::onClick); + + timerID = 0; + } + + ~JoyMapButton() + { + } + +protected: + void keyPressEvent(QKeyEvent* event) override + { + if (!isChecked()) return QPushButton::keyPressEvent(event); + + int key = event->key(); + int mod = event->modifiers(); + + if (!mod) + { + if (key == Qt::Key_Escape) { click(); return; } + if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; } + } + } + + void focusOutEvent(QFocusEvent* event) override + { + if (isChecked()) + { + // if we lost the focus while mapping, consider it 'done' + click(); + } + + QPushButton::focusOutEvent(event); + } + + void timerEvent(QTimerEvent* event) override + { + SDL_Joystick* joy = Input::Joystick; + if (!joy) { click(); return; } + if (!SDL_JoystickGetAttached(joy)) { click(); return; } + + int oldmap; + if (*mapping == -1) oldmap = 0xFFFF; + else oldmap = *mapping; + + int nbuttons = SDL_JoystickNumButtons(joy); + for (int i = 0; i < nbuttons; i++) + { + if (SDL_JoystickGetButton(joy, i)) + { + *mapping = (oldmap & 0xFFFF0000) | i; + click(); + return; + } + } + + int nhats = SDL_JoystickNumHats(joy); + if (nhats > 16) nhats = 16; + for (int i = 0; i < nhats; i++) + { + Uint8 blackhat = SDL_JoystickGetHat(joy, i); + if (blackhat) + { + if (blackhat & 0x1) blackhat = 0x1; + else if (blackhat & 0x2) blackhat = 0x2; + else if (blackhat & 0x4) blackhat = 0x4; + else blackhat = 0x8; + + *mapping = (oldmap & 0xFFFF0000) | 0x100 | blackhat | (i << 4); + click(); + return; + } + } + + int naxes = SDL_JoystickNumAxes(joy); + if (naxes > 16) naxes = 16; + for (int i = 0; i < naxes; i++) + { + Sint16 axisval = SDL_JoystickGetAxis(joy, i); + int diff = abs(axisval - axesRest[i]); + + if (axesRest[i] < -16384 && axisval >= 0) + { + *mapping = (oldmap & 0xFFFF) | 0x10000 | (2 << 20) | (i << 24); + click(); + return; + } + else if (diff > 16384) + { + int axistype; + if (axisval > 0) axistype = 0; + else axistype = 1; + + *mapping = (oldmap & 0xFFFF) | 0x10000 | (axistype << 20) | (i << 24); + click(); + return; + } + } + } + + bool focusNextPrevChild(bool next) override { return false; } + +private slots: + void onClick() + { + if (isChecked()) + { + setText("[press button/axis]"); + timerID = startTimer(50); + + memset(axesRest, 0, sizeof(axesRest)); + if (Input::Joystick && SDL_JoystickGetAttached(Input::Joystick)) + { + int naxes = SDL_JoystickNumAxes(Input::Joystick); + if (naxes > 16) naxes = 16; + for (int a = 0; a < naxes; a++) + { + axesRest[a] = SDL_JoystickGetAxis(Input::Joystick, a); + } + } + } + else + { + setText(mappingText()); + if (timerID) { killTimer(timerID); timerID = 0; } + } + } + +private: + QString mappingText() + { + int id = *mapping; + + if (id == -1) return "None"; + + bool hasbtn = ((id & 0xFFFF) != 0xFFFF); + QString str; + + if (hasbtn) + { + if (id & 0x100) + { + int hatnum = ((id >> 4) & 0xF) + 1; + + switch (id & 0xF) + { + case 0x1: str = "Hat %1 up"; break; + case 0x2: str = "Hat %1 right"; break; + case 0x4: str = "Hat %1 down"; break; + case 0x8: str = "Hat %1 left"; break; + } + + str = str.arg(hatnum); + } + else + { + str = QString("Button %1").arg((id & 0xFFFF) + 1); + } + } + else + { + str = ""; + } + + if (id & 0x10000) + { + int axisnum = ((id >> 24) & 0xF) + 1; + + if (hasbtn) str += " / "; + + switch ((id >> 20) & 0xF) + { + case 0: str += QString("Axis %1 +").arg(axisnum); break; + case 1: str += QString("Axis %1 -").arg(axisnum); break; + case 2: str += QString("Trigger %1").arg(axisnum); break; + } + } + + return str; + } + + int* mapping; + bool isHotkey; + + int timerID; + int axesRest[16]; +}; + +#endif // MAPBUTTON_H \ No newline at end of file diff --git a/src/frontend/qt_sdl/InputConfig/resources/LICENSE.md b/src/frontend/qt_sdl/InputConfig/resources/LICENSE.md new file mode 100644 index 0000000..8dea997 --- /dev/null +++ b/src/frontend/qt_sdl/InputConfig/resources/LICENSE.md @@ -0,0 +1,6 @@ +These vector images are modified from the [Nintendo DS Lite illustration on dimensions.com](https://www.dimensions.com/element/nintendo-ds-lite). + +These have been used with the permission of the copyright holders. +> "We restrict the usage of our drawings and 3D models in commercial software, but as long as it's a free and open source community project, that would be approved. Any reference/backlink to Dimensions.com that could be provided in the developer notes and/or credits for the project would be sufficient for use." + +https://www.dimensions.com/legal diff --git a/src/frontend/qt_sdl/InputConfig/resources/ds.qrc b/src/frontend/qt_sdl/InputConfig/resources/ds.qrc new file mode 100644 index 0000000..47466a4 --- /dev/null +++ b/src/frontend/qt_sdl/InputConfig/resources/ds.qrc @@ -0,0 +1,6 @@ + + + ds_open.svg + ds_back.svg + + diff --git a/src/frontend/qt_sdl/InputConfig/resources/ds_back.svg b/src/frontend/qt_sdl/InputConfig/resources/ds_back.svg new file mode 100644 index 0000000..a2f3c99 --- /dev/null +++ b/src/frontend/qt_sdl/InputConfig/resources/ds_back.svg @@ -0,0 +1,182 @@ + + + + + + + + + + diff --git a/src/frontend/qt_sdl/InputConfig/resources/ds_open.svg b/src/frontend/qt_sdl/InputConfig/resources/ds_open.svg new file mode 100644 index 0000000..06c28ff --- /dev/null +++ b/src/frontend/qt_sdl/InputConfig/resources/ds_open.svg @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + -- cgit v1.2.3