From d13e71eeb82653b7189345f260f62df5ea1fbd78 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 22 Jul 2018 10:57:28 +0200 Subject: [PATCH] Qt: merge pad settings --- rpcs3/pad_thread.cpp | 1 - rpcs3/rpcs3.vcxproj | 2 - rpcs3/rpcs3.vcxproj.filters | 6 - rpcs3/rpcs3qt/gamepads_settings_dialog.cpp | 423 --- rpcs3/rpcs3qt/gamepads_settings_dialog.h | 36 - rpcs3/rpcs3qt/main_window.cpp | 12 +- rpcs3/rpcs3qt/pad_settings_dialog.cpp | 950 ++++-- rpcs3/rpcs3qt/pad_settings_dialog.h | 78 +- rpcs3/rpcs3qt/pad_settings_dialog.ui | 3422 ++++++++++---------- 9 files changed, 2487 insertions(+), 2443 deletions(-) delete mode 100644 rpcs3/rpcs3qt/gamepads_settings_dialog.cpp delete mode 100644 rpcs3/rpcs3qt/gamepads_settings_dialog.h diff --git a/rpcs3/pad_thread.cpp b/rpcs3/pad_thread.cpp index 62d2e6546a..853f05c334 100644 --- a/rpcs3/pad_thread.cpp +++ b/rpcs3/pad_thread.cpp @@ -1,5 +1,4 @@ #include "pad_thread.h" -#include "rpcs3qt/gamepads_settings_dialog.h" #include "../ds4_pad_handler.h" #ifdef _WIN32 #include "../xinput_pad_handler.h" diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index de4388acbd..5dfe160bbf 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -987,7 +987,6 @@ - @@ -1428,7 +1427,6 @@ - $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing game_compatibility.h... diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 3f5393619c..6a44ee0c1f 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -491,9 +491,6 @@ Gui\game window - - Gui\settings - Gui\settings @@ -688,9 +685,6 @@ Gui\game window - - Gui\settings - Gui\game list diff --git a/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp b/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp deleted file mode 100644 index 415333e4ce..0000000000 --- a/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp +++ /dev/null @@ -1,423 +0,0 @@ -#include "gamepads_settings_dialog.h" -#include "pad_settings_dialog.h" -#include "qt_utils.h" - -#include "../Emu/Io/PadHandler.h" -#include "../ds4_pad_handler.h" -#ifdef _WIN32 -#include "../xinput_pad_handler.h" -#include "../mm_joystick_handler.h" -#elif HAVE_LIBEVDEV -#include "../evdev_joystick_handler.h" -#endif -#include "../keyboard_pad_handler.h" -#include "../Emu/Io/Null/NullPadHandler.h" - -#include -#include -#include -#include -#include - -inline std::string sstr(const QString& _in) { return _in.toStdString(); } -constexpr auto qstr = QString::fromStdString; - -inline bool CreateConfigFile(const QString& dir, const QString& name) -{ - QString input_dir = qstr(fs::get_config_dir()) + "/InputConfigs/"; - if (!QDir().mkdir(input_dir) && !QDir().exists(input_dir)) - { - LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(input_dir)); - return false; - } - if (!QDir().mkdir(dir) && !QDir().exists(dir)) - { - LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(dir)); - return false; - } - - QString filename = dir + name + ".yml"; - QFile new_file(filename); - - if (!new_file.open(QIODevice::WriteOnly)) - { - LOG_ERROR(GENERAL, "Failed to create file %s", sstr(filename)); - return false; - } - - new_file.close(); - return true; -}; - -// taken from https://stackoverflow.com/a/30818424/8353754 -// because size policies won't work as expected (see similar bugs in Qt bugtracker) -inline void resizeComboBoxView(QComboBox* combo) -{ - int max_width = 0; - QFontMetrics fm(combo->font()); - for (int i = 0; i < combo->count(); ++i) - { - int width = fm.width(combo->itemText(i)); - if (width > max_width) max_width = width; - } - if (combo->view()->minimumWidth() < max_width) - { - // add scrollbar width and margin - max_width += combo->style()->pixelMetric(QStyle::PM_ScrollBarExtent); - max_width += combo->view()->autoScrollMargin(); - combo->view()->setMinimumWidth(max_width); - } -}; - -gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent) - : QDialog(parent) -{ - setWindowTitle(tr("Gamepads Settings")); - - // read tooltips from json - QFile json_file(":/Json/tooltips.json"); - json_file.open(QIODevice::ReadOnly | QIODevice::Text); - QJsonObject json_input = QJsonDocument::fromJson(json_file.readAll()).object().value("input").toObject(); - json_file.close(); - - QVBoxLayout *dialog_layout = new QVBoxLayout(); - QHBoxLayout *all_players = new QHBoxLayout(); - - g_cfg_input.from_default(); - g_cfg_input.load(); - - for (int i = 0; i < MAX_PLAYERS; i++) - { - QGroupBox *grp_player = new QGroupBox(QString(tr("Player %1").arg(i+1))); - - QVBoxLayout *ppad_layout = new QVBoxLayout(); - - co_inputtype[i] = new QComboBox(); - co_inputtype[i]->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - co_inputtype[i]->view()->setTextElideMode(Qt::ElideNone); -#ifdef WIN32 - co_inputtype[i]->setToolTip(json_input["padHandlerBox"].toString()); -#else - co_inputtype[i]->setToolTip(json_input["padHandlerBox_Linux"].toString()); -#endif - ppad_layout->addWidget(co_inputtype[i]); - - co_deviceID[i] = new QComboBox(); - co_deviceID[i]->setEnabled(false); - co_deviceID[i]->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - co_deviceID[i]->view()->setTextElideMode(Qt::ElideNone); - ppad_layout->addWidget(co_deviceID[i]); - - co_profile[i] = new QComboBox(); - co_profile[i]->setEnabled(false); - co_profile[i]->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - co_profile[i]->view()->setTextElideMode(Qt::ElideNone); - ppad_layout->addWidget(co_profile[i]); - - QHBoxLayout *button_layout = new QHBoxLayout(); - bu_new_profile[i] = new QPushButton(tr("Add Profile")); - bu_new_profile[i]->setEnabled(false); - bu_config[i] = new QPushButton(tr("Configure")); - bu_config[i]->setEnabled(false); - button_layout->setContentsMargins(0,0,0,0); - button_layout->addWidget(bu_config[i]); - button_layout->addWidget(bu_new_profile[i]); - ppad_layout->addLayout(button_layout); - - grp_player->setLayout(ppad_layout); - grp_player->setFixedSize(grp_player->sizeHint()); - - // fill comboboxes after setting the groupbox's size to prevent stretch - std::vector str_inputs = g_cfg_input.player[0]->handler.to_list(); - for (int index = 0; index < str_inputs.size(); index++) - { - co_inputtype[i]->addItem(qstr(str_inputs[index])); - } - resizeComboBoxView(co_inputtype[i]); - - all_players->addWidget(grp_player); - - if (i == 3) - { - dialog_layout->addLayout(all_players); - all_players = new QHBoxLayout(); - all_players->addStretch(); - } - } - - all_players->addStretch(); - dialog_layout->addLayout(all_players); - - QHBoxLayout *buttons_layout = new QHBoxLayout(); - QPushButton *ok_button = new QPushButton(tr("OK")); - QPushButton *cancel_button = new QPushButton(tr("Cancel")); - QPushButton *refresh_button = new QPushButton(tr("Refresh")); - buttons_layout->addWidget(ok_button); - buttons_layout->addWidget(refresh_button); - buttons_layout->addWidget(cancel_button); - buttons_layout->addStretch(); - dialog_layout->addLayout(buttons_layout); - - setLayout(dialog_layout); - layout()->setSizeConstraint(QLayout::SetFixedSize); - - auto configure_combos = [=] - { - //Set the values from config - for (int i = 0; i < MAX_PLAYERS; i++) - { - // No extra loops are necessary because setCurrentText does it for us - co_inputtype[i]->setCurrentText(qstr(g_cfg_input.player[i]->handler.to_string())); - // Device will be empty on some rare occasions, so fill them by force - ChangeInputType(i); - } - }; - - for (int i = 0; i < MAX_PLAYERS; i++) - { - connect(co_inputtype[i], &QComboBox::currentTextChanged, [=] - { - ChangeInputType(i); - }); - connect(co_deviceID[i], &QComboBox::currentTextChanged, [=](const QString& dev) - { - std::string device = sstr(dev); - if (!g_cfg_input.player[i]->device.from_string(device)) - { - //Something went wrong - LOG_ERROR(GENERAL, "Failed to convert device string: %s", device); - return; - } - }); - connect(co_profile[i], &QComboBox::currentTextChanged, [=](const QString& prof) - { - std::string profile = sstr(prof); - if (!g_cfg_input.player[i]->profile.from_string(profile)) - { - //Something went wrong - LOG_ERROR(GENERAL, "Failed to convert profile string: %s", profile); - return; - } - }); - connect(bu_config[i], &QAbstractButton::clicked, [=] - { - ClickConfigButton(i); - }); - connect(bu_new_profile[i], &QAbstractButton::clicked, [=] - { - QInputDialog* dialog = new QInputDialog(this); - dialog->setWindowTitle(tr("Choose a unique name")); - dialog->setLabelText(tr("Profile Name: ")); - dialog->setFixedSize(500, 100); - - while (dialog->exec() != QDialog::Rejected) - { - QString friendlyName = dialog->textValue(); - if (friendlyName == "") - { - QMessageBox::warning(this, tr("Error"), tr("Name cannot be empty")); - continue; - } - if (friendlyName.contains(".")) - { - QMessageBox::warning(this, tr("Error"), tr("Must choose a name without '.'")); - continue; - } - if (co_profile[i]->findText(friendlyName) != -1) - { - QMessageBox::warning(this, tr("Error"), tr("Please choose a non-existing name")); - continue; - } - if (CreateConfigFile(qstr(PadHandlerBase::get_config_dir(g_cfg_input.player[i]->handler)), friendlyName)) - { - co_profile[i]->addItem(friendlyName); - co_profile[i]->setCurrentText(friendlyName); - } - break; - } - }); - } - connect(ok_button, &QPushButton::pressed, this, &gamepads_settings_dialog::SaveExit); - connect(cancel_button, &QPushButton::pressed, this, &gamepads_settings_dialog::CancelExit); - connect(refresh_button, &QPushButton::pressed, [=] { configure_combos(); }); - - configure_combos(); -} - -void gamepads_settings_dialog::SaveExit() -{ - //Check for invalid selection - for (int i = 0; i < MAX_PLAYERS; i++) - { - if (co_deviceID[i]->currentData() == -1) - { - g_cfg_input.player[i]->handler.from_default(); - g_cfg_input.player[i]->device.from_default(); - g_cfg_input.player[i]->profile.from_default(); - } - } - - g_cfg_input.save(); - - QDialog::accept(); -} - -void gamepads_settings_dialog::CancelExit() -{ - //Reloads config from file or defaults - g_cfg_input.from_default(); - g_cfg_input.load(); - - QDialog::accept(); -} - -std::shared_ptr gamepads_settings_dialog::GetHandler(pad_handler type) -{ - std::shared_ptr ret_handler; - - switch (type) - { - case pad_handler::null: - ret_handler = std::make_unique(); - break; - case pad_handler::keyboard: - ret_handler = std::make_unique(); - break; - case pad_handler::ds4: - ret_handler = std::make_unique(); - break; -#ifdef _MSC_VER - case pad_handler::xinput: - ret_handler = std::make_unique(); - break; -#endif -#ifdef _WIN32 - case pad_handler::mm: - ret_handler = std::make_unique(); - break; -#endif -#ifdef HAVE_LIBEVDEV - case pad_handler::evdev: - ret_handler = std::make_unique(); - break; -#endif - } - - return ret_handler; -} - -void gamepads_settings_dialog::ChangeInputType(int player) -{ - std::string handler = sstr(co_inputtype[player]->currentText()); - std::string device = g_cfg_input.player[player]->device.to_string(); - std::string profile = g_cfg_input.player[player]->profile.to_string(); - - // Change this player's current handler - if (!g_cfg_input.player[player]->handler.from_string(handler)) - { - //Something went wrong - LOG_ERROR(GENERAL, "Failed to convert input string:%s", handler); - return; - } - - // Get this player's current handler and it's currently available devices - std::shared_ptr cur_pad_handler = GetHandler(g_cfg_input.player[player]->handler); - std::vector list_devices = cur_pad_handler->ListDevices(); - - // Refill the device combobox with currently available devices - co_deviceID[player]->clear(); - - bool force_enable = true; // enable configs even with disconnected devices - - switch (cur_pad_handler->m_type) - { -#ifdef _MSC_VER - case pad_handler::xinput: - { - QString name_string = qstr(cur_pad_handler->name_string()); - for (int i = 0; i < cur_pad_handler->max_devices(); i++) - { - co_deviceID[player]->addItem(name_string + QString::number(i), i); - } - break; - } -#endif - default: - for (int i = 0; i < list_devices.size(); i++) - { - co_deviceID[player]->addItem(qstr(list_devices[i]), i); - } - force_enable = false; - break; - } - - // Handle empty device list - bool device_found = list_devices.size() > 0; - co_deviceID[player]->setEnabled(force_enable || device_found); - - if (force_enable || device_found) - { - co_deviceID[player]->setCurrentText(qstr(device)); - } - else - { - co_deviceID[player]->addItem(tr("No Device Detected"), -1); - } - - bool config_enabled = force_enable || (device_found && cur_pad_handler->has_config()); - co_profile[player]->clear(); - - // update profile list if possible - if (config_enabled) - { - QString s_profile_dir = qstr(PadHandlerBase::get_config_dir(cur_pad_handler->m_type)); - QStringList profiles = gui::utils::get_dir_entries(QDir(s_profile_dir), QStringList() << "*.yml"); - - if (profiles.isEmpty()) - { - QString def_name = "Default Profile"; - if (!CreateConfigFile(s_profile_dir, def_name)) - { - config_enabled = false; - } - else - { - co_profile[player]->addItem(def_name); - co_profile[player]->setCurrentText(def_name); - } - } - else - { - for (const auto& prof : profiles) - { - co_profile[player]->addItem(prof); - } - co_profile[player]->setCurrentText(qstr(profile)); - } - } - - if (!config_enabled) - co_profile[player]->addItem(tr("No Profiles")); - - // enable configuration and profile list if possible - bu_config[player]->setEnabled(config_enabled); - bu_new_profile[player]->setEnabled(config_enabled); - co_profile[player]->setEnabled(config_enabled); - - // update view - resizeComboBoxView(co_deviceID[player]); - resizeComboBoxView(co_profile[player]); -} - -void gamepads_settings_dialog::ClickConfigButton(int player) -{ - // Get this player's current handler and open its pad settings dialog - std::shared_ptr cur_pad_handler = GetHandler(g_cfg_input.player[player]->handler); - if (cur_pad_handler->has_config()) - { - std::string device = sstr(co_deviceID[player]->currentText()); - std::string profile = sstr(co_profile[player]->currentText()); - pad_settings_dialog dlg(device, profile, cur_pad_handler); - dlg.exec(); - } -} diff --git a/rpcs3/rpcs3qt/gamepads_settings_dialog.h b/rpcs3/rpcs3qt/gamepads_settings_dialog.h deleted file mode 100644 index 4f43e9928c..0000000000 --- a/rpcs3/rpcs3qt/gamepads_settings_dialog.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "../Emu/System.h" -#include "../../Utilities/Config.h" -#include "../../Utilities/File.h" -#include "../Emu/Io/PadHandler.h" - -class gamepads_settings_dialog : public QDialog -{ - const int MAX_PLAYERS = 7; - -protected: - std::shared_ptr GetHandler(pad_handler type); - void ChangeInputType(int player); - void ClickConfigButton(int player); - void SaveExit(); - void CancelExit(); - -protected: - QComboBox *co_inputtype[7]; - QComboBox *co_deviceID[7]; - QComboBox *co_profile[7]; - QPushButton *bu_config[7]; - QPushButton *bu_new_profile[7]; - -public: - gamepads_settings_dialog(QWidget* parent); - ~gamepads_settings_dialog() = default; -}; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 7c50832a38..59fdfb0f3b 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -29,7 +29,7 @@ #include "main_window.h" #include "emu_settings.h" #include "about_dialog.h" -#include "gamepads_settings_dialog.h" +#include "pad_settings_dialog.h" #include "progress_dialog.h" #include @@ -1228,11 +1228,13 @@ void main_window::CreateConnects() connect(ui->confIOAct, &QAction::triggered, [=]() { openSettings(3); }); connect(ui->confSystemAct, &QAction::triggered, [=]() { openSettings(4); }); - connect(ui->confPadsAct, &QAction::triggered, this, [=] + auto openPadSettings = [this] { - gamepads_settings_dialog dlg(this); + pad_settings_dialog dlg(this); dlg.exec(); - }); + }; + + connect(ui->confPadsAct, &QAction::triggered, openPadSettings); connect(ui->confAutopauseManagerAct, &QAction::triggered, [=] { @@ -1416,7 +1418,7 @@ void main_window::CreateConnects() } }); - connect(ui->toolbar_controls, &QAction::triggered, [=]() { gamepads_settings_dialog dlg(this); dlg.exec(); }); + connect(ui->toolbar_controls, &QAction::triggered, openPadSettings); connect(ui->toolbar_config, &QAction::triggered, [=]() { openSettings(0); }); connect(ui->toolbar_list, &QAction::triggered, [=]() { ui->setlistModeListAct->trigger(); }); connect(ui->toolbar_grid, &QAction::triggered, [=]() { ui->setlistModeGridAct->trigger(); }); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 1f9eee6944..7d1fe55dd5 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -2,275 +2,247 @@ #include #include #include -#include -#include -#include #include +#include +#include #include "qt_utils.h" #include "pad_settings_dialog.h" #include "ui_pad_settings_dialog.h" +#include "Emu/Io/Null/NullPadHandler.h" + +#include "keyboard_pad_handler.h" +#include "ds4_pad_handler.h" +#ifdef _WIN32 +#include "xinput_pad_handler.h" +#endif +#ifdef _MSC_VER +#include "mm_joystick_handler.h" +#endif +#ifdef HAVE_LIBEVDEV +#include "evdev_joystick_handler.h" +#endif + inline std::string sstr(const QString& _in) { return _in.toStdString(); } constexpr auto qstr = QString::fromStdString; -pad_settings_dialog::pad_settings_dialog(const std::string& device, const std::string& profile, std::shared_ptr handler, QWidget *parent) - : QDialog(parent), ui(new Ui::pad_settings_dialog), m_device_name(device), m_handler(handler), m_handler_type(handler->m_type) +inline bool CreateConfigFile(const QString& dir, const QString& name) +{ + QString input_dir = qstr(fs::get_config_dir()) + "/InputConfigs/"; + if (!QDir().mkdir(input_dir) && !QDir().exists(input_dir)) + { + LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(input_dir)); + return false; + } + if (!QDir().mkdir(dir) && !QDir().exists(dir)) + { + LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(dir)); + return false; + } + + QString filename = dir + name + ".yml"; + QFile new_file(filename); + + if (!new_file.open(QIODevice::WriteOnly)) + { + LOG_ERROR(GENERAL, "Failed to create file %s", sstr(filename)); + return false; + } + + new_file.close(); + return true; +}; + +pad_settings_dialog::pad_settings_dialog(QWidget *parent) + : QDialog(parent), ui(new Ui::pad_settings_dialog) { ui->setupUi(this); - ui->b_cancel->setDefault(true); - connect(ui->b_cancel, &QAbstractButton::clicked, this, &QWidget::close); + setWindowTitle(tr("Gamepads Settings")); + // load input config + g_cfg_input.from_default(); + g_cfg_input.load(); + + // Create tab widget for 7 players + m_tabs = new QTabWidget; + for (int i = 1; i < 8; i++) + { + QWidget* tab = new QWidget; + m_tabs->addTab(tab, tr("Player %0").arg(i)); + } + + // on tab change: move the layout to the new tab and refresh + connect(m_tabs, &QTabWidget::currentChanged, this, &pad_settings_dialog::OnTabChanged); + + // Set tab widget as layout + QVBoxLayout* mainLayout = new QVBoxLayout; + mainLayout->addWidget(m_tabs); + setLayout(mainLayout); + + // Fill input type combobox + std::vector str_inputs = g_cfg_input.player[0]->handler.to_list(); + for (int index = 0; index < str_inputs.size(); index++) + { + ui->chooseHandler->addItem(qstr(str_inputs[index])); + } + + // Combobox: Input type + connect(ui->chooseHandler, &QComboBox::currentTextChanged, this, &pad_settings_dialog::ChangeInputType); + + // Combobox: Devices + connect(ui->chooseDevice, &QComboBox::currentTextChanged, [this](const QString& dev) + { + if (dev.isEmpty()) + { + return; + } + m_device_name = sstr(dev); + if (!g_cfg_input.player[m_tabs->currentIndex()]->device.from_string(m_device_name)) + { + // Something went wrong + LOG_ERROR(GENERAL, "Failed to convert device string: %s", m_device_name); + return; + } + }); + + // Combobox: Profiles + connect(ui->chooseProfile, &QComboBox::currentTextChanged, [this](const QString& prof) + { + if (prof.isEmpty()) + { + return; + } + m_profile = sstr(prof); + if (!g_cfg_input.player[m_tabs->currentIndex()]->profile.from_string(m_profile)) + { + // Something went wrong + LOG_ERROR(GENERAL, "Failed to convert profile string: %s", m_profile); + return; + } + ChangeProfile(); + }); + + // Pushbutton: Add Profile + connect(ui->b_addProfile, &QAbstractButton::clicked, [=] + { + const int i = m_tabs->currentIndex(); + + QInputDialog* dialog = new QInputDialog(this); + dialog->setWindowTitle(tr("Choose a unique name")); + dialog->setLabelText(tr("Profile Name: ")); + dialog->setFixedSize(500, 100); + + while (dialog->exec() != QDialog::Rejected) + { + QString friendlyName = dialog->textValue(); + if (friendlyName.isEmpty()) + { + QMessageBox::warning(this, tr("Error"), tr("Name cannot be empty")); + continue; + } + if (friendlyName.contains(".")) + { + QMessageBox::warning(this, tr("Error"), tr("Must choose a name without '.'")); + continue; + } + if (ui->chooseProfile->findText(friendlyName) != -1) + { + QMessageBox::warning(this, tr("Error"), tr("Please choose a non-existing name")); + continue; + } + if (CreateConfigFile(qstr(PadHandlerBase::get_config_dir(g_cfg_input.player[i]->handler)), friendlyName)) + { + ui->chooseProfile->addItem(friendlyName); + ui->chooseProfile->setCurrentText(friendlyName); + } + break; + } + }); + + // Cancel Button + connect(ui->b_cancel, &QAbstractButton::clicked, this, &pad_settings_dialog::CancelExit); + + // Save Button + connect(ui->b_ok, &QAbstractButton::clicked, this, &pad_settings_dialog::SaveExit); + + // Refresh Button + connect(ui->b_refresh, &QPushButton::clicked, this, &pad_settings_dialog::RefreshInputTypes); + + // Initialize configurable buttons + InitButtons(); + + // Set up first tab + OnTabChanged(0); + + // repaint and resize controller image + ui->l_controller->setPixmap(gui::utils::get_colorized_pixmap(*ui->l_controller->pixmap(), QColor(), gui::utils::get_label_color("l_controller"), false, true)); + ui->l_controller->setMaximumSize(ui->gb_description->sizeHint().width(), ui->l_controller->maximumHeight() * ui->gb_description->sizeHint().width() / ui->l_controller->maximumWidth()); + + // set tab layout constraint to the first tab + m_tabs->widget(0)->layout()->setSizeConstraint(QLayout::SetFixedSize); + + layout()->setSizeConstraint(QLayout::SetFixedSize); +} + +pad_settings_dialog::~pad_settings_dialog() +{ + delete ui; +} + +void pad_settings_dialog::InitButtons() +{ m_padButtons = new QButtonGroup(this); m_palette = ui->b_left->palette(); // save normal palette - std::string cfg_name = PadHandlerBase::get_config_dir(m_handler_type) + profile + ".yml"; - - // Adjust to the different pad handlers - if (m_handler_type == pad_handler::keyboard) + auto insertButton = [this](int id, QPushButton* button) { - setWindowTitle(tr("Configure Keyboard")); - ui->b_blacklist->setEnabled(false); - ((keyboard_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); - } - else if (m_handler_type == pad_handler::ds4) - { - setWindowTitle(tr("Configure DS4")); - ((ds4_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); - } -#ifdef _MSC_VER - else if (m_handler_type == pad_handler::xinput) - { - setWindowTitle(tr("Configure XInput")); - ((xinput_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); - } -#endif -#ifdef _WIN32 - else if (m_handler_type == pad_handler::mm) - { - setWindowTitle(tr("Configure MMJoystick")); - ((mm_joystick_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); - } -#endif -#ifdef HAVE_LIBEVDEV - else if (m_handler_type == pad_handler::evdev) - { - setWindowTitle(tr("Configure evdev")); - ((evdev_joystick_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); - } -#endif - - m_handler_cfg.load(); - - ui->chb_vibration_large->setChecked((bool)m_handler_cfg.enable_vibration_motor_large); - ui->chb_vibration_small->setChecked((bool)m_handler_cfg.enable_vibration_motor_small); - ui->chb_vibration_switch->setChecked((bool)m_handler_cfg.switch_vibration_motors); - - // Enable Button Remapping - if (m_handler->has_config()) - { - // Use timer to get button input - const auto& callback = [=](u16 val, std::string name, int preview_values[6]) - { - if (m_handler->has_deadzones()) - { - ui->preview_trigger_left->setValue(preview_values[0]); - ui->preview_trigger_right->setValue(preview_values[1]); - - if (lx != preview_values[2] || ly != preview_values[3]) - { - lx = preview_values[2], ly = preview_values[3]; - RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->size().width(), lx, ly); - } - if (rx != preview_values[4] || ry != preview_values[5]) - { - rx = preview_values[4], ry = preview_values[5]; - RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), rx, ry); - } - } - - if (val <= 0) return; - - LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_handler_type, name, val); - if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end) - { - m_cfg_entries[m_button_id].key = name; - m_cfg_entries[m_button_id].text = qstr(name); - ReactivateButtons(); - } - }; - - connect(&m_timer_input, &QTimer::timeout, [=]() - { - std::vector buttons = - { - m_cfg_entries[button_ids::id_pad_l2].key, - m_cfg_entries[button_ids::id_pad_r2].key, - m_cfg_entries[button_ids::id_pad_lstick_left].key, - m_cfg_entries[button_ids::id_pad_lstick_right].key, - m_cfg_entries[button_ids::id_pad_lstick_down].key, - m_cfg_entries[button_ids::id_pad_lstick_up].key, - m_cfg_entries[button_ids::id_pad_rstick_left].key, - m_cfg_entries[button_ids::id_pad_rstick_right].key, - m_cfg_entries[button_ids::id_pad_rstick_down].key, - m_cfg_entries[button_ids::id_pad_rstick_up].key - }; - m_handler->GetNextButtonPress(m_device_name, callback, false, buttons); - }); - - m_timer_input.start(1); - }; - - // Enable Vibration Checkboxes - if (m_handler->has_rumble()) - { - const s32 min_force = m_handler->vibration_min; - const s32 max_force = m_handler->vibration_max; - - ui->chb_vibration_large->setEnabled(true); - ui->chb_vibration_small->setEnabled(true); - ui->chb_vibration_switch->setEnabled(true); - - connect(ui->chb_vibration_large, &QCheckBox::clicked, [=](bool checked) - { - if (!checked) return; - - ui->chb_vibration_switch->isChecked() ? m_handler->TestVibration(m_device_name, min_force, max_force) - : m_handler->TestVibration(m_device_name, max_force, min_force); - - QTimer::singleShot(300, [=]() - { - m_handler->TestVibration(m_device_name, min_force, min_force); - }); - }); - - connect(ui->chb_vibration_small, &QCheckBox::clicked, [=](bool checked) - { - if (!checked) return; - - ui->chb_vibration_switch->isChecked() ? m_handler->TestVibration(m_device_name, max_force, min_force) - : m_handler->TestVibration(m_device_name, min_force, max_force); - - QTimer::singleShot(300, [=]() - { - m_handler->TestVibration(m_device_name, min_force, min_force); - }); - }); - - connect(ui->chb_vibration_switch, &QCheckBox::clicked, [=](bool checked) - { - checked ? m_handler->TestVibration(m_device_name, min_force, max_force) - : m_handler->TestVibration(m_device_name, max_force, min_force); - - QTimer::singleShot(200, [=]() - { - checked ? m_handler->TestVibration(m_device_name, max_force, min_force) - : m_handler->TestVibration(m_device_name, min_force, max_force); - - QTimer::singleShot(200, [=]() - { - m_handler->TestVibration(m_device_name, min_force, min_force); - }); - }); - }); - } - else - { - ui->verticalLayout_left->removeWidget(ui->gb_vibration); - delete ui->gb_vibration; - } - - // Enable Deadzone Settings - if (m_handler->has_deadzones()) - { - auto initSlider = [=](QSlider* slider, const s32& value, const s32& min, const s32& max) - { - slider->setEnabled(true); - slider->setRange(min, max); - slider->setValue(value); - }; - - // Enable Trigger Thresholds - initSlider(ui->slider_trigger_left, m_handler_cfg.ltriggerthreshold, 0, m_handler->trigger_max); - initSlider(ui->slider_trigger_right, m_handler_cfg.rtriggerthreshold, 0, m_handler->trigger_max); - ui->preview_trigger_left->setRange(0, m_handler->trigger_max); - ui->preview_trigger_right->setRange(0, m_handler->trigger_max); - - // Enable Stick Deadzones - initSlider(ui->slider_stick_left, m_handler_cfg.lstickdeadzone, 0, m_handler->thumb_max); - initSlider(ui->slider_stick_right, m_handler_cfg.rstickdeadzone, 0, m_handler->thumb_max); - - RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->size().width(), lx, ly); - connect(ui->slider_stick_left, &QSlider::valueChanged, [&](int value) - { - RepaintPreviewLabel(ui->preview_stick_left, value, ui->slider_stick_left->size().width(), lx, ly); - }); - - RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), rx, ry); - connect(ui->slider_stick_right, &QSlider::valueChanged, [&](int value) - { - RepaintPreviewLabel(ui->preview_stick_right, value, ui->slider_stick_right->size().width(), rx, ry); - }); - } - else - { - ui->verticalLayout_right->removeWidget(ui->gb_sticks); - ui->verticalLayout_left->removeWidget(ui->gb_triggers); - - delete ui->gb_sticks; - delete ui->gb_triggers; - } - - auto insertButton = [this](int id, QPushButton* button, cfg::string* cfg_name) - { - QString name = qstr(*cfg_name); - m_cfg_entries.insert(std::make_pair(id, pad_button{ cfg_name, *cfg_name, name })); m_padButtons->addButton(button, id); - button->setText(name); button->installEventFilter(this); }; - insertButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &m_handler_cfg.ls_left); - insertButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &m_handler_cfg.ls_down); - insertButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &m_handler_cfg.ls_right); - insertButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &m_handler_cfg.ls_up); + insertButton(button_ids::id_pad_lstick_left, ui->b_lstick_left); + insertButton(button_ids::id_pad_lstick_down, ui->b_lstick_down); + insertButton(button_ids::id_pad_lstick_right, ui->b_lstick_right); + insertButton(button_ids::id_pad_lstick_up, ui->b_lstick_up); - insertButton(button_ids::id_pad_left, ui->b_left, &m_handler_cfg.left); - insertButton(button_ids::id_pad_down, ui->b_down, &m_handler_cfg.down); - insertButton(button_ids::id_pad_right, ui->b_right, &m_handler_cfg.right); - insertButton(button_ids::id_pad_up, ui->b_up, &m_handler_cfg.up); + insertButton(button_ids::id_pad_left, ui->b_left); + insertButton(button_ids::id_pad_down, ui->b_down); + insertButton(button_ids::id_pad_right, ui->b_right); + insertButton(button_ids::id_pad_up, ui->b_up); - insertButton(button_ids::id_pad_l1, ui->b_shift_l1, &m_handler_cfg.l1); - insertButton(button_ids::id_pad_l2, ui->b_shift_l2, &m_handler_cfg.l2); - insertButton(button_ids::id_pad_l3, ui->b_shift_l3, &m_handler_cfg.l3); + insertButton(button_ids::id_pad_l1, ui->b_shift_l1); + insertButton(button_ids::id_pad_l2, ui->b_shift_l2); + insertButton(button_ids::id_pad_l3, ui->b_shift_l3); - insertButton(button_ids::id_pad_start, ui->b_start, &m_handler_cfg.start); - insertButton(button_ids::id_pad_select, ui->b_select, &m_handler_cfg.select); - insertButton(button_ids::id_pad_ps, ui->b_ps, &m_handler_cfg.ps); + insertButton(button_ids::id_pad_start, ui->b_start); + insertButton(button_ids::id_pad_select, ui->b_select); + insertButton(button_ids::id_pad_ps, ui->b_ps); - insertButton(button_ids::id_pad_r1, ui->b_shift_r1, &m_handler_cfg.r1); - insertButton(button_ids::id_pad_r2, ui->b_shift_r2, &m_handler_cfg.r2); - insertButton(button_ids::id_pad_r3, ui->b_shift_r3, &m_handler_cfg.r3); + insertButton(button_ids::id_pad_r1, ui->b_shift_r1); + insertButton(button_ids::id_pad_r2, ui->b_shift_r2); + insertButton(button_ids::id_pad_r3, ui->b_shift_r3); - insertButton(button_ids::id_pad_square, ui->b_square, &m_handler_cfg.square); - insertButton(button_ids::id_pad_cross, ui->b_cross, &m_handler_cfg.cross); - insertButton(button_ids::id_pad_circle, ui->b_circle, &m_handler_cfg.circle); - insertButton(button_ids::id_pad_triangle, ui->b_triangle, &m_handler_cfg.triangle); + insertButton(button_ids::id_pad_square, ui->b_square); + insertButton(button_ids::id_pad_cross, ui->b_cross); + insertButton(button_ids::id_pad_circle, ui->b_circle); + insertButton(button_ids::id_pad_triangle, ui->b_triangle); - insertButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &m_handler_cfg.rs_left); - insertButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &m_handler_cfg.rs_down); - insertButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg.rs_right); - insertButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg.rs_up); + insertButton(button_ids::id_pad_rstick_left, ui->b_rstick_left); + insertButton(button_ids::id_pad_rstick_down, ui->b_rstick_down); + insertButton(button_ids::id_pad_rstick_right, ui->b_rstick_right); + insertButton(button_ids::id_pad_rstick_up, ui->b_rstick_up); - m_padButtons->addButton(ui->b_reset, button_ids::id_reset_parameters); + m_padButtons->addButton(ui->b_reset, button_ids::id_reset_parameters); m_padButtons->addButton(ui->b_blacklist, button_ids::id_blacklist); - m_padButtons->addButton(ui->b_ok, button_ids::id_ok); - m_padButtons->addButton(ui->b_cancel, button_ids::id_cancel); + m_padButtons->addButton(ui->b_refresh, button_ids::id_refresh); + m_padButtons->addButton(ui->b_ok, button_ids::id_ok); + m_padButtons->addButton(ui->b_cancel, button_ids::id_cancel); connect(m_padButtons, static_cast(&QButtonGroup::buttonClicked), this, &pad_settings_dialog::OnPadButtonClicked); - connect(&m_timer, &QTimer::timeout, [&]() + connect(&m_timer, &QTimer::timeout, [this]() { if (--m_seconds <= 0) { @@ -280,18 +252,191 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, const std::s m_padButtons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(m_seconds)); }); - UpdateLabel(); + connect(ui->chb_vibration_large, &QCheckBox::clicked, [this](bool checked) + { + if (!checked) + { + return; + } - // repaint and resize controller image - ui->l_controller->setPixmap(gui::utils::get_colorized_pixmap(*ui->l_controller->pixmap(), QColor(), gui::utils::get_label_color("l_controller"), false, true)); - ui->l_controller->setMaximumSize(ui->gb_description->sizeHint().width(), ui->l_controller->maximumHeight() * ui->gb_description->sizeHint().width() / ui->l_controller->maximumWidth()); + ui->chb_vibration_switch->isChecked() ? m_handler->TestVibration(m_device_name, m_min_force, m_max_force) + : m_handler->TestVibration(m_device_name, m_max_force, m_min_force); - layout()->setSizeConstraint(QLayout::SetFixedSize); + QTimer::singleShot(300, [this]() + { + m_handler->TestVibration(m_device_name, m_min_force, m_min_force); + }); + }); + + connect(ui->chb_vibration_small, &QCheckBox::clicked, [this](bool checked) + { + if (!checked) + { + return; + } + + ui->chb_vibration_switch->isChecked() ? m_handler->TestVibration(m_device_name, m_max_force, m_min_force) + : m_handler->TestVibration(m_device_name, m_min_force, m_max_force); + + QTimer::singleShot(300, [this]() + { + m_handler->TestVibration(m_device_name, m_min_force, m_min_force); + }); + }); + + connect(ui->chb_vibration_switch, &QCheckBox::clicked, [this](bool checked) + { + checked ? m_handler->TestVibration(m_device_name, m_min_force, m_max_force) + : m_handler->TestVibration(m_device_name, m_max_force, m_min_force); + + QTimer::singleShot(200, [this, checked]() + { + checked ? m_handler->TestVibration(m_device_name, m_max_force, m_min_force) + : m_handler->TestVibration(m_device_name, m_min_force, m_max_force); + + QTimer::singleShot(200, [this]() + { + m_handler->TestVibration(m_device_name, m_min_force, m_min_force); + }); + }); + }); + + connect(ui->slider_stick_left, &QSlider::valueChanged, [&](int value) + { + RepaintPreviewLabel(ui->preview_stick_left, value, ui->slider_stick_left->size().width(), lx, ly); + }); + + connect(ui->slider_stick_right, &QSlider::valueChanged, [&](int value) + { + RepaintPreviewLabel(ui->preview_stick_right, value, ui->slider_stick_right->size().width(), rx, ry); + }); + + // Enable Button Remapping + const auto& callback = [=](u16 val, std::string name, int preview_values[6]) + { + if (m_handler->has_deadzones()) + { + ui->preview_trigger_left->setValue(preview_values[0]); + ui->preview_trigger_right->setValue(preview_values[1]); + + if (lx != preview_values[2] || ly != preview_values[3]) + { + lx = preview_values[2], ly = preview_values[3]; + RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->size().width(), lx, ly); + } + if (rx != preview_values[4] || ry != preview_values[5]) + { + rx = preview_values[4], ry = preview_values[5]; + RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), rx, ry); + } + } + + if (val <= 0) + { + return; + } + + LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_handler->m_type, name, val); + if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end) + { + m_cfg_entries[m_button_id].key = name; + m_cfg_entries[m_button_id].text = qstr(name); + ReactivateButtons(); + } + }; + + // Use timer to get button input + connect(&m_timer_input, &QTimer::timeout, [this, callback]() + { + std::vector buttons = + { + m_cfg_entries[button_ids::id_pad_l2].key, m_cfg_entries[button_ids::id_pad_r2].key, m_cfg_entries[button_ids::id_pad_lstick_left].key, + m_cfg_entries[button_ids::id_pad_lstick_right].key, m_cfg_entries[button_ids::id_pad_lstick_down].key, m_cfg_entries[button_ids::id_pad_lstick_up].key, + m_cfg_entries[button_ids::id_pad_rstick_left].key, m_cfg_entries[button_ids::id_pad_rstick_right].key, m_cfg_entries[button_ids::id_pad_rstick_down].key, + m_cfg_entries[button_ids::id_pad_rstick_up].key + }; + m_handler->GetNextButtonPress(m_device_name, callback, false, buttons); + }); } -pad_settings_dialog::~pad_settings_dialog() +void pad_settings_dialog::ReloadButtons() { - delete ui; + m_cfg_entries.clear(); + + auto updateButton = [this](int id, QPushButton* button, cfg::string* cfg_name) + { + const QString name = qstr(*cfg_name); + m_cfg_entries.insert(std::make_pair(id, pad_button{cfg_name, *cfg_name, name})); + button->setText(name); + }; + + updateButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &m_handler_cfg.ls_left); + updateButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &m_handler_cfg.ls_down); + updateButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &m_handler_cfg.ls_right); + updateButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &m_handler_cfg.ls_up); + + updateButton(button_ids::id_pad_left, ui->b_left, &m_handler_cfg.left); + updateButton(button_ids::id_pad_down, ui->b_down, &m_handler_cfg.down); + updateButton(button_ids::id_pad_right, ui->b_right, &m_handler_cfg.right); + updateButton(button_ids::id_pad_up, ui->b_up, &m_handler_cfg.up); + + updateButton(button_ids::id_pad_l1, ui->b_shift_l1, &m_handler_cfg.l1); + updateButton(button_ids::id_pad_l2, ui->b_shift_l2, &m_handler_cfg.l2); + updateButton(button_ids::id_pad_l3, ui->b_shift_l3, &m_handler_cfg.l3); + + updateButton(button_ids::id_pad_start, ui->b_start, &m_handler_cfg.start); + updateButton(button_ids::id_pad_select, ui->b_select, &m_handler_cfg.select); + updateButton(button_ids::id_pad_ps, ui->b_ps, &m_handler_cfg.ps); + + updateButton(button_ids::id_pad_r1, ui->b_shift_r1, &m_handler_cfg.r1); + updateButton(button_ids::id_pad_r2, ui->b_shift_r2, &m_handler_cfg.r2); + updateButton(button_ids::id_pad_r3, ui->b_shift_r3, &m_handler_cfg.r3); + + updateButton(button_ids::id_pad_square, ui->b_square, &m_handler_cfg.square); + updateButton(button_ids::id_pad_cross, ui->b_cross, &m_handler_cfg.cross); + updateButton(button_ids::id_pad_circle, ui->b_circle, &m_handler_cfg.circle); + updateButton(button_ids::id_pad_triangle, ui->b_triangle, &m_handler_cfg.triangle); + + updateButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &m_handler_cfg.rs_left); + updateButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &m_handler_cfg.rs_down); + updateButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg.rs_right); + updateButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg.rs_up); + + // Enable Vibration Checkboxes + ui->gb_vibration->setEnabled(m_handler->has_rumble()); + + ui->chb_vibration_large->setChecked((bool)m_handler_cfg.enable_vibration_motor_large); + ui->chb_vibration_small->setChecked((bool)m_handler_cfg.enable_vibration_motor_small); + ui->chb_vibration_switch->setChecked((bool)m_handler_cfg.switch_vibration_motors); + + m_min_force = m_handler->vibration_min; + m_max_force = m_handler->vibration_max; + + // Enable Deadzone Settings + const bool enable_deadzones = m_handler->has_deadzones(); + + ui->gb_sticks->setEnabled(enable_deadzones); + ui->gb_triggers->setEnabled(enable_deadzones); + + // Enable Trigger Thresholds + ui->slider_trigger_left->setRange(0, m_handler->trigger_max); + ui->slider_trigger_left->setValue(m_handler_cfg.ltriggerthreshold); + + ui->slider_trigger_right->setRange(0, m_handler->trigger_max); + ui->slider_trigger_right->setValue(m_handler_cfg.rtriggerthreshold); + + ui->preview_trigger_left->setRange(0, m_handler->trigger_max); + ui->preview_trigger_right->setRange(0, m_handler->trigger_max); + + // Enable Stick Deadzones + ui->slider_stick_left->setRange(0, m_handler->thumb_max); + ui->slider_stick_left->setValue(m_handler_cfg.lstickdeadzone); + + ui->slider_stick_right->setRange(0, m_handler->thumb_max); + ui->slider_stick_right->setValue(m_handler_cfg.rstickdeadzone); + + RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->size().width(), lx, ly); + RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), rx, ry); } void pad_settings_dialog::ReactivateButtons() @@ -350,7 +495,7 @@ void pad_settings_dialog::RepaintPreviewLabel(QLabel* l, int dz, int w, int x, i void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) { - if (m_handler_type != pad_handler::keyboard) + if (m_handler->m_type != pad_handler::keyboard) { return; } @@ -362,7 +507,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) if (m_button_id <= button_ids::id_pad_begin || m_button_id >= button_ids::id_pad_end) { - LOG_NOTICE(HLE, "Pad Settings: Handler Type: %d, Unknown button ID: %d", static_cast(m_handler_type), m_button_id); + LOG_NOTICE(HLE, "Pad Settings: Handler Type: %d, Unknown button ID: %d", static_cast(m_handler->m_type), m_button_id); } else { @@ -375,7 +520,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) void pad_settings_dialog::mousePressEvent(QMouseEvent* event) { - if (m_handler_type != pad_handler::keyboard) + if (m_handler->m_type != pad_handler::keyboard) { return; } @@ -387,7 +532,7 @@ void pad_settings_dialog::mousePressEvent(QMouseEvent* event) if (m_button_id <= button_ids::id_pad_begin || m_button_id >= button_ids::id_pad_end) { - LOG_NOTICE(HLE, "Pad Settings: Handler Type: %d, Unknown button ID: %d", static_cast(m_handler_type), m_button_id); + LOG_NOTICE(HLE, "Pad Settings: Handler Type: %d, Unknown button ID: %d", static_cast(m_handler->m_type), m_button_id); } else { @@ -402,7 +547,9 @@ bool pad_settings_dialog::eventFilter(QObject* object, QEvent* event) { // Disabled buttons should not absorb mouseclicks if (event->type() == QEvent::MouseButtonPress) + { event->ignore(); + } return QDialog::eventFilter(object, event); } @@ -446,8 +593,263 @@ void pad_settings_dialog::SwitchButtons(bool is_enabled) } } -void pad_settings_dialog::SaveConfig() +void pad_settings_dialog::OnPadButtonClicked(int id) { + switch (id) + { + case button_ids::id_pad_begin: + case button_ids::id_pad_end: + case button_ids::id_refresh: + case button_ids::id_ok: + case button_ids::id_cancel: + return; + case button_ids::id_reset_parameters: + ReactivateButtons(); + m_handler_cfg.from_default(); + UpdateLabel(true); + return; + case button_ids::id_blacklist: + m_handler->GetNextButtonPress(m_device_name, nullptr, true); + return; + default: + break; + } + + for (auto but : m_padButtons->buttons()) + { + but->setFocusPolicy(Qt::ClickFocus); + } + + m_button_id = id; + m_padButtons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(MAX_SECONDS)); + m_padButtons->button(m_button_id)->setPalette(QPalette(Qt::blue)); + SwitchButtons(false); // disable all buttons, needed for using Space, Enter and other specific buttons + m_timer.start(1000); +} + +void pad_settings_dialog::OnTabChanged(int index) +{ + // Save old profile + SaveProfile(); + + // Move layout to the new tab + m_tabs->widget(index)->setLayout(ui->mainLayout); + + // Refresh handlers + RefreshInputTypes(); +} + +std::shared_ptr pad_settings_dialog::GetHandler(pad_handler type) +{ + std::shared_ptr ret_handler; + + switch (type) + { + case pad_handler::null: + ret_handler = std::make_unique(); + break; + case pad_handler::keyboard: + ret_handler = std::make_unique(); + break; + case pad_handler::ds4: + ret_handler = std::make_unique(); + break; +#ifdef _MSC_VER + case pad_handler::xinput: + ret_handler = std::make_unique(); + break; +#endif +#ifdef _WIN32 + case pad_handler::mm: + ret_handler = std::make_unique(); + break; +#endif +#ifdef HAVE_LIBEVDEV + case pad_handler::evdev: + ret_handler = std::make_unique(); + break; +#endif + } + + return ret_handler; +} + +void pad_settings_dialog::ChangeInputType() +{ + bool force_enable = false; // enable configs even with disconnected devices + const int player = m_tabs->currentIndex(); + + const std::string handler = sstr(ui->chooseHandler->currentText()); + const std::string device = g_cfg_input.player[player]->device.to_string(); + const std::string profile = g_cfg_input.player[player]->profile.to_string(); + + // Change this player's current handler + if (!g_cfg_input.player[player]->handler.from_string(handler)) + { + // Something went wrong + LOG_ERROR(GENERAL, "Failed to convert input string:%s", handler); + return; + } + + ui->chooseDevice->clear(); + ui->chooseProfile->clear(); + + // Get this player's current handler and it's currently available devices + m_handler = GetHandler(g_cfg_input.player[player]->handler); + const std::vector list_devices = m_handler->ListDevices(); + + // Refill the device combobox with currently available devices + switch (m_handler->m_type) + { +#ifdef _MSC_VER + case pad_handler::xinput: + { + const QString name_string = qstr(m_handler->name_string()); + for (int i = 0; i < m_handler->max_devices(); i++) + { + ui->chooseDevice->addItem(name_string + QString::number(i), i); + } + force_enable = true; + break; + } +#endif + default: + { + for (int i = 0; i < list_devices.size(); i++) + { + ui->chooseDevice->addItem(qstr(list_devices[i]), i); + } + break; + } + } + + // Handle empty device list + bool config_enabled = force_enable || (m_handler->m_type != pad_handler::null && list_devices.size() > 0); + ui->chooseDevice->setEnabled(config_enabled); + + if (config_enabled) + { + ui->chooseDevice->setCurrentText(qstr(device)); + + QString profile_dir = qstr(PadHandlerBase::get_config_dir(m_handler->m_type)); + QStringList profiles = gui::utils::get_dir_entries(QDir(profile_dir), QStringList() << "*.yml"); + + if (profiles.isEmpty()) + { + QString def_name = "Default Profile"; + if (CreateConfigFile(profile_dir, def_name)) + { + ui->chooseProfile->addItem(def_name); + } + else + { + config_enabled = false; + } + } + else + { + for (const auto& prof : profiles) + { + ui->chooseProfile->addItem(prof); + } + ui->chooseProfile->setCurrentText(qstr(profile)); + } + } + else + { + ui->chooseProfile->addItem(tr("No Profiles")); + ui->chooseDevice->addItem(tr("No Device Detected"), -1); + } + + // enable configuration and profile list if possible + SwitchButtons(config_enabled); + ui->b_addProfile->setEnabled(config_enabled); + ui->chooseProfile->setEnabled(config_enabled); +} + +void pad_settings_dialog::ChangeProfile() +{ + if (!m_handler) + { + return; + } + + // Handle running timers + if (m_timer.isActive()) + { + ReactivateButtons(); + } + if (m_timer_input.isActive()) + { + m_timer_input.stop(); + } + + // Change handler + const std::string cfg_name = PadHandlerBase::get_config_dir(m_handler->m_type) + m_profile + ".yml"; + + // Adjust to the different pad handlers + switch (m_handler->m_type) + { + case pad_handler::null: + ((NullPadHandler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); + break; + case pad_handler::keyboard: + ui->b_blacklist->setEnabled(false); + ((keyboard_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); + break; + case pad_handler::ds4: + ((ds4_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); + break; +#ifdef _MSC_VER + case pad_handler::xinput: + ((xinput_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); + break; +#endif +#ifdef _WIN32 + case pad_handler::mm: + ((mm_joystick_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); + break; +#endif +#ifdef HAVE_LIBEVDEV + case pad_handler::evdev: + ((evdev_joystick_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); + break; +#endif + default: + break; + } + + // Load new config + m_handler_cfg.load(); + + // Reload the buttons with the new handler and profile + ReloadButtons(); + + // Reenable input timer + if (ui->chooseDevice->isEnabled() && ui->chooseDevice->currentIndex() >= 0) + { + m_timer_input.start(1); + } +} + +void pad_settings_dialog::RefreshInputTypes() +{ + // Set the current input type from config. Disable signal to have ChangeInputType always executed exactly once + ui->chooseHandler->blockSignals(true); + ui->chooseHandler->setCurrentText(qstr(g_cfg_input.player[m_tabs->currentIndex()]->handler.to_string())); + ui->chooseHandler->blockSignals(false); + + // Force Change + ChangeInputType(); +} + +void pad_settings_dialog::SaveProfile() +{ + if (!m_handler || !ui->chooseProfile->isEnabled() || ui->chooseProfile->currentIndex() < 0) + { + return; + } + for (const auto& entry : m_cfg_entries) { entry.second.cfg_name->from_string(entry.second.key); @@ -471,38 +873,30 @@ void pad_settings_dialog::SaveConfig() m_handler_cfg.save(); } -void pad_settings_dialog::OnPadButtonClicked(int id) +void pad_settings_dialog::SaveExit() { - switch (id) + SaveProfile(); + + // Check for invalid selection + if (!ui->chooseDevice->isEnabled() || ui->chooseDevice->currentIndex() < 0) { - case button_ids::id_pad_begin: - case button_ids::id_pad_end: - case button_ids::id_cancel: - return; - case button_ids::id_reset_parameters: - ReactivateButtons(); - m_handler_cfg.from_default(); - UpdateLabel(true); - return; - case button_ids::id_blacklist: - m_handler->GetNextButtonPress(m_device_name, nullptr, true); - return; - case button_ids::id_ok: - SaveConfig(); - QDialog::accept(); - return; - default: - break; + const int i = m_tabs->currentIndex(); + + g_cfg_input.player[i]->handler.from_default(); + g_cfg_input.player[i]->device.from_default(); + g_cfg_input.player[i]->profile.from_default(); } - for (auto but : m_padButtons->buttons()) - { - but->setFocusPolicy(Qt::ClickFocus); - } + g_cfg_input.save(); - m_button_id = id; - m_padButtons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(MAX_SECONDS)); - m_padButtons->button(m_button_id)->setPalette(QPalette(Qt::blue)); - SwitchButtons(false); // disable all buttons, needed for using Space, Enter and other specific buttons - m_timer.start(1000); + QDialog::accept(); +} + +void pad_settings_dialog::CancelExit() +{ + // Reloads config from file or defaults + g_cfg_input.from_default(); + g_cfg_input.load(); + + QDialog::reject(); } diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 2477a3f8e6..bf95f26f45 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -3,27 +3,11 @@ #include #include #include -#include #include +#include #include -#include "keyboard_pad_handler.h" -#include "Utilities/types.h" -#include "Utilities/Config.h" #include "Emu/Io/PadHandler.h" -#include "stdafx.h" -#include "Emu/System.h" - -#ifdef _WIN32 -#include "xinput_pad_handler.h" -#endif -#ifdef _MSC_VER -#include "mm_joystick_handler.h" -#endif -#ifdef HAVE_LIBEVDEV -#include "evdev_joystick_handler.h" -#endif -#include "ds4_pad_handler.h" namespace Ui { @@ -34,6 +18,8 @@ class pad_settings_dialog : public QDialog { Q_OBJECT + const int MAX_PLAYERS = 7; + enum button_ids { id_pad_begin, // begin @@ -74,6 +60,7 @@ class pad_settings_dialog : public QDialog id_reset_parameters, id_blacklist, + id_refresh, id_ok, id_cancel }; @@ -85,12 +72,26 @@ class pad_settings_dialog : public QDialog QString text; }; +public: + explicit pad_settings_dialog(QWidget *parent = nullptr); + ~pad_settings_dialog(); + private Q_SLOTS: void OnPadButtonClicked(int id); + void OnTabChanged(int index); + void RefreshInputTypes(); + void ChangeInputType(); + /** Save the Pad Configuration to the current Pad Handler Config File */ + void SaveProfile(); + void SaveExit(); + void CancelExit(); private: Ui::pad_settings_dialog *ui; + // TabWidget + QTabWidget* m_tabs; + // Button Mapping QButtonGroup* m_padButtons; u32 m_button_id = id_pad_begin; @@ -102,14 +103,18 @@ private: int rx = 0; int ry = 0; + // Rumble + s32 m_min_force; + s32 m_max_force; + // Backup for standard button palette QPalette m_palette; - // Pad Handlers - pad_handler m_handler_type; + // Pad Handlers std::shared_ptr m_handler; pad_config m_handler_cfg; std::string m_device_name; + std::string m_profile; // Remap Timer const int MAX_SECONDS = 5; @@ -119,27 +124,28 @@ private: // Input timer. Its Callback handles the input QTimer m_timer_input; - /** Resets the view to default. Resets the Remap Timer */ - void ReactivateButtons(); - - /** Repaints a stick deadzone preview label */ - void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y); - -public: - explicit pad_settings_dialog(const std::string& device, const std::string& profile, std::shared_ptr handler, QWidget *parent = nullptr); - ~pad_settings_dialog(); - - /** Handle keyboard handler input */ - void keyPressEvent(QKeyEvent *keyEvent) override; - void mousePressEvent(QMouseEvent *event) override; - bool eventFilter(QObject* object, QEvent* event) override; - /** Update all the Button Labels with current button mapping */ void UpdateLabel(bool is_reset = false); /** Enable/Disable Buttons while trying to remap an other */ void SwitchButtons(bool is_enabled); - /** Save the Pad Configuration to the current Pad Handler Config File */ - void SaveConfig(); + /** Resets the view to default. Resets the Remap Timer */ + void ReactivateButtons(); + + void InitButtons(); + void ReloadButtons(); + + void ChangeProfile(); + + /** Repaints a stick deadzone preview label */ + void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y); + + std::shared_ptr GetHandler(pad_handler type); + +protected: + /** Handle keyboard handler input */ + void keyPressEvent(QKeyEvent *keyEvent) override; + void mousePressEvent(QMouseEvent *event) override; + bool eventFilter(QObject* object, QEvent* event) override; }; diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.ui b/rpcs3/rpcs3qt/pad_settings_dialog.ui index fe26ee6e0f..b9ade1f0ef 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.ui +++ b/rpcs3/rpcs3qt/pad_settings_dialog.ui @@ -17,867 +17,782 @@ :/rpcs3.ico:/rpcs3.ico - - - - - 5 - - - - - D-Pad - - - - 7 + + + + 60 + 10 + 878 + 624 + + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + Handlers - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Up - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - W - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Left - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - A - - - false - - - - - - - - - - Right - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - D - - - false - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Down - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - S - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - Left Analog - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Up - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Up - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Left - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Left - - - false - - - - - - - - - - Right - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Right - - - false - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Down - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Down - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - 0 - 80 - - - - Trigger Thresholds - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - - false - - - Qt::Horizontal - - - - - - - false - - - Qt::Horizontal - - - - - - - - - - - false - - - Qt::Horizontal - - - - - - - false - - - Qt::Horizontal - - - - - - - - - - - - Enable Vibration - - - - 5 - - - 9 - - - 5 - - - 9 - - - - - false - - - Large - - - true - - - - - - - false - - - Small - - - true - - - - - - - false - - - Switch - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - - Save + + + 5 - - false + + 5 - - - - - - Close + + 5 + + + 5 - - - - - - - - - - 0 - - - - - 0 - - - - - - L1 - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Q - - - false - - - - - + - - - L2 + + + Refresh + + + false - - - 5 - - - 5 - - - 5 - - - 5 - - - - - R - - - false - - - - - - - + + + + + + Devices + + + + 5 + + + 5 + + + 5 + + + 5 + - - - 10 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Select - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Space - - - false - - - - - - - - - - Start - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Enter - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + + + + + + Profiles + + + + 5 + + + 5 + + + 5 + + + 5 + + + - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal + + + Add Profile + + + false + + + + + + + + + + + + + + 5 + + + + + D-Pad + + + + 6 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + 0 - - - 40 - 20 - + + 0 - - + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Up + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + W + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Left + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + A + + + false + + + + + + + + + + Right + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + D + + + false + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Down + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + S + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Left Analog + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Up + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Up + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Left + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Left + + + false + + + + + + + + + + Right + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Right + + + false + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Down + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Down + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 80 + + + + Trigger Thresholds + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + + + + + + + Enable Vibration + + + + 5 + + + 9 + + + 5 + + + 9 + + + + + Large + + + true + + + + + + + Small + + + true + + + + + + + Switch + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 0 + + + + + + + + + + Save + + + false + + + + + + + Close + + + true + + + + + + + + + + + 0 + + + + + 0 + + + - + - PS Button + L1 - + 5 @@ -891,9 +806,9 @@ 5 - + - Backspace + Q false @@ -904,180 +819,1035 @@ - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - R1 - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - E - - - false + + + L2 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + R + + + false + + + + - - - - - - R2 - - - - 5 - - - 5 - - - 5 - - - 5 - + + + - - - T - - - false + + + 10 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Select + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Space + + + false + + + + + + + + + + Start + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Enter + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + PS Button + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Backspace + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - - - - - - - - - 0 - 200 - - - - - 0 - - - 0 - - - 0 - - - 0 - + + + + + + + R1 + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + E + + + false + + + + + + + + + + R2 + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + T + + + false + + + + + + + + + + - - + + - 430 - 265 + 0 + 200 - - + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 430 + 265 + + + + + + + Qt::AutoText + + + :/Icons/controller.png + + + true + + + Qt::AlignBottom|Qt::AlignHCenter + + + + + + + + + + 10 - - Qt::AutoText + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + L3 + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + F + + + false + + + + + + + + + + R3 + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + G + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical - - :/Icons/controller.png + + QSizePolicy::MinimumExpanding - - true + + + 20 + 0 + - - Qt::AlignBottom|Qt::AlignHCenter + + + + + + Description + + + + + Unfortunately, we currently do not natively support DualShock 3 controllers. You can however use third party tools like SCP Driver Package to allow your DualShock 3 controller to function like an XInput controller. We plan to add additional input methods in the future. + + + Qt::PlainText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + - - - - - - 10 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - L3 - - - - 5 + + + + + 5 + + + + + Face Buttons - - 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Triangle + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + V + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Square + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Z + + + false + + + + + + + + + + Circle + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + C + + + false + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cross + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + X + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Right Analog - - 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Up + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + PgUp + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Left + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Home + + + false + + + + + + + + + + Right + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + End + + + false + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Down + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + PgDown + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Analog Deadzones - - 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + + + + + + Qt::Vertical + + QSizePolicy::MinimumExpanding + + + + 20 + 0 + + + + + + - + - F + Filter Noise + + + false + + + + + + + Restore Defaults false @@ -1085,673 +1855,13 @@ - - - - - - R3 - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - G - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - Description - - - - - - Unfortunately, we currently do not natively support DualShock 3 controllers. You can however use third party tools like SCP Driver Package to allow your DualShock 3 controller to function like an XInput controller. We plan to add additional input methods in the future. - - - Qt::PlainText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - - 5 - - - - - Face Buttons - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Triangle - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - V - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Square - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Z - - - false - - - - - - - - - - Circle - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - C - - - false - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Cross - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - X - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - Right Analog - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Up - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - PgUp - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Left - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Home - - - false - - - - - - - - - - Right - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - End - - - false - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Down - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - PgDown - - - false - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - Analog Deadzones - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - - false - - - Qt::Horizontal - - - - - - - - - - - - - - - - - - false - - - Qt::Horizontal - - - - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - - Filter Noise - - - - - - - Restore Defaults - - - false - - - - - - - - + + + + +