summaryrefslogtreecommitdiff
path: root/src/yuzu/configuration
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/configuration')
-rw-r--r--src/yuzu/configuration/config.cpp403
-rw-r--r--src/yuzu/configuration/config.h14
-rw-r--r--src/yuzu/configuration/configure_audio.h5
-rw-r--r--src/yuzu/configuration/configure_debug.cpp4
-rw-r--r--src/yuzu/configuration/configure_debug.h3
-rw-r--r--src/yuzu/configuration/configure_debug.ui31
-rw-r--r--src/yuzu/configuration/configure_dialog.h3
-rw-r--r--src/yuzu/configuration/configure_gamelist.cpp16
-rw-r--r--src/yuzu/configuration/configure_gamelist.h4
-rw-r--r--src/yuzu/configuration/configure_gamelist.ui223
-rw-r--r--src/yuzu/configuration/configure_general.cpp36
-rw-r--r--src/yuzu/configuration/configure_general.h3
-rw-r--r--src/yuzu/configuration/configure_general.ui9
-rw-r--r--src/yuzu/configuration/configure_graphics.h3
-rw-r--r--src/yuzu/configuration/configure_graphics.ui94
-rw-r--r--src/yuzu/configuration/configure_input.cpp446
-rw-r--r--src/yuzu/configuration/configure_input.h58
-rw-r--r--src/yuzu/configuration/configure_input.ui1064
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp500
-rw-r--r--src/yuzu/configuration/configure_input_player.h104
-rw-r--r--src/yuzu/configuration/configure_input_player.ui1164
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp213
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.h68
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.ui261
-rw-r--r--src/yuzu/configuration/configure_system.cpp19
-rw-r--r--src/yuzu/configuration/configure_system.ui228
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.cpp42
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.h32
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.ui199
-rw-r--r--src/yuzu/configuration/configure_web.h5
30 files changed, 3913 insertions, 1341 deletions
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index d4fd60a73..83ebbd1fe 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -5,6 +5,7 @@
#include <QSettings>
#include "common/file_util.h"
#include "core/hle/service/acc/profile_manager.h"
+#include "core/hle/service/hid/controllers/npad.h"
#include "input_common/main.h"
#include "yuzu/configuration/config.h"
#include "yuzu/ui_settings.h"
@@ -47,40 +48,313 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config:
},
}};
-void Config::ReadValues() {
- qt_config->beginGroup("Controls");
+const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons =
+ {
+ Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal,
+};
+
+const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> Config::default_keyboard_keys = {
+ 0,
+ 0,
+ 0,
+ 0,
+ Qt::Key_A,
+ Qt::Key_B,
+ Qt::Key_C,
+ Qt::Key_D,
+ Qt::Key_E,
+ Qt::Key_F,
+ Qt::Key_G,
+ Qt::Key_H,
+ Qt::Key_I,
+ Qt::Key_J,
+ Qt::Key_K,
+ Qt::Key_L,
+ Qt::Key_M,
+ Qt::Key_N,
+ Qt::Key_O,
+ Qt::Key_P,
+ Qt::Key_Q,
+ Qt::Key_R,
+ Qt::Key_S,
+ Qt::Key_T,
+ Qt::Key_U,
+ Qt::Key_V,
+ Qt::Key_W,
+ Qt::Key_X,
+ Qt::Key_Y,
+ Qt::Key_Z,
+ Qt::Key_1,
+ Qt::Key_2,
+ Qt::Key_3,
+ Qt::Key_4,
+ Qt::Key_5,
+ Qt::Key_6,
+ Qt::Key_7,
+ Qt::Key_8,
+ Qt::Key_9,
+ Qt::Key_0,
+ Qt::Key_Enter,
+ Qt::Key_Escape,
+ Qt::Key_Backspace,
+ Qt::Key_Tab,
+ Qt::Key_Space,
+ Qt::Key_Minus,
+ Qt::Key_Equal,
+ Qt::Key_BracketLeft,
+ Qt::Key_BracketRight,
+ Qt::Key_Backslash,
+ Qt::Key_Dead_Tilde,
+ Qt::Key_Semicolon,
+ Qt::Key_Apostrophe,
+ Qt::Key_Dead_Grave,
+ Qt::Key_Comma,
+ Qt::Key_Period,
+ Qt::Key_Slash,
+ Qt::Key_CapsLock,
+
+ Qt::Key_F1,
+ Qt::Key_F2,
+ Qt::Key_F3,
+ Qt::Key_F4,
+ Qt::Key_F5,
+ Qt::Key_F6,
+ Qt::Key_F7,
+ Qt::Key_F8,
+ Qt::Key_F9,
+ Qt::Key_F10,
+ Qt::Key_F11,
+ Qt::Key_F12,
+
+ Qt::Key_SysReq,
+ Qt::Key_ScrollLock,
+ Qt::Key_Pause,
+ Qt::Key_Insert,
+ Qt::Key_Home,
+ Qt::Key_PageUp,
+ Qt::Key_Delete,
+ Qt::Key_End,
+ Qt::Key_PageDown,
+ Qt::Key_Right,
+ Qt::Key_Left,
+ Qt::Key_Down,
+ Qt::Key_Up,
+
+ Qt::Key_NumLock,
+ Qt::Key_Slash,
+ Qt::Key_Asterisk,
+ Qt::Key_Minus,
+ Qt::Key_Plus,
+ Qt::Key_Enter,
+ Qt::Key_1,
+ Qt::Key_2,
+ Qt::Key_3,
+ Qt::Key_4,
+ Qt::Key_5,
+ Qt::Key_6,
+ Qt::Key_7,
+ Qt::Key_8,
+ Qt::Key_9,
+ Qt::Key_0,
+ Qt::Key_Period,
+
+ 0,
+ 0,
+ Qt::Key_PowerOff,
+ Qt::Key_Equal,
+
+ Qt::Key_F13,
+ Qt::Key_F14,
+ Qt::Key_F15,
+ Qt::Key_F16,
+ Qt::Key_F17,
+ Qt::Key_F18,
+ Qt::Key_F19,
+ Qt::Key_F20,
+ Qt::Key_F21,
+ Qt::Key_F22,
+ Qt::Key_F23,
+ Qt::Key_F24,
+
+ Qt::Key_Open,
+ Qt::Key_Help,
+ Qt::Key_Menu,
+ 0,
+ Qt::Key_Stop,
+ Qt::Key_AudioRepeat,
+ Qt::Key_Undo,
+ Qt::Key_Cut,
+ Qt::Key_Copy,
+ Qt::Key_Paste,
+ Qt::Key_Find,
+ Qt::Key_VolumeMute,
+ Qt::Key_VolumeUp,
+ Qt::Key_VolumeDown,
+ Qt::Key_CapsLock,
+ Qt::Key_NumLock,
+ Qt::Key_ScrollLock,
+ Qt::Key_Comma,
+
+ Qt::Key_ParenLeft,
+ Qt::Key_ParenRight,
+};
+
+const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default_keyboard_mods = {
+ Qt::Key_Control, Qt::Key_Shift, Qt::Key_Alt, Qt::Key_ApplicationLeft,
+ Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight,
+};
+
+void Config::ReadPlayerValues() {
+ for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
+ Settings::values.players[p].connected =
+ qt_config->value(QString("player_%1_connected").arg(p), false).toBool();
+
+ Settings::values.players[p].type = static_cast<Settings::ControllerType>(
+ qt_config
+ ->value(QString("player_%1_type").arg(p),
+ static_cast<u8>(Settings::ControllerType::DualJoycon))
+ .toUInt());
+
+ Settings::values.players[p].body_color_left =
+ qt_config
+ ->value(QString("player_%1_body_color_left").arg(p),
+ Settings::JOYCON_BODY_NEON_BLUE)
+ .toUInt();
+ Settings::values.players[p].body_color_right =
+ qt_config
+ ->value(QString("player_%1_body_color_right").arg(p),
+ Settings::JOYCON_BODY_NEON_RED)
+ .toUInt();
+ Settings::values.players[p].button_color_left =
+ qt_config
+ ->value(QString("player_%1_button_color_left").arg(p),
+ Settings::JOYCON_BUTTONS_NEON_BLUE)
+ .toUInt();
+ Settings::values.players[p].button_color_right =
+ qt_config
+ ->value(QString("player_%1_button_color_right").arg(p),
+ Settings::JOYCON_BUTTONS_NEON_RED)
+ .toUInt();
+
+ for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
+ std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
+ Settings::values.players[p].buttons[i] =
+ qt_config
+ ->value(QString("player_%1_").arg(p) + Settings::NativeButton::mapping[i],
+ QString::fromStdString(default_param))
+ .toString()
+ .toStdString();
+ if (Settings::values.players[p].buttons[i].empty())
+ Settings::values.players[p].buttons[i] = default_param;
+ }
+
+ for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
+ std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
+ default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
+ default_analogs[i][3], default_analogs[i][4], 0.5f);
+ Settings::values.players[p].analogs[i] =
+ qt_config
+ ->value(QString("player_%1_").arg(p) + Settings::NativeAnalog::mapping[i],
+ QString::fromStdString(default_param))
+ .toString()
+ .toStdString();
+ if (Settings::values.players[p].analogs[i].empty())
+ Settings::values.players[p].analogs[i] = default_param;
+ }
+ }
+
+ std::stable_partition(
+ Settings::values.players.begin(),
+ Settings::values.players.begin() +
+ Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
+ [](const auto& player) { return player.connected; });
+}
+
+void Config::ReadDebugValues() {
+ Settings::values.debug_pad_enabled = qt_config->value("debug_pad_enabled", false).toBool();
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
- Settings::values.buttons[i] =
+ Settings::values.debug_pad_buttons[i] =
qt_config
- ->value(Settings::NativeButton::mapping[i], QString::fromStdString(default_param))
+ ->value(QString("debug_pad_") + Settings::NativeButton::mapping[i],
+ QString::fromStdString(default_param))
.toString()
.toStdString();
- if (Settings::values.buttons[i].empty())
- Settings::values.buttons[i] = default_param;
+ if (Settings::values.debug_pad_buttons[i].empty())
+ Settings::values.debug_pad_buttons[i] = default_param;
}
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
default_analogs[i][3], default_analogs[i][4], 0.5f);
- Settings::values.analogs[i] =
+ Settings::values.debug_pad_analogs[i] =
+ qt_config
+ ->value(QString("debug_pad_") + Settings::NativeAnalog::mapping[i],
+ QString::fromStdString(default_param))
+ .toString()
+ .toStdString();
+ if (Settings::values.debug_pad_analogs[i].empty())
+ Settings::values.debug_pad_analogs[i] = default_param;
+ }
+}
+
+void Config::ReadKeyboardValues() {
+ Settings::values.keyboard_enabled = qt_config->value("keyboard_enabled", false).toBool();
+
+ std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(),
+ Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
+ std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
+ Settings::values.keyboard_keys.begin() +
+ Settings::NativeKeyboard::LeftControlKey,
+ InputCommon::GenerateKeyboardParam);
+ std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
+ Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
+}
+
+void Config::ReadMouseValues() {
+ Settings::values.mouse_enabled = qt_config->value("mouse_enabled", false).toBool();
+
+ for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
+ std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
+ Settings::values.mouse_buttons[i] =
qt_config
- ->value(Settings::NativeAnalog::mapping[i], QString::fromStdString(default_param))
+ ->value(QString("mouse_") + Settings::NativeMouseButton::mapping[i],
+ QString::fromStdString(default_param))
.toString()
.toStdString();
- if (Settings::values.analogs[i].empty())
- Settings::values.analogs[i] = default_param;
+ if (Settings::values.mouse_buttons[i].empty())
+ Settings::values.mouse_buttons[i] = default_param;
}
+}
+
+void Config::ReadTouchscreenValues() {
+ Settings::values.touchscreen.enabled = qt_config->value("touchscreen_enabled", true).toBool();
+ Settings::values.touchscreen.device =
+ qt_config->value("touchscreen_device", "engine:emu_window").toString().toStdString();
+
+ Settings::values.touchscreen.finger = qt_config->value("touchscreen_finger", 0).toUInt();
+ Settings::values.touchscreen.rotation_angle = qt_config->value("touchscreen_angle", 0).toUInt();
+ Settings::values.touchscreen.diameter_x =
+ qt_config->value("touchscreen_diameter_x", 15).toUInt();
+ Settings::values.touchscreen.diameter_y =
+ qt_config->value("touchscreen_diameter_y", 15).toUInt();
+ qt_config->endGroup();
+}
+
+void Config::ReadValues() {
+ qt_config->beginGroup("Controls");
+
+ ReadPlayerValues();
+ ReadDebugValues();
+ ReadKeyboardValues();
+ ReadMouseValues();
+ ReadTouchscreenValues();
Settings::values.motion_device =
qt_config->value("motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01")
.toString()
.toStdString();
- Settings::values.touch_device =
- qt_config->value("touch_device", "engine:emu_window").toString().toStdString();
-
- qt_config->endGroup();
qt_config->beginGroup("Core");
Settings::values.use_cpu_jit = qt_config->value("use_cpu_jit", true).toBool();
@@ -126,6 +400,11 @@ void Config::ReadValues() {
.toStdString());
qt_config->endGroup();
+ qt_config->beginGroup("Core");
+ Settings::values.use_cpu_jit = qt_config->value("use_cpu_jit", true).toBool();
+ Settings::values.use_multi_core = qt_config->value("use_multi_core", false).toBool();
+ qt_config->endGroup();
+
qt_config->beginGroup("System");
Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool();
Settings::values.enable_nfc = qt_config->value("enable_nfc", true).toBool();
@@ -134,6 +413,14 @@ void Config::ReadValues() {
Service::Account::MAX_USERS - 1);
Settings::values.language_index = qt_config->value("language_index", 1).toInt();
+
+ const auto enabled = qt_config->value("rng_seed_enabled", false).toBool();
+ if (enabled) {
+ Settings::values.rng_seed = qt_config->value("rng_seed", 0).toULongLong();
+ } else {
+ Settings::values.rng_seed = std::nullopt;
+ }
+
qt_config->endGroup();
qt_config->beginGroup("Miscellaneous");
@@ -145,6 +432,8 @@ void Config::ReadValues() {
Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool();
Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt();
Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString();
+ Settings::values.dump_exefs = qt_config->value("dump_exefs", false).toBool();
+ Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool();
qt_config->endGroup();
qt_config->beginGroup("WebService");
@@ -162,6 +451,7 @@ void Config::ReadValues() {
qt_config->beginGroup("UIGameList");
UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool();
+ UISettings::values.show_add_ons = qt_config->value("show_add_ons", true).toBool();
UISettings::values.icon_size = qt_config->value("icon_size", 64).toUInt();
UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 3).toUInt();
UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 2).toUInt();
@@ -220,18 +510,81 @@ void Config::ReadValues() {
qt_config->endGroup();
}
-void Config::SaveValues() {
- qt_config->beginGroup("Controls");
+void Config::SavePlayerValues() {
+ for (int p = 0; p < Settings::values.players.size(); ++p) {
+ qt_config->setValue(QString("player_%1_connected").arg(p),
+ Settings::values.players[p].connected);
+ qt_config->setValue(QString("player_%1_type").arg(p),
+ static_cast<u8>(Settings::values.players[p].type));
+
+ qt_config->setValue(QString("player_%1_body_color_left").arg(p),
+ Settings::values.players[p].body_color_left);
+ qt_config->setValue(QString("player_%1_body_color_right").arg(p),
+ Settings::values.players[p].body_color_right);
+ qt_config->setValue(QString("player_%1_button_color_left").arg(p),
+ Settings::values.players[p].button_color_left);
+ qt_config->setValue(QString("player_%1_button_color_right").arg(p),
+ Settings::values.players[p].button_color_right);
+
+ for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
+ qt_config->setValue(QString("player_%1_").arg(p) +
+ QString::fromStdString(Settings::NativeButton::mapping[i]),
+ QString::fromStdString(Settings::values.players[p].buttons[i]));
+ }
+ for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
+ qt_config->setValue(QString("player_%1_").arg(p) +
+ QString::fromStdString(Settings::NativeAnalog::mapping[i]),
+ QString::fromStdString(Settings::values.players[p].analogs[i]));
+ }
+ }
+}
+
+void Config::SaveDebugValues() {
+ qt_config->setValue("debug_pad_enabled", Settings::values.debug_pad_enabled);
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
- qt_config->setValue(QString::fromStdString(Settings::NativeButton::mapping[i]),
- QString::fromStdString(Settings::values.buttons[i]));
+ qt_config->setValue(QString("debug_pad_") +
+ QString::fromStdString(Settings::NativeButton::mapping[i]),
+ QString::fromStdString(Settings::values.debug_pad_buttons[i]));
}
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
- qt_config->setValue(QString::fromStdString(Settings::NativeAnalog::mapping[i]),
- QString::fromStdString(Settings::values.analogs[i]));
+ qt_config->setValue(QString("debug_pad_") +
+ QString::fromStdString(Settings::NativeAnalog::mapping[i]),
+ QString::fromStdString(Settings::values.debug_pad_analogs[i]));
+ }
+}
+
+void Config::SaveMouseValues() {
+ qt_config->setValue("mouse_enabled", Settings::values.mouse_enabled);
+
+ for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
+ qt_config->setValue(QString("mouse_") +
+ QString::fromStdString(Settings::NativeMouseButton::mapping[i]),
+ QString::fromStdString(Settings::values.mouse_buttons[i]));
}
+}
+
+void Config::SaveTouchscreenValues() {
+ qt_config->setValue("touchscreen_enabled", Settings::values.touchscreen.enabled);
+ qt_config->setValue("touchscreen_device",
+ QString::fromStdString(Settings::values.touchscreen.device));
+
+ qt_config->setValue("touchscreen_finger", Settings::values.touchscreen.finger);
+ qt_config->setValue("touchscreen_angle", Settings::values.touchscreen.rotation_angle);
+ qt_config->setValue("touchscreen_diameter_x", Settings::values.touchscreen.diameter_x);
+ qt_config->setValue("touchscreen_diameter_y", Settings::values.touchscreen.diameter_y);
+}
+
+void Config::SaveValues() {
+ qt_config->beginGroup("Controls");
+
+ SavePlayerValues();
+ SaveDebugValues();
+ SaveMouseValues();
+ SaveTouchscreenValues();
+
qt_config->setValue("motion_device", QString::fromStdString(Settings::values.motion_device));
- qt_config->setValue("touch_device", QString::fromStdString(Settings::values.touch_device));
+ qt_config->setValue("keyboard_enabled", Settings::values.keyboard_enabled);
+
qt_config->endGroup();
qt_config->beginGroup("Core");
@@ -270,8 +623,11 @@ void Config::SaveValues() {
qt_config->setValue("use_docked_mode", Settings::values.use_docked_mode);
qt_config->setValue("enable_nfc", Settings::values.enable_nfc);
qt_config->setValue("current_user", Settings::values.current_user);
-
qt_config->setValue("language_index", Settings::values.language_index);
+
+ qt_config->setValue("rng_seed_enabled", Settings::values.rng_seed.has_value());
+ qt_config->setValue("rng_seed", Settings::values.rng_seed.value_or(0));
+
qt_config->endGroup();
qt_config->beginGroup("Miscellaneous");
@@ -283,6 +639,8 @@ void Config::SaveValues() {
qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub);
qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port);
qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args));
+ qt_config->setValue("dump_exefs", Settings::values.dump_exefs);
+ qt_config->setValue("dump_nso", Settings::values.dump_nso);
qt_config->endGroup();
qt_config->beginGroup("WebService");
@@ -298,6 +656,7 @@ void Config::SaveValues() {
qt_config->beginGroup("UIGameList");
qt_config->setValue("show_unknown", UISettings::values.show_unknown);
+ qt_config->setValue("show_add_ons", UISettings::values.show_add_ons);
qt_config->setValue("icon_size", UISettings::values.icon_size);
qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id);
qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id);
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 9c99c1b75..a1c27bbf9 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -22,10 +22,24 @@ public:
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
+ static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>
+ default_mouse_buttons;
+ static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
+ static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
private:
void ReadValues();
+ void ReadPlayerValues();
+ void ReadDebugValues();
+ void ReadKeyboardValues();
+ void ReadMouseValues();
+ void ReadTouchscreenValues();
+
void SaveValues();
+ void SavePlayerValues();
+ void SaveDebugValues();
+ void SaveMouseValues();
+ void SaveTouchscreenValues();
std::unique_ptr<QSettings> qt_config;
std::string qt_config_loc;
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 207f9dfb3..8771421c0 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -16,15 +16,14 @@ class ConfigureAudio : public QWidget {
public:
explicit ConfigureAudio(QWidget* parent = nullptr);
- ~ConfigureAudio();
+ ~ConfigureAudio() override;
void applyConfiguration();
void retranslateUi();
-public slots:
+private:
void updateAudioDevices(int sink_index);
-private:
void setConfiguration();
void setOutputSinkFromSinkID();
void setAudioDeviceFromDeviceID();
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 9e765fc93..aa7de7b54 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -34,6 +34,8 @@ void ConfigureDebug::setConfiguration() {
ui->toggle_console->setChecked(UISettings::values.show_console);
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
+ ui->dump_exefs->setChecked(Settings::values.dump_exefs);
+ ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
}
void ConfigureDebug::applyConfiguration() {
@@ -42,6 +44,8 @@ void ConfigureDebug::applyConfiguration() {
UISettings::values.show_console = ui->toggle_console->isChecked();
Settings::values.log_filter = ui->log_filter_edit->text().toStdString();
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
+ Settings::values.dump_exefs = ui->dump_exefs->isChecked();
+ Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked();
Debugger::ToggleConsole();
Log::Filter filter;
filter.ParseFilterString(Settings::values.log_filter);
diff --git a/src/yuzu/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h
index d167eb996..c6420b18c 100644
--- a/src/yuzu/configuration/configure_debug.h
+++ b/src/yuzu/configuration/configure_debug.h
@@ -16,13 +16,12 @@ class ConfigureDebug : public QWidget {
public:
explicit ConfigureDebug(QWidget* parent = nullptr);
- ~ConfigureDebug();
+ ~ConfigureDebug() override;
void applyConfiguration();
private:
void setConfiguration();
-private:
std::unique_ptr<Ui::ConfigureDebug> ui;
};
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index ff4987604..758a92335 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
- <height>300</height>
+ <height>357</height>
</rect>
</property>
<property name="windowTitle">
@@ -130,6 +130,35 @@
</widget>
</item>
<item>
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="title">
+ <string>Dump</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QCheckBox" name="dump_decompressed_nso">
+ <property name="whatsThis">
+ <string>When checked, any NSO yuzu tries to load or patch will be copied decompressed to the yuzu/dump directory.</string>
+ </property>
+ <property name="text">
+ <string>Dump Decompressed NSOs</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="dump_exefs">
+ <property name="whatsThis">
+ <string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string>
+ </property>
+ <property name="text">
+ <string>Dump ExeFS</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index bbbdacc29..f6df7b827 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -18,13 +18,12 @@ class ConfigureDialog : public QDialog {
public:
explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry);
- ~ConfigureDialog();
+ ~ConfigureDialog() override;
void applyConfiguration();
private:
void setConfiguration();
-private:
std::unique_ptr<Ui::ConfigureDialog> ui;
};
diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp
index 8743ce982..ae8cac243 100644
--- a/src/yuzu/configuration/configure_gamelist.cpp
+++ b/src/yuzu/configuration/configure_gamelist.cpp
@@ -36,20 +36,36 @@ ConfigureGameList::ConfigureGameList(QWidget* parent)
InitializeRowComboBoxes();
this->setConfiguration();
+
+ // Force game list reload if any of the relevant settings are changed.
+ connect(ui->show_unknown, &QCheckBox::stateChanged, this,
+ &ConfigureGameList::RequestGameListUpdate);
+ connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
+ &ConfigureGameList::RequestGameListUpdate);
+ connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
+ &ConfigureGameList::RequestGameListUpdate);
+ connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
+ &ConfigureGameList::RequestGameListUpdate);
}
ConfigureGameList::~ConfigureGameList() = default;
void ConfigureGameList::applyConfiguration() {
UISettings::values.show_unknown = ui->show_unknown->isChecked();
+ UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
Settings::Apply();
}
+void ConfigureGameList::RequestGameListUpdate() {
+ UISettings::values.is_game_list_reload_pending.exchange(true);
+}
+
void ConfigureGameList::setConfiguration() {
ui->show_unknown->setChecked(UISettings::values.show_unknown);
+ ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
ui->icon_size_combobox->setCurrentIndex(
ui->icon_size_combobox->findData(UISettings::values.icon_size));
ui->row_1_text_combobox->setCurrentIndex(
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h
index ff7406c60..bf3f1cdfa 100644
--- a/src/yuzu/configuration/configure_gamelist.h
+++ b/src/yuzu/configuration/configure_gamelist.h
@@ -16,11 +16,13 @@ class ConfigureGameList : public QWidget {
public:
explicit ConfigureGameList(QWidget* parent = nullptr);
- ~ConfigureGameList();
+ ~ConfigureGameList() override;
void applyConfiguration();
private:
+ void RequestGameListUpdate();
+
void setConfiguration();
void changeEvent(QEvent*) override;
diff --git a/src/yuzu/configuration/configure_gamelist.ui b/src/yuzu/configuration/configure_gamelist.ui
index 7471fdb60..7a69377e7 100644
--- a/src/yuzu/configuration/configure_gamelist.ui
+++ b/src/yuzu/configuration/configure_gamelist.ui
@@ -1,126 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureGameList</class>
- <widget class="QWidget" name="ConfigureGeneral">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>300</width>
- <height>377</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
- <layout class="QHBoxLayout" name="HorizontalLayout">
- <item>
- <layout class="QVBoxLayout" name="VerticalLayout">
+ <widget class="QWidget" name="ConfigureGameList">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>300</width>
+ <height>377</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="HorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="VerticalLayout">
+ <item>
+ <widget class="QGroupBox" name="GeneralGroupBox">
+ <property name="title">
+ <string>General</string>
+ </property>
+ <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="GeneralVerticalLayout">
<item>
- <widget class="QGroupBox" name="GeneralGroupBox">
- <property name="title">
- <string>General</string>
- </property>
- <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
- <item>
- <layout class="QVBoxLayout" name="GeneralVerticalLayout">
- <item>
- <widget class="QCheckBox" name="show_unknown">
- <property name="text">
- <string>Show files with type 'Unknown'</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
+ <widget class="QCheckBox" name="show_unknown">
+ <property name="text">
+ <string>Show files with type 'Unknown'</string>
+ </property>
+ </widget>
</item>
<item>
- <widget class="QGroupBox" name="IconSizeGroupBox">
- <property name="title">
- <string>Icon Size</string>
- </property>
- <layout class="QHBoxLayout" name="icon_size_qhbox_layout">
- <item>
- <layout class="QVBoxLayout" name="icon_size_qvbox_layout">
- <item>
- <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
- <item>
- <widget class="QLabel" name="icon_size_label">
- <property name="text">
- <string>Icon Size:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="icon_size_combobox"/>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
+ <widget class="QCheckBox" name="show_add_ons">
+ <property name="text">
+ <string>Show Add-Ons Column</string>
+ </property>
+ </widget>
</item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="IconSizeGroupBox">
+ <property name="title">
+ <string>Icon Size</string>
+ </property>
+ <layout class="QHBoxLayout" name="icon_size_qhbox_layout">
+ <item>
+ <layout class="QVBoxLayout" name="icon_size_qvbox_layout">
<item>
- <widget class="QGroupBox" name="RowGroupBox">
- <property name="title">
- <string>Row Text</string>
+ <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
+ <item>
+ <widget class="QLabel" name="icon_size_label">
+ <property name="text">
+ <string>Icon Size:</string>
</property>
- <layout class="QHBoxLayout" name="RowHorizontalLayout">
- <item>
- <layout class="QVBoxLayout" name="RowVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="row_1_qhbox_layout">
- <item>
- <widget class="QLabel" name="row_1_label">
- <property name="text">
- <string>Row 1 Text:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="row_1_text_combobox"/>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="row_2_qhbox_layout">
- <item>
- <widget class="QLabel" name="row_2_label">
- <property name="text">
- <string>Row 2 Text:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="row_2_text_combobox"/>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="icon_size_combobox"/>
+ </item>
+ </layout>
</item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="RowGroupBox">
+ <property name="title">
+ <string>Row Text</string>
+ </property>
+ <layout class="QHBoxLayout" name="RowHorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="RowVerticalLayout">
<item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
+ <layout class="QHBoxLayout" name="row_1_qhbox_layout">
+ <item>
+ <widget class="QLabel" name="row_1_label">
+ <property name="text">
+ <string>Row 1 Text:</string>
</property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="row_1_text_combobox"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="row_2_qhbox_layout">
+ <item>
+ <widget class="QLabel" name="row_2_label">
+ <property name="text">
+ <string>Row 2 Text:</string>
</property>
- </spacer>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="row_2_text_combobox"/>
+ </item>
+ </layout>
</item>
- </layout>
- </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
- </widget>
+ </item>
+ </layout>
+ </widget>
<resources/>
<connections/>
</ui>
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index b322258a0..92a441308 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -3,10 +3,6 @@
// Refer to the license.txt file included.
#include "core/core.h"
-#include "core/hle/service/am/am.h"
-#include "core/hle/service/am/applet_ae.h"
-#include "core/hle/service/am/applet_oe.h"
-#include "core/hle/service/sm/sm.h"
#include "core/settings.h"
#include "ui_configure_general.h"
#include "yuzu/configuration/configure_general.h"
@@ -23,6 +19,9 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
this->setConfiguration();
+ connect(ui->toggle_deepscan, &QCheckBox::stateChanged, this,
+ [] { UISettings::values.is_game_list_reload_pending.exchange(true); });
+
ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
}
@@ -33,7 +32,6 @@ void ConfigureGeneral::setConfiguration() {
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
- ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
ui->enable_nfc->setChecked(Settings::values.enable_nfc);
}
@@ -41,30 +39,6 @@ void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
ui->widget->Populate(registry);
}
-void ConfigureGeneral::OnDockedModeChanged(bool last_state, bool new_state) {
- if (last_state == new_state) {
- return;
- }
-
- Core::System& system{Core::System::GetInstance()};
- Service::SM::ServiceManager& sm = system.ServiceManager();
-
- // Message queue is shared between these services, we just need to signal an operation
- // change to one and it will handle both automatically
- auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
- auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
- bool has_signalled = false;
-
- if (applet_oe != nullptr) {
- applet_oe->GetMessageQueue()->OperationModeChanged();
- has_signalled = true;
- }
-
- if (applet_ae != nullptr && !has_signalled) {
- applet_ae->GetMessageQueue()->OperationModeChanged();
- }
-}
-
void ConfigureGeneral::applyConfiguration() {
UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
@@ -72,9 +46,5 @@ void ConfigureGeneral::applyConfiguration() {
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
- const bool pre_docked_mode = Settings::values.use_docked_mode;
- Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
- OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
-
Settings::values.enable_nfc = ui->enable_nfc->isChecked();
}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 2210d48da..59738af40 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -18,14 +18,13 @@ class ConfigureGeneral : public QWidget {
public:
explicit ConfigureGeneral(QWidget* parent = nullptr);
- ~ConfigureGeneral();
+ ~ConfigureGeneral() override;
void PopulateHotkeyList(const HotkeyRegistry& registry);
void applyConfiguration();
private:
void setConfiguration();
- void OnDockedModeChanged(bool last_state, bool new_state);
std::unique_ptr<Ui::ConfigureGeneral> ui;
};
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index b82fffde8..bf37446c6 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>300</width>
- <height>377</height>
+ <height>407</height>
</rect>
</property>
<property name="windowTitle">
@@ -72,13 +72,6 @@
<item>
<layout class="QVBoxLayout" name="EmulationVerticalLayout">
<item>
- <widget class="QCheckBox" name="use_docked_mode">
- <property name="text">
- <string>Enable docked mode</string>
- </property>
- </widget>
- </item>
- <item>
<widget class="QCheckBox" name="enable_nfc">
<property name="text">
<string>Enable NFC</string>
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 9bda26fd6..d6ffc6fde 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -16,14 +16,13 @@ class ConfigureGraphics : public QWidget {
public:
explicit ConfigureGraphics(QWidget* parent = nullptr);
- ~ConfigureGraphics();
+ ~ConfigureGraphics() override;
void applyConfiguration();
private:
void setConfiguration();
-private:
std::unique_ptr<Ui::ConfigureGraphics> ui;
QColor bg_color;
};
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 91fcad994..e278cdd05 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -23,31 +23,31 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QCheckBox" name="toggle_frame_limit">
- <property name="text">
- <string>Limit Speed Percent</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="frame_limit">
- <property name="suffix">
- <string>%</string>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>9999</number>
- </property>
- <property name="value">
- <number>100</number>
- </property>
- </widget>
- </item>
- </layout>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="toggle_frame_limit">
+ <property name="text">
+ <string>Limit Speed Percent</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="frame_limit">
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>9999</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
<item>
<widget class="QCheckBox" name="use_accurate_gpu_emulation">
@@ -61,7 +61,7 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
- <string>Internal Resolution:(Currently does nothing.)</string>
+ <string>Internal Resolution</string>
</property>
</widget>
</item>
@@ -96,27 +96,27 @@
</item>
</layout>
</item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_6">
- <item>
- <widget class="QLabel" name="bg_label">
- <property name="text">
- <string>Background Color:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="bg_button">
- <property name="maximumSize">
- <size>
- <width>40</width>
- <height>16777215</height>
- </size>
- </property>
- </widget>
- </item>
- </layout>
- </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QLabel" name="bg_label">
+ <property name="text">
+ <string>Background Color:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="bg_button">
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
</layout>
</widget>
</item>
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 42a7beac6..830d26115 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -4,339 +4,209 @@
#include <algorithm>
#include <memory>
-#include <utility>
-#include <QMenu>
-#include <QMessageBox>
+
#include <QTimer>
-#include "common/param_package.h"
-#include "input_common/main.h"
-#include "yuzu/configuration/config.h"
+
+#include "configuration/configure_touchscreen_advanced.h"
+#include "core/core.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applet_ae.h"
+#include "core/hle/service/am/applet_oe.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/sm/sm.h"
+#include "ui_configure_input.h"
+#include "ui_configure_input_player.h"
#include "yuzu/configuration/configure_input.h"
+#include "yuzu/configuration/configure_input_player.h"
+#include "yuzu/configuration/configure_mouse_advanced.h"
-const std::array<std::string, ConfigureInput::ANALOG_SUB_BUTTONS_NUM>
- ConfigureInput::analog_sub_buttons{{
- "up",
- "down",
- "left",
- "right",
- "modifier",
- }};
-
-static QString getKeyName(int key_code) {
- switch (key_code) {
- case Qt::Key_Shift:
- return QObject::tr("Shift");
- case Qt::Key_Control:
- return QObject::tr("Ctrl");
- case Qt::Key_Alt:
- return QObject::tr("Alt");
- case Qt::Key_Meta:
- return "";
- default:
- return QKeySequence(key_code).toString();
- }
-}
+namespace {
+template <typename Dialog, typename... Args>
+void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
+ parent.applyConfiguration();
+ Dialog dialog(&parent, std::forward<Args>(args)...);
-static void SetAnalogButton(const Common::ParamPackage& input_param,
- Common::ParamPackage& analog_param, const std::string& button_name) {
- if (analog_param.Get("engine", "") != "analog_from_button") {
- analog_param = {
- {"engine", "analog_from_button"},
- {"modifier_scale", "0.5"},
- };
+ const auto res = dialog.exec();
+ if (res == QDialog::Accepted) {
+ dialog.applyConfiguration();
}
- analog_param.Set(button_name, input_param.Serialize());
}
-
-static QString ButtonToText(const Common::ParamPackage& param) {
- if (!param.Has("engine")) {
- return QObject::tr("[not set]");
- } else if (param.Get("engine", "") == "keyboard") {
- return getKeyName(param.Get("code", 0));
- } else if (param.Get("engine", "") == "sdl") {
- if (param.Has("hat")) {
- return QString(QObject::tr("Hat %1 %2"))
- .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
- }
- if (param.Has("axis")) {
- return QString(QObject::tr("Axis %1%2"))
- .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
- }
- if (param.Has("button")) {
- return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
- }
- return QString();
- } else {
- return QObject::tr("[unknown]");
- }
-};
-
-static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
- if (!param.Has("engine")) {
- return QObject::tr("[not set]");
- } else if (param.Get("engine", "") == "analog_from_button") {
- return ButtonToText(Common::ParamPackage{param.Get(dir, "")});
- } else if (param.Get("engine", "") == "sdl") {
- if (dir == "modifier") {
- return QString(QObject::tr("[unused]"));
- }
-
- if (dir == "left" || dir == "right") {
- return QString(QObject::tr("Axis %1")).arg(param.Get("axis_x", "").c_str());
- } else if (dir == "up" || dir == "down") {
- return QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str());
- }
- return QString();
- } else {
- return QObject::tr("[unknown]");
- }
-};
+} // Anonymous namespace
ConfigureInput::ConfigureInput(QWidget* parent)
- : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
- timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
-
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
ui->setupUi(this);
- setFocusPolicy(Qt::ClickFocus);
-
- button_map = {
- ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
- ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
- ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
- ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
- ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown,
- ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown,
- ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
+
+ players_controller = {
+ ui->player1_combobox, ui->player2_combobox, ui->player3_combobox, ui->player4_combobox,
+ ui->player5_combobox, ui->player6_combobox, ui->player7_combobox, ui->player8_combobox,
};
- analog_map_buttons = {{
- {
- ui->buttonLStickUp,
- ui->buttonLStickDown,
- ui->buttonLStickLeft,
- ui->buttonLStickRight,
- ui->buttonLStickMod,
- },
- {
- ui->buttonRStickUp,
- ui->buttonRStickDown,
- ui->buttonRStickLeft,
- ui->buttonRStickRight,
- ui->buttonRStickMod,
- },
- }};
-
- analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
-
- for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
- if (!button_map[button_id])
- continue;
- button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(button_map[button_id], &QPushButton::released, [=]() {
- handleClick(
- button_map[button_id],
- [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
- InputCommon::Polling::DeviceType::Button);
- });
- connect(button_map[button_id], &QPushButton::customContextMenuRequested,
- [=](const QPoint& menu_location) {
- QMenu context_menu;
- context_menu.addAction(tr("Clear"), [&] {
- buttons_param[button_id].Clear();
- button_map[button_id]->setText(tr("[not set]"));
- });
- context_menu.addAction(tr("Restore Default"), [&] {
- buttons_param[button_id] = Common::ParamPackage{
- InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
- button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
- });
- context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
- });
- }
+ players_configure = {
+ ui->player1_configure, ui->player2_configure, ui->player3_configure, ui->player4_configure,
+ ui->player5_configure, ui->player6_configure, ui->player7_configure, ui->player8_configure,
+ };
- for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
- for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
- if (!analog_map_buttons[analog_id][sub_button_id])
- continue;
- analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
- Qt::CustomContextMenu);
- connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() {
- handleClick(analog_map_buttons[analog_id][sub_button_id],
- [=](const Common::ParamPackage& params) {
- SetAnalogButton(params, analogs_param[analog_id],
- analog_sub_buttons[sub_button_id]);
- },
- InputCommon::Polling::DeviceType::Button);
- });
- connect(analog_map_buttons[analog_id][sub_button_id],
- &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
- QMenu context_menu;
- context_menu.addAction(tr("Clear"), [&] {
- analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
- analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
- });
- context_menu.addAction(tr("Restore Default"), [&] {
- Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
- Config::default_analogs[analog_id][sub_button_id])};
- SetAnalogButton(params, analogs_param[analog_id],
- analog_sub_buttons[sub_button_id]);
- analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
- analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
- });
- context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
- menu_location));
- });
- }
- connect(analog_map_stick[analog_id], &QPushButton::released, [=]() {
- QMessageBox::information(this, tr("Information"),
- tr("After pressing OK, first move your joystick horizontally, "
- "and then vertically."));
- handleClick(
- analog_map_stick[analog_id],
- [=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; },
- InputCommon::Polling::DeviceType::Analog);
- });
+ for (auto* controller_box : players_controller) {
+ controller_box->addItems({"None", "Pro Controller", "Dual Joycons", "Single Right Joycon",
+ "Single Left Joycon"});
}
- connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
- connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
+ this->loadConfiguration();
+ updateUIEnabled();
- timeout_timer->setSingleShot(true);
- connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
+ connect(ui->restore_defaults_button, &QPushButton::pressed, this,
+ &ConfigureInput::restoreDefaults);
- connect(poll_timer.get(), &QTimer::timeout, [this]() {
- Common::ParamPackage params;
- for (auto& poller : device_pollers) {
- params = poller->GetNextInput();
- if (params.Has("engine")) {
- setPollingResult(params, false);
- return;
- }
- }
- });
+ for (auto* enabled : players_controller)
+ connect(enabled, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
+ &ConfigureInput::updateUIEnabled);
+ connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
+ connect(ui->handheld_connected, &QCheckBox::stateChanged, this,
+ &ConfigureInput::updateUIEnabled);
+ connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
+ connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
+ connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
+ connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
+ &ConfigureInput::updateUIEnabled);
- this->loadConfiguration();
+ for (std::size_t i = 0; i < players_configure.size(); ++i) {
+ connect(players_configure[i], &QPushButton::pressed, this,
+ [this, i] { CallConfigureDialog<ConfigureInputPlayer>(*this, i, false); });
+ }
- // TODO(wwylele): enable this when we actually emulate it
- ui->buttonHome->setEnabled(false);
-}
+ connect(ui->handheld_configure, &QPushButton::pressed, this,
+ [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 8, false); });
-void ConfigureInput::applyConfiguration() {
- std::transform(buttons_param.begin(), buttons_param.end(), Settings::values.buttons.begin(),
- [](const Common::ParamPackage& param) { return param.Serialize(); });
- std::transform(analogs_param.begin(), analogs_param.end(), Settings::values.analogs.begin(),
- [](const Common::ParamPackage& param) { return param.Serialize(); });
-}
+ connect(ui->debug_configure, &QPushButton::pressed, this,
+ [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 9, true); });
-void ConfigureInput::loadConfiguration() {
- std::transform(Settings::values.buttons.begin(), Settings::values.buttons.end(),
- buttons_param.begin(),
- [](const std::string& str) { return Common::ParamPackage(str); });
- std::transform(Settings::values.analogs.begin(), Settings::values.analogs.end(),
- analogs_param.begin(),
- [](const std::string& str) { return Common::ParamPackage(str); });
- updateButtonLabels();
+ connect(ui->mouse_advanced, &QPushButton::pressed, this,
+ [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); });
+
+ connect(ui->touchscreen_advanced, &QPushButton::pressed, this,
+ [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
}
-void ConfigureInput::restoreDefaults() {
- for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
- buttons_param[button_id] = Common::ParamPackage{
- InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
- }
+ConfigureInput::~ConfigureInput() = default;
- for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
- for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
- Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
- Config::default_analogs[analog_id][sub_button_id])};
- SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
- }
+void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) {
+ if (ui->use_docked_mode->isChecked() && ui->handheld_connected->isChecked()) {
+ ui->handheld_connected->setChecked(false);
}
- updateButtonLabels();
-}
-void ConfigureInput::ClearAll() {
- for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
- if (button_map[button_id] && button_map[button_id]->isEnabled())
- buttons_param[button_id].Clear();
+ if (last_state == new_state) {
+ return;
}
- for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
- for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
- if (analog_map_buttons[analog_id][sub_button_id] &&
- analog_map_buttons[analog_id][sub_button_id]->isEnabled())
- analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
- }
+
+ Core::System& system{Core::System::GetInstance()};
+ if (!system.IsPoweredOn()) {
+ return;
}
- updateButtonLabels();
-}
+ Service::SM::ServiceManager& sm = system.ServiceManager();
-void ConfigureInput::updateButtonLabels() {
- for (int button = 0; button < Settings::NativeButton::NumButtons; button++) {
- button_map[button]->setText(ButtonToText(buttons_param[button]));
+ // Message queue is shared between these services, we just need to signal an operation
+ // change to one and it will handle both automatically
+ auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
+ auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
+ bool has_signalled = false;
+
+ if (applet_oe != nullptr) {
+ applet_oe->GetMessageQueue()->OperationModeChanged();
+ has_signalled = true;
}
- for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
- for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
- if (analog_map_buttons[analog_id][sub_button_id]) {
- analog_map_buttons[analog_id][sub_button_id]->setText(
- AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
- }
- }
- analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
+ if (applet_ae != nullptr && !has_signalled) {
+ applet_ae->GetMessageQueue()->OperationModeChanged();
}
}
-void ConfigureInput::handleClick(QPushButton* button,
- std::function<void(const Common::ParamPackage&)> new_input_setter,
- InputCommon::Polling::DeviceType type) {
- button->setText(tr("[press key]"));
- button->setFocus();
-
- input_setter = new_input_setter;
-
- device_pollers = InputCommon::Polling::GetPollers(type);
+void ConfigureInput::applyConfiguration() {
+ for (std::size_t i = 0; i < players_controller.size(); ++i) {
+ const auto controller_type_index = players_controller[i]->currentIndex();
- // Keyboard keys can only be used as button devices
- want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
+ Settings::values.players[i].connected = controller_type_index != 0;
- for (auto& poller : device_pollers) {
- poller->Start();
+ if (controller_type_index > 0) {
+ Settings::values.players[i].type =
+ static_cast<Settings::ControllerType>(controller_type_index - 1);
+ } else {
+ Settings::values.players[i].type = Settings::ControllerType::DualJoycon;
+ }
}
- grabKeyboard();
- grabMouse();
- timeout_timer->start(5000); // Cancel after 5 seconds
- poll_timer->start(200); // Check for new inputs every 200ms
+ const bool pre_docked_mode = Settings::values.use_docked_mode;
+ Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
+ OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
+ Settings::values
+ .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
+ .connected = ui->handheld_connected->isChecked();
+ Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
+ Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
+ Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
+ Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
}
-void ConfigureInput::setPollingResult(const Common::ParamPackage& params, bool abort) {
- releaseKeyboard();
- releaseMouse();
- timeout_timer->stop();
- poll_timer->stop();
- for (auto& poller : device_pollers) {
- poller->Stop();
+void ConfigureInput::updateUIEnabled() {
+ bool hit_disabled = false;
+ for (auto* player : players_controller) {
+ player->setDisabled(hit_disabled);
+ if (hit_disabled)
+ player->setCurrentIndex(0);
+ if (!hit_disabled && player->currentIndex() == 0)
+ hit_disabled = true;
}
- if (!abort) {
- (*input_setter)(params);
+ for (std::size_t i = 0; i < players_controller.size(); ++i) {
+ players_configure[i]->setEnabled(players_controller[i]->currentIndex() != 0);
}
- updateButtonLabels();
- input_setter = {};
+ ui->handheld_connected->setEnabled(!ui->use_docked_mode->isChecked());
+ ui->handheld_configure->setEnabled(ui->handheld_connected->isChecked() &&
+ !ui->use_docked_mode->isChecked());
+ ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
+ ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
+ ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
}
-void ConfigureInput::keyPressEvent(QKeyEvent* event) {
- if (!input_setter || !event)
- return;
+void ConfigureInput::loadConfiguration() {
+ std::stable_partition(
+ Settings::values.players.begin(),
+ Settings::values.players.begin() +
+ Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
+ [](const auto& player) { return player.connected; });
+
+ for (std::size_t i = 0; i < players_controller.size(); ++i) {
+ const auto connected = Settings::values.players[i].connected;
+ players_controller[i]->setCurrentIndex(
+ connected ? static_cast<u8>(Settings::values.players[i].type) + 1 : 0);
+ }
+
+ ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
+ ui->handheld_connected->setChecked(
+ Settings::values
+ .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
+ .connected);
+ ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
+ ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
+ ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
+ ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
+
+ updateUIEnabled();
+}
- if (event->key() != Qt::Key_Escape) {
- if (want_keyboard_keys) {
- setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
- false);
- } else {
- // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
- return;
- }
+void ConfigureInput::restoreDefaults() {
+ players_controller[0]->setCurrentIndex(2);
+
+ for (std::size_t i = 1; i < players_controller.size(); ++i) {
+ players_controller[i]->setCurrentIndex(0);
}
- setPollingResult({}, true);
+
+ ui->use_docked_mode->setCheckState(Qt::Unchecked);
+ ui->handheld_connected->setCheckState(Qt::Unchecked);
+ ui->mouse_enabled->setCheckState(Qt::Unchecked);
+ ui->keyboard_enabled->setCheckState(Qt::Unchecked);
+ ui->debug_enabled->setCheckState(Qt::Unchecked);
+ ui->touchscreen_enabled->setCheckState(Qt::Checked);
+ updateUIEnabled();
}
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index 32c7183f9..1649e4c0b 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -5,18 +5,11 @@
#pragma once
#include <array>
-#include <functional>
#include <memory>
-#include <optional>
-#include <string>
-#include <unordered_map>
#include <QKeyEvent>
#include <QWidget>
-#include "common/param_package.h"
-#include "core/settings.h"
-#include "input_common/main.h"
#include "ui_configure_input.h"
class QPushButton;
@@ -32,62 +25,23 @@ class ConfigureInput : public QWidget {
public:
explicit ConfigureInput(QWidget* parent = nullptr);
+ ~ConfigureInput() override;
/// Save all button configurations to settings file
void applyConfiguration();
private:
- std::unique_ptr<Ui::ConfigureInput> ui;
-
- std::unique_ptr<QTimer> timeout_timer;
- std::unique_ptr<QTimer> poll_timer;
-
- /// This will be the the setting function when an input is awaiting configuration.
- std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
-
- std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
- std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
-
- static constexpr int ANALOG_SUB_BUTTONS_NUM = 5;
-
- /// Each button input is represented by a QPushButton.
- std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
-
- /// A group of five QPushButtons represent one analog input. The buttons each represent up,
- /// down, left, right, and modifier, respectively.
- std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
- analog_map_buttons;
+ void updateUIEnabled();
- /// Analog inputs are also represented each with a single button, used to configure with an
- /// actual analog stick
- std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick;
-
- static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
-
- std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
-
- /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
- /// keyboard events are ignored.
- bool want_keyboard_keys = false;
+ void OnDockedModeChanged(bool last_state, bool new_state);
/// Load configuration settings.
void loadConfiguration();
/// Restore all buttons to their default values.
void restoreDefaults();
- /// Clear all input configuration
- void ClearAll();
- /// Update UI to reflect current configuration.
- void updateButtonLabels();
-
- /// Called when the button was pressed.
- void handleClick(QPushButton* button,
- std::function<void(const Common::ParamPackage&)> new_input_setter,
- InputCommon::Polling::DeviceType type);
-
- /// Finish polling and configure input using the input_setter
- void setPollingResult(const Common::ParamPackage& params, bool abort);
+ std::unique_ptr<Ui::ConfigureInput> ui;
- /// Handle key press events.
- void keyPressEvent(QKeyEvent* event) override;
+ std::array<QComboBox*, 8> players_controller;
+ std::array<QPushButton*, 8> players_configure;
};
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index 8a019a693..dae8277bc 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>343</width>
- <height>677</height>
+ <width>473</width>
+ <height>685</height>
</rect>
</property>
<property name="windowTitle">
@@ -15,740 +15,470 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
- <layout class="QGridLayout" name="buttons">
- <item row="3" column="1">
- <widget class="QGroupBox" name="misc">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="gridGroupBox">
<property name="title">
- <string>Misc.</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
+ <string>Players</string>
</property>
- <layout class="QGridLayout" name="gridLayout_6">
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonMiscMinusVerticalLayout">
- <item>
- <widget class="QLabel" name="labelMinus">
- <property name="text">
- <string>Minus:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonMinus">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="2">
+ <widget class="QComboBox" name="player1_combobox">
+ <property name="minimumSize">
+ <size>
+ <width>110</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
</item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonMiscPlusVerticalLayout">
- <item>
- <widget class="QLabel" name="labelPlus">
- <property name="text">
- <string>Plus:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonPlus">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="1" column="3">
+ <widget class="QPushButton" name="player1_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
</item>
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonMiscHomeVerticalLayout">
- <item>
- <widget class="QLabel" name="labelHome">
- <property name="text">
- <string>Home:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonHome">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="0" column="2">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Controller Type</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
</item>
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonMiscScrCapVerticalLayout">
- <item>
- <widget class="QLabel" name="labelScrCap">
- <property name="text">
- <string>Screen
-Capture:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonScreenshot">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="2" column="2">
+ <widget class="QComboBox" name="player2_combobox">
+ <property name="minimumSize">
+ <size>
+ <width>110</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
</item>
- <item row="2" column="1">
- <spacer name="verticalSpacer">
+ <item row="3" column="2">
+ <widget class="QComboBox" name="player3_combobox">
+ <property name="minimumSize">
+ <size>
+ <width>110</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
+ <widget class="QComboBox" name="player4_combobox">
+ <property name="minimumSize">
+ <size>
+ <width>110</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="2">
+ <widget class="QComboBox" name="player5_combobox">
+ <property name="minimumSize">
+ <size>
+ <width>110</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="2">
+ <widget class="QComboBox" name="player6_combobox">
+ <property name="minimumSize">
+ <size>
+ <width>110</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="2">
+ <widget class="QComboBox" name="player7_combobox">
+ <property name="minimumSize">
+ <size>
+ <width>110</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="2">
+ <widget class="QComboBox" name="player8_combobox">
+ <property name="minimumSize">
+ <size>
+ <width>110</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QPushButton" name="player2_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3">
+ <widget class="QPushButton" name="player3_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3">
+ <widget class="QPushButton" name="player4_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="3">
+ <widget class="QPushButton" name="player5_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="3">
+ <widget class="QPushButton" name="player6_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="3">
+ <widget class="QPushButton" name="player7_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="3">
+ <widget class="QPushButton" name="player8_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <spacer name="horizontalSpacer">
<property name="orientation">
- <enum>Qt::Vertical</enum>
+ <enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>20</width>
- <height>40</height>
+ <width>40</width>
+ <height>20</height>
</size>
</property>
</spacer>
</item>
- </layout>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QGroupBox" name="faceButtons">
- <property name="title">
- <string>Face Buttons</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonFaceButtonsAVerticalLayout">
- <item>
- <widget class="QLabel" name="labelA">
- <property name="text">
- <string>A:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonA">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="0" column="4">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
</item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonFaceButtonsBVerticalLayout">
- <item>
- <widget class="QLabel" name="labelB">
- <property name="text">
- <string>B:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonB">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="1" column="1">
+ <widget class="QLabel" name="label_3">
+ <property name="minimumSize">
+ <size>
+ <width>55</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Player 1</string>
+ </property>
+ </widget>
</item>
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonFaceButtonsXVerticalLayout">
- <item>
- <widget class="QLabel" name="labelX">
- <property name="text">
- <string>X:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonX">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="2" column="1">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Player 2</string>
+ </property>
+ </widget>
</item>
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonFaceButtonsYVerticalLayout">
- <item>
- <widget class="QLabel" name="labelY">
- <property name="text">
- <string>Y:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonY">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="3" column="1">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Player 3</string>
+ </property>
+ </widget>
</item>
- </layout>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QGroupBox" name="Dpad">
- <property name="title">
- <string>Directional Pad</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonDpadUpVerticalLayout">
- <item>
- <widget class="QLabel" name="labelDpadUp">
- <property name="text">
- <string>Up:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonDpadUp">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="4" column="1">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Player 4</string>
+ </property>
+ </widget>
</item>
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonDpadDownVerticalLayout">
- <item>
- <widget class="QLabel" name="labelDpadDown">
- <property name="text">
- <string>Down:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonDpadDown">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="5" column="1">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Player 5</string>
+ </property>
+ </widget>
</item>
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout">
- <item>
- <widget class="QLabel" name="labelDpadLeft">
- <property name="text">
- <string>Left:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonDpadLeft">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="6" column="1">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>Player 6</string>
+ </property>
+ </widget>
</item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout">
- <item>
- <widget class="QLabel" name="labelDpadRight">
- <property name="text">
- <string>Right:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonDpadRight">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="7" column="1">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Player 7</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="1">
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>Player 8</string>
+ </property>
+ </widget>
</item>
</layout>
</widget>
</item>
- <item row="3" column="0">
- <widget class="QGroupBox" name="shoulderButtons">
+ <item>
+ <widget class="QGroupBox" name="gridGroupBox">
<property name="title">
- <string>Shoulder Buttons</string>
- </property>
- <property name="flat">
- <bool>false</bool>
+ <string>Handheld</string>
</property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsLVerticalLayout">
- <item>
- <widget class="QLabel" name="labelL">
- <property name="text">
- <string>L:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonL">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="1" column="2">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>72</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
</item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsRVerticalLayout">
- <item>
- <widget class="QLabel" name="labelR">
- <property name="text">
- <string>R:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonR">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="1" column="4">
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="3">
+ <widget class="QPushButton" name="handheld_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
</item>
<item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsZLVerticalLayout">
- <item>
- <widget class="QLabel" name="labelZL">
- <property name="text">
- <string>ZL:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonZL">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
</item>
<item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsZRVerticalLayout">
- <item>
- <widget class="QLabel" name="labelZR">
- <property name="text">
- <string>ZR:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonZR">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="2" column="0">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
- <item>
- <widget class="QLabel" name="labelSL">
- <property name="text">
- <string>SL:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonSL">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <widget class="QCheckBox" name="handheld_connected">
+ <property name="text">
+ <string>Joycons Docked</string>
+ </property>
+ </widget>
</item>
- <item row="2" column="1">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
- <item>
- <widget class="QLabel" name="labelSR">
- <property name="text">
- <string>SR:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonSR">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="use_docked_mode">
+ <property name="text">
+ <string>Use Docked Mode</string>
+ </property>
+ </widget>
</item>
</layout>
</widget>
</item>
- <item row="1" column="1">
- <widget class="QGroupBox" name="RStick">
+ <item>
+ <widget class="QGroupBox" name="gridGroupBox">
<property name="title">
- <string>Right Stick</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
- </property>
- <property name="flat">
- <bool>false</bool>
+ <string>Other</string>
</property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_5">
+ <layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonRStickDownVerticalLayout">
- <item>
- <widget class="QLabel" name="labelRStickDown">
- <property name="text">
- <string>Down:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickDown">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonRStickRightVerticalLayout">
- <item>
- <widget class="QLabel" name="labelRStickRight">
- <property name="text">
- <string>Right:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickRight">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="0" colspan="2">
- <widget class="QPushButton" name="buttonRStickAnalog">
+ <widget class="QCheckBox" name="keyboard_enabled">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
<property name="text">
- <string>Set Analog Stick</string>
+ <string>Keyboard</string>
</property>
</widget>
</item>
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonRStickLeftVerticalLayout">
- <item>
- <widget class="QLabel" name="labelRStickLeft">
- <property name="text">
- <string>Left:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickLeft">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonRStickUpVerticalLayout">
- <item>
- <widget class="QLabel" name="labelRStickUp">
- <property name="text">
- <string>Up:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickUp">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="2" column="0">
- <layout class="QVBoxLayout" name="buttonRStickPressedVerticalLayout">
- <item>
- <widget class="QLabel" name="labelRStickPressed">
- <property name="text">
- <string>Pressed:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStick">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
<item row="2" column="1">
- <layout class="QVBoxLayout" name="buttonRStickModVerticalLayout">
- <item>
- <widget class="QLabel" name="labelRStickMod">
- <property name="text">
- <string>Modifier:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickMod">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <widget class="QCheckBox" name="debug_enabled">
+ <property name="text">
+ <string>Debug Controller</string>
+ </property>
+ </widget>
</item>
- </layout>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QGroupBox" name="LStick">
- <property name="title">
- <string>Left Stick</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_4">
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonLStickDownVerticalLayout">
- <item>
- <widget class="QLabel" name="labelLStickDown">
- <property name="text">
- <string>Down:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickDown">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="4" column="0" colspan="2">
- <widget class="QPushButton" name="buttonLStickAnalog">
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="touchscreen_enabled">
<property name="text">
- <string>Set Analog Stick</string>
+ <string>Touchscreen</string>
</property>
</widget>
</item>
<item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonLStickRightVerticalLayout">
- <item>
- <widget class="QLabel" name="labelLStickRight">
- <property name="text">
- <string>Right:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickRight">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <widget class="QCheckBox" name="mouse_enabled">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Mouse</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <spacer name="horizontalSpacer_7">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>76</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
</item>
<item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonLStickLeftVerticalLayout">
- <item>
- <widget class="QLabel" name="labelLStickLeft">
- <property name="text">
- <string>Left:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickLeft">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <spacer name="horizontalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
</item>
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonLStickUpVerticalLayout">
- <item>
- <widget class="QLabel" name="labelLStickUp">
- <property name="text">
- <string>Up:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickUp">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="0">
- <layout class="QVBoxLayout" name="buttonLStickModVerticalLayout">
- <item>
- <widget class="QLabel" name="labelLStickMod">
- <property name="text">
- <string>Modifier:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickMod">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="3" column="3">
+ <widget class="QPushButton" name="touchscreen_advanced">
+ <property name="text">
+ <string>Advanced</string>
+ </property>
+ </widget>
</item>
- <item row="3" column="1">
- <layout class="QVBoxLayout" name="buttonLStickPressedVerticalLayout" stretch="0,0">
- <item>
- <widget class="QLabel" name="labelLStickPressed">
- <property name="text">
- <string>Pressed:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStick">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item row="2" column="3">
+ <widget class="QPushButton" name="debug_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QPushButton" name="mouse_advanced">
+ <property name="text">
+ <string>Advanced</string>
+ </property>
+ </widget>
</item>
</layout>
</widget>
</item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <spacer name="horizontalSpacer">
+ <spacer name="verticalSpacer">
<property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>40</width>
- <height>20</height>
+ <width>20</width>
+ <height>40</height>
</size>
</property>
</spacer>
</item>
<item>
- <widget class="QPushButton" name="buttonClearAll">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="sizeIncrement">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="baseSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="layoutDirection">
- <enum>Qt::LeftToRight</enum>
- </property>
- <property name="text">
- <string>Clear All</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRestoreDefaults">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="sizeIncrement">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="baseSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="layoutDirection">
- <enum>Qt::LeftToRight</enum>
- </property>
- <property name="text">
- <string>Restore Defaults</string>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="restore_defaults_button">
+ <property name="text">
+ <string>Restore Defaults</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
</layout>
</item>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
new file mode 100644
index 000000000..7dadd83c1
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -0,0 +1,500 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <QColorDialog>
+#include <QMenu>
+#include <QMessageBox>
+#include <QTimer>
+#include "common/assert.h"
+#include "common/param_package.h"
+#include "input_common/main.h"
+#include "ui_configure_input_player.h"
+#include "yuzu/configuration/config.h"
+#include "yuzu/configuration/configure_input_player.h"
+
+const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM>
+ ConfigureInputPlayer::analog_sub_buttons{{
+ "up",
+ "down",
+ "left",
+ "right",
+ "modifier",
+ }};
+
+static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) {
+ const int index1 = grid->indexOf(item);
+ const int index2 = grid->indexOf(onTopOf);
+ int row, column, rowSpan, columnSpan;
+ grid->getItemPosition(index2, &row, &column, &rowSpan, &columnSpan);
+ grid->takeAt(index1);
+ grid->addWidget(item, row, column, rowSpan, columnSpan);
+}
+
+static QString GetKeyName(int key_code) {
+ switch (key_code) {
+ case Qt::Key_Shift:
+ return QObject::tr("Shift");
+ case Qt::Key_Control:
+ return QObject::tr("Ctrl");
+ case Qt::Key_Alt:
+ return QObject::tr("Alt");
+ case Qt::Key_Meta:
+ return "";
+ default:
+ return QKeySequence(key_code).toString();
+ }
+}
+
+static void SetAnalogButton(const Common::ParamPackage& input_param,
+ Common::ParamPackage& analog_param, const std::string& button_name) {
+ if (analog_param.Get("engine", "") != "analog_from_button") {
+ analog_param = {
+ {"engine", "analog_from_button"},
+ {"modifier_scale", "0.5"},
+ };
+ }
+ analog_param.Set(button_name, input_param.Serialize());
+}
+
+static QString ButtonToText(const Common::ParamPackage& param) {
+ if (!param.Has("engine")) {
+ return QObject::tr("[not set]");
+ } else if (param.Get("engine", "") == "keyboard") {
+ return GetKeyName(param.Get("code", 0));
+ } else if (param.Get("engine", "") == "sdl") {
+ if (param.Has("hat")) {
+ return QString(QObject::tr("Hat %1 %2"))
+ .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
+ }
+ if (param.Has("axis")) {
+ return QString(QObject::tr("Axis %1%2"))
+ .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
+ }
+ if (param.Has("button")) {
+ return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
+ }
+ return QString();
+ } else {
+ return QObject::tr("[unknown]");
+ }
+};
+
+static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
+ if (!param.Has("engine")) {
+ return QObject::tr("[not set]");
+ } else if (param.Get("engine", "") == "analog_from_button") {
+ return ButtonToText(Common::ParamPackage{param.Get(dir, "")});
+ } else if (param.Get("engine", "") == "sdl") {
+ if (dir == "modifier") {
+ return QString(QObject::tr("[unused]"));
+ }
+
+ if (dir == "left" || dir == "right") {
+ return QString(QObject::tr("Axis %1")).arg(param.Get("axis_x", "").c_str());
+ } else if (dir == "up" || dir == "down") {
+ return QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str());
+ }
+ return QString();
+ } else {
+ return QObject::tr("[unknown]");
+ }
+};
+
+ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
+ debug(debug), timeout_timer(std::make_unique<QTimer>()),
+ poll_timer(std::make_unique<QTimer>()) {
+ ui->setupUi(this);
+ setFocusPolicy(Qt::ClickFocus);
+
+ button_map = {
+ ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
+ ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
+ ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
+ ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
+ ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown,
+ ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown,
+ ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
+ };
+
+ analog_map_buttons = {{
+ {
+ ui->buttonLStickUp,
+ ui->buttonLStickDown,
+ ui->buttonLStickLeft,
+ ui->buttonLStickRight,
+ ui->buttonLStickMod,
+ },
+ {
+ ui->buttonRStickUp,
+ ui->buttonRStickDown,
+ ui->buttonRStickLeft,
+ ui->buttonRStickRight,
+ ui->buttonRStickMod,
+ },
+ }};
+
+ debug_hidden = {
+ ui->buttonSL, ui->labelSL,
+ ui->buttonSR, ui->labelSR,
+ ui->buttonLStick, ui->labelLStickPressed,
+ ui->buttonRStick, ui->labelRStickPressed,
+ ui->buttonHome, ui->labelHome,
+ ui->buttonScreenshot, ui->labelScreenshot,
+ };
+
+ auto layout = Settings::values.players[player_index].type;
+ if (debug)
+ layout = Settings::ControllerType::DualJoycon;
+
+ switch (layout) {
+ case Settings::ControllerType::ProController:
+ case Settings::ControllerType::DualJoycon:
+ layout_hidden = {
+ ui->buttonSL,
+ ui->labelSL,
+ ui->buttonSR,
+ ui->labelSR,
+ };
+ break;
+ case Settings::ControllerType::LeftJoycon:
+ layout_hidden = {
+ ui->right_body_button,
+ ui->right_buttons_button,
+ ui->right_body_label,
+ ui->right_buttons_label,
+ ui->buttonR,
+ ui->labelR,
+ ui->buttonZR,
+ ui->labelZR,
+ ui->labelHome,
+ ui->buttonHome,
+ ui->buttonPlus,
+ ui->labelPlus,
+ ui->RStick,
+ ui->faceButtons,
+ };
+ break;
+ case Settings::ControllerType::RightJoycon:
+ layout_hidden = {
+ ui->left_body_button, ui->left_buttons_button,
+ ui->left_body_label, ui->left_buttons_label,
+ ui->buttonL, ui->labelL,
+ ui->buttonZL, ui->labelZL,
+ ui->labelScreenshot, ui->buttonScreenshot,
+ ui->buttonMinus, ui->labelMinus,
+ ui->LStick, ui->Dpad,
+ };
+ break;
+ }
+
+ if (debug || layout == Settings::ControllerType::ProController) {
+ ui->controller_color->hide();
+ } else {
+ if (layout == Settings::ControllerType::LeftJoycon ||
+ layout == Settings::ControllerType::RightJoycon) {
+ ui->horizontalSpacer_4->setGeometry({0, 0, 0, 0});
+
+ LayerGridElements(ui->buttons, ui->shoulderButtons, ui->Dpad);
+ LayerGridElements(ui->buttons, ui->misc, ui->RStick);
+ LayerGridElements(ui->buttons, ui->Dpad, ui->faceButtons);
+ LayerGridElements(ui->buttons, ui->RStick, ui->LStick);
+ }
+ }
+
+ for (auto* widget : layout_hidden)
+ widget->setVisible(false);
+
+ analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
+
+ for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
+ if (!button_map[button_id])
+ continue;
+ button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(button_map[button_id], &QPushButton::released, [=]() {
+ handleClick(
+ button_map[button_id],
+ [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
+ InputCommon::Polling::DeviceType::Button);
+ });
+ connect(button_map[button_id], &QPushButton::customContextMenuRequested,
+ [=](const QPoint& menu_location) {
+ QMenu context_menu;
+ context_menu.addAction(tr("Clear"), [&] {
+ buttons_param[button_id].Clear();
+ button_map[button_id]->setText(tr("[not set]"));
+ });
+ context_menu.addAction(tr("Restore Default"), [&] {
+ buttons_param[button_id] = Common::ParamPackage{
+ InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
+ button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
+ });
+ context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
+ });
+ }
+
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ if (!analog_map_buttons[analog_id][sub_button_id])
+ continue;
+ analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
+ Qt::CustomContextMenu);
+ connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() {
+ handleClick(analog_map_buttons[analog_id][sub_button_id],
+ [=](const Common::ParamPackage& params) {
+ SetAnalogButton(params, analogs_param[analog_id],
+ analog_sub_buttons[sub_button_id]);
+ },
+ InputCommon::Polling::DeviceType::Button);
+ });
+ connect(analog_map_buttons[analog_id][sub_button_id],
+ &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
+ QMenu context_menu;
+ context_menu.addAction(tr("Clear"), [&] {
+ analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
+ analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
+ });
+ context_menu.addAction(tr("Restore Default"), [&] {
+ Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
+ Config::default_analogs[analog_id][sub_button_id])};
+ SetAnalogButton(params, analogs_param[analog_id],
+ analog_sub_buttons[sub_button_id]);
+ analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
+ analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
+ });
+ context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
+ menu_location));
+ });
+ }
+ connect(analog_map_stick[analog_id], &QPushButton::released, [=]() {
+ QMessageBox::information(this, tr("Information"),
+ tr("After pressing OK, first move your joystick horizontally, "
+ "and then vertically."));
+ handleClick(
+ analog_map_stick[analog_id],
+ [=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; },
+ InputCommon::Polling::DeviceType::Analog);
+ });
+ }
+
+ connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
+ connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
+
+ timeout_timer->setSingleShot(true);
+ connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
+
+ connect(poll_timer.get(), &QTimer::timeout, [this]() {
+ Common::ParamPackage params;
+ for (auto& poller : device_pollers) {
+ params = poller->GetNextInput();
+ if (params.Has("engine")) {
+ setPollingResult(params, false);
+ return;
+ }
+ }
+ });
+
+ controller_color_buttons = {
+ ui->left_body_button,
+ ui->left_buttons_button,
+ ui->right_body_button,
+ ui->right_buttons_button,
+ };
+
+ for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) {
+ connect(controller_color_buttons[i], &QPushButton::clicked, this,
+ [this, i] { OnControllerButtonClick(static_cast<int>(i)); });
+ }
+
+ this->loadConfiguration();
+ this->resize(0, 0);
+
+ // TODO(wwylele): enable this when we actually emulate it
+ ui->buttonHome->setEnabled(false);
+}
+
+ConfigureInputPlayer::~ConfigureInputPlayer() = default;
+
+void ConfigureInputPlayer::applyConfiguration() {
+ auto& buttons =
+ debug ? Settings::values.debug_pad_buttons : Settings::values.players[player_index].buttons;
+ auto& analogs =
+ debug ? Settings::values.debug_pad_analogs : Settings::values.players[player_index].analogs;
+
+ std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(),
+ [](const Common::ParamPackage& param) { return param.Serialize(); });
+ std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(),
+ [](const Common::ParamPackage& param) { return param.Serialize(); });
+
+ if (debug)
+ return;
+
+ std::array<u32, 4> colors{};
+ std::transform(controller_colors.begin(), controller_colors.end(), colors.begin(),
+ [](QColor color) { return color.rgb(); });
+
+ Settings::values.players[player_index].body_color_left = colors[0];
+ Settings::values.players[player_index].button_color_left = colors[1];
+ Settings::values.players[player_index].body_color_right = colors[2];
+ Settings::values.players[player_index].button_color_right = colors[3];
+}
+
+void ConfigureInputPlayer::OnControllerButtonClick(int i) {
+ const QColor new_bg_color = QColorDialog::getColor(controller_colors[i]);
+ if (!new_bg_color.isValid())
+ return;
+ controller_colors[i] = new_bg_color;
+ controller_color_buttons[i]->setStyleSheet(
+ QString("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
+}
+
+void ConfigureInputPlayer::loadConfiguration() {
+ if (debug) {
+ std::transform(Settings::values.debug_pad_buttons.begin(),
+ Settings::values.debug_pad_buttons.end(), buttons_param.begin(),
+ [](const std::string& str) { return Common::ParamPackage(str); });
+ std::transform(Settings::values.debug_pad_analogs.begin(),
+ Settings::values.debug_pad_analogs.end(), analogs_param.begin(),
+ [](const std::string& str) { return Common::ParamPackage(str); });
+ } else {
+ std::transform(Settings::values.players[player_index].buttons.begin(),
+ Settings::values.players[player_index].buttons.end(), buttons_param.begin(),
+ [](const std::string& str) { return Common::ParamPackage(str); });
+ std::transform(Settings::values.players[player_index].analogs.begin(),
+ Settings::values.players[player_index].analogs.end(), analogs_param.begin(),
+ [](const std::string& str) { return Common::ParamPackage(str); });
+ }
+
+ updateButtonLabels();
+
+ if (debug)
+ return;
+
+ std::array<u32, 4> colors = {
+ Settings::values.players[player_index].body_color_left,
+ Settings::values.players[player_index].button_color_left,
+ Settings::values.players[player_index].body_color_right,
+ Settings::values.players[player_index].button_color_right,
+ };
+
+ std::transform(colors.begin(), colors.end(), controller_colors.begin(),
+ [](u32 rgb) { return QColor::fromRgb(rgb); });
+
+ for (std::size_t i = 0; i < colors.size(); ++i) {
+ controller_color_buttons[i]->setStyleSheet(
+ QString("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
+ }
+}
+
+void ConfigureInputPlayer::restoreDefaults() {
+ for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
+ buttons_param[button_id] = Common::ParamPackage{
+ InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
+ }
+
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
+ Config::default_analogs[analog_id][sub_button_id])};
+ SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
+ }
+ }
+ updateButtonLabels();
+}
+
+void ConfigureInputPlayer::ClearAll() {
+ for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
+ if (button_map[button_id] && button_map[button_id]->isEnabled())
+ buttons_param[button_id].Clear();
+ }
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ if (analog_map_buttons[analog_id][sub_button_id] &&
+ analog_map_buttons[analog_id][sub_button_id]->isEnabled())
+ analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
+ }
+ }
+
+ updateButtonLabels();
+}
+
+void ConfigureInputPlayer::updateButtonLabels() {
+ for (int button = 0; button < Settings::NativeButton::NumButtons; button++) {
+ button_map[button]->setText(ButtonToText(buttons_param[button]));
+ }
+
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ if (analog_map_buttons[analog_id][sub_button_id]) {
+ analog_map_buttons[analog_id][sub_button_id]->setText(
+ AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
+ }
+ }
+ analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
+ }
+}
+
+void ConfigureInputPlayer::handleClick(
+ QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
+ InputCommon::Polling::DeviceType type) {
+ button->setText(tr("[press key]"));
+ button->setFocus();
+
+ const auto iter = std::find(button_map.begin(), button_map.end(), button);
+ ASSERT(iter != button_map.end());
+ const auto index = std::distance(button_map.begin(), iter);
+ ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
+
+ input_setter = new_input_setter;
+
+ device_pollers = InputCommon::Polling::GetPollers(type);
+
+ // Keyboard keys can only be used as button devices
+ want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
+
+ for (auto& poller : device_pollers) {
+ poller->Start();
+ }
+
+ grabKeyboard();
+ grabMouse();
+ timeout_timer->start(5000); // Cancel after 5 seconds
+ poll_timer->start(200); // Check for new inputs every 200ms
+}
+
+void ConfigureInputPlayer::setPollingResult(const Common::ParamPackage& params, bool abort) {
+ releaseKeyboard();
+ releaseMouse();
+ timeout_timer->stop();
+ poll_timer->stop();
+ for (auto& poller : device_pollers) {
+ poller->Stop();
+ }
+
+ if (!abort) {
+ (*input_setter)(params);
+ }
+
+ updateButtonLabels();
+ input_setter = std::nullopt;
+}
+
+void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
+ if (!input_setter || !event)
+ return;
+
+ if (event->key() != Qt::Key_Escape) {
+ if (want_keyboard_keys) {
+ setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
+ false);
+ } else {
+ // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
+ return;
+ }
+ }
+ setPollingResult({}, true);
+}
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
new file mode 100644
index 000000000..7a53f6715
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -0,0 +1,104 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+
+#include <QDialog>
+#include <QKeyEvent>
+
+#include "common/param_package.h"
+#include "core/settings.h"
+#include "input_common/main.h"
+#include "ui_configure_input.h"
+
+class QPushButton;
+class QString;
+class QTimer;
+
+namespace Ui {
+class ConfigureInputPlayer;
+}
+
+class ConfigureInputPlayer : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false);
+ ~ConfigureInputPlayer() override;
+
+ /// Save all button configurations to settings file
+ void applyConfiguration();
+
+private:
+ void OnControllerButtonClick(int i);
+
+ /// Load configuration settings.
+ void loadConfiguration();
+ /// Restore all buttons to their default values.
+ void restoreDefaults();
+ /// Clear all input configuration
+ void ClearAll();
+
+ /// Update UI to reflect current configuration.
+ void updateButtonLabels();
+
+ /// Called when the button was pressed.
+ void handleClick(QPushButton* button,
+ std::function<void(const Common::ParamPackage&)> new_input_setter,
+ InputCommon::Polling::DeviceType type);
+
+ /// Finish polling and configure input using the input_setter
+ void setPollingResult(const Common::ParamPackage& params, bool abort);
+
+ /// Handle key press events.
+ void keyPressEvent(QKeyEvent* event) override;
+
+ std::unique_ptr<Ui::ConfigureInputPlayer> ui;
+
+ std::size_t player_index;
+ bool debug;
+
+ std::unique_ptr<QTimer> timeout_timer;
+ std::unique_ptr<QTimer> poll_timer;
+
+ /// This will be the the setting function when an input is awaiting configuration.
+ std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
+
+ std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
+ std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
+
+ static constexpr int ANALOG_SUB_BUTTONS_NUM = 5;
+
+ /// Each button input is represented by a QPushButton.
+ std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
+
+ std::vector<QWidget*> debug_hidden;
+ std::vector<QWidget*> layout_hidden;
+
+ /// A group of five QPushButtons represent one analog input. The buttons each represent up,
+ /// down, left, right, and modifier, respectively.
+ std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
+ analog_map_buttons;
+
+ /// Analog inputs are also represented each with a single button, used to configure with an
+ /// actual analog stick
+ std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick;
+
+ static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
+
+ std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
+
+ /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
+ /// keyboard events are ignored.
+ bool want_keyboard_keys = false;
+
+ std::array<QPushButton*, 4> controller_color_buttons;
+ std::array<QColor, 4> controller_colors;
+};
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
new file mode 100644
index 000000000..42db020be
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -0,0 +1,1164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureInputPlayer</class>
+ <widget class="QDialog" name="ConfigureInputPlayer">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>408</width>
+ <height>731</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Input</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <layout class="QGridLayout" name="buttons">
+ <item row="1" column="1">
+ <widget class="QGroupBox" name="RStick">
+ <property name="title">
+ <string>Right Stick</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_5">
+ <item row="1" column="1">
+ <layout class="QVBoxLayout" name="buttonRStickDownVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonRStickDownHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelRStickDown">
+ <property name="text">
+ <string>Down:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonRStickDown">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout" name="buttonRStickRightVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonRStickRightHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelRStickRight">
+ <property name="text">
+ <string>Right:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonRStickRight">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QPushButton" name="buttonRStickAnalog">
+ <property name="text">
+ <string>Set Analog Stick</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="buttonRStickLeftVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonRStickLeftHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelRStickLeft">
+ <property name="text">
+ <string>Left:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonRStickLeft">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <layout class="QVBoxLayout" name="buttonRStickUpVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonRStickUpHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelRStickUp">
+ <property name="text">
+ <string>Up:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonRStickUp">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <layout class="QVBoxLayout" name="buttonRStickPressedVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonRStickPressedHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelRStickPressed">
+ <property name="text">
+ <string>Pressed:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonRStick">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="1">
+ <layout class="QVBoxLayout" name="buttonRStickModVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonRStickModHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelRStickMod">
+ <property name="text">
+ <string>Modifier:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonRStickMod">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QGroupBox" name="Dpad">
+ <property name="title">
+ <string>Directional Pad</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="1" column="0">
+ <layout class="QVBoxLayout" name="buttonDpadUpVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonDpadUpHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelDpadUp">
+ <property name="text">
+ <string>Up:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonDpadUp">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <layout class="QVBoxLayout" name="buttonDpadDownVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonDpadDownHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelDpadDown">
+ <property name="text">
+ <string>Down:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonDpadDown">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonDpadLeftHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelDpadLeft">
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Left:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonDpadLeft">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonDpadRightHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelDpadRight">
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Right:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonDpadRight">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="faceButtons">
+ <property name="title">
+ <string>Face Buttons</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="buttonFaceButtonsAVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonFaceButtonsAHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelA">
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>A:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonA">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout" name="buttonFaceButtonsBVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonFaceButtonsBHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelB">
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>B:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonB">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <layout class="QVBoxLayout" name="buttonFaceButtonsXVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonFaceButtonsXHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelX">
+ <property name="text">
+ <string>X:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonX">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <layout class="QVBoxLayout" name="buttonFaceButtonsYVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonFaceButtonsYHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelY">
+ <property name="text">
+ <string>Y:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonY">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <widget class="QGroupBox" name="controller_color">
+ <property name="title">
+ <string>Controller Color</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_10" columnstretch="0,0,0,0,0,0,0">
+ <item row="0" column="0">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="left_body_label">
+ <property name="text">
+ <string>Left Body</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="6">
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="left_buttons_label">
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Left Buttons</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="5">
+ <widget class="QPushButton" name="right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLabel" name="right_body_label">
+ <property name="text">
+ <string>Right Body</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QLabel" name="right_buttons_label">
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Right Buttons</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="5">
+ <widget class="QPushButton" name="right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QGroupBox" name="LStick">
+ <property name="title">
+ <string>Left Stick</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="1" column="1">
+ <layout class="QVBoxLayout" name="buttonLStickUpVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonLStickUpHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelLStickUp">
+ <property name="text">
+ <string>Up:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonLStickUp">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="2">
+ <layout class="QVBoxLayout" name="buttonLStickRightVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonLStickRightHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelLStickRight">
+ <property name="text">
+ <string>Right:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonLStickRight">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="4" column="1" colspan="2">
+ <widget class="QPushButton" name="buttonLStickAnalog">
+ <property name="text">
+ <string>Set Analog Stick</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout" name="buttonLStickLeftVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonLStickLeftHorizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="labelLStickLeft">
+ <property name="text">
+ <string>Left:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonLStickLeft">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="2">
+ <layout class="QVBoxLayout" name="buttonLStickDownVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonLStickDownHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelLStickDown">
+ <property name="text">
+ <string>Down:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonLStickDown">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="2">
+ <layout class="QVBoxLayout" name="buttonLStickModVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonLStickModHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelLStickMod">
+ <property name="text">
+ <string>Modifier:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonLStickMod">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="1">
+ <layout class="QVBoxLayout" name="buttonLStickPressedVerticalLayout" stretch="0,0">
+ <item>
+ <layout class="QHBoxLayout" name="buttonLStickPressedHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelLStickPressed">
+ <property name="text">
+ <string>Pressed:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonLStick">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QGroupBox" name="shoulderButtons">
+ <property name="title">
+ <string>Shoulder Buttons</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="3" column="0">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonShoulderButtonsSLHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelSL">
+ <property name="text">
+ <string>SL:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonSL">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="1">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsZRVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonShoulderButtonsZRHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelZR">
+ <property name="text">
+ <string>ZR:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonZR">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="1">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonShoulderButtonsSRHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelSR">
+ <property name="text">
+ <string>SR:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonSR">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsZLVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonShoulderButtonsZLHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelZL">
+ <property name="text">
+ <string>ZL:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonZL">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsLVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonShoulderButtonsLHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelL">
+ <property name="text">
+ <string>L:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonL">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsRVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonShoulderButtonsRHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelR">
+ <property name="text">
+ <string>R:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonR">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QGroupBox" name="misc">
+ <property name="title">
+ <string>Misc.</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_6">
+ <item row="1" column="0">
+ <layout class="QVBoxLayout" name="buttonMiscMinusVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonMiscMinusHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelMinus">
+ <property name="text">
+ <string>Minus:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonMinus">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="1">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="buttonMiscPlusVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonMiscPlusHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelPlus">
+ <property name="text">
+ <string>Plus:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonPlus">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout" name="buttonMiscHomeVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonMiscHomeHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelHome">
+ <property name="text">
+ <string>Home:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonHome">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <layout class="QVBoxLayout" name="buttonMiscScrCapVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="buttonMiscScrCapHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelScreenshot">
+ <property name="text">
+ <string>Screen Capture:</string>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonScreenshot">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>80</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QPushButton" name="buttonClearAll">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string>Clear All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonRestoreDefaults">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string>Restore Defaults</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ConfigureInputPlayer</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>371</x>
+ <y>730</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>229</x>
+ <y>375</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ConfigureInputPlayer</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>371</x>
+ <y>730</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>229</x>
+ <y>375</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
new file mode 100644
index 000000000..ef857035e
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -0,0 +1,213 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <memory>
+
+#include <QKeyEvent>
+#include <QMenu>
+#include <QTimer>
+
+#include "common/assert.h"
+#include "common/param_package.h"
+#include "input_common/main.h"
+#include "ui_configure_mouse_advanced.h"
+#include "yuzu/configuration/config.h"
+#include "yuzu/configuration/configure_mouse_advanced.h"
+
+static QString GetKeyName(int key_code) {
+ switch (key_code) {
+ case Qt::Key_Shift:
+ return QObject::tr("Shift");
+ case Qt::Key_Control:
+ return QObject::tr("Ctrl");
+ case Qt::Key_Alt:
+ return QObject::tr("Alt");
+ case Qt::Key_Meta:
+ return "";
+ default:
+ return QKeySequence(key_code).toString();
+ }
+}
+
+static QString ButtonToText(const Common::ParamPackage& param) {
+ if (!param.Has("engine")) {
+ return QObject::tr("[not set]");
+ } else if (param.Get("engine", "") == "keyboard") {
+ return GetKeyName(param.Get("code", 0));
+ } else if (param.Get("engine", "") == "sdl") {
+ if (param.Has("hat")) {
+ return QString(QObject::tr("Hat %1 %2"))
+ .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
+ }
+ if (param.Has("axis")) {
+ return QString(QObject::tr("Axis %1%2"))
+ .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
+ }
+ if (param.Has("button")) {
+ return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
+ }
+ return QString();
+ } else {
+ return QObject::tr("[unknown]");
+ }
+}
+
+ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigureMouseAdvanced>()),
+ timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
+ ui->setupUi(this);
+ setFocusPolicy(Qt::ClickFocus);
+
+ button_map = {
+ ui->left_button, ui->right_button, ui->middle_button, ui->forward_button, ui->back_button,
+ };
+
+ for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
+ if (!button_map[button_id])
+ continue;
+ button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(button_map[button_id], &QPushButton::released, [=]() {
+ handleClick(
+ button_map[button_id],
+ [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
+ InputCommon::Polling::DeviceType::Button);
+ });
+ connect(button_map[button_id], &QPushButton::customContextMenuRequested,
+ [=](const QPoint& menu_location) {
+ QMenu context_menu;
+ context_menu.addAction(tr("Clear"), [&] {
+ buttons_param[button_id].Clear();
+ button_map[button_id]->setText(tr("[not set]"));
+ });
+ context_menu.addAction(tr("Restore Default"), [&] {
+ buttons_param[button_id] =
+ Common::ParamPackage{InputCommon::GenerateKeyboardParam(
+ Config::default_mouse_buttons[button_id])};
+ button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
+ });
+ context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
+ });
+ }
+
+ connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
+ connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
+
+ timeout_timer->setSingleShot(true);
+ connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
+
+ connect(poll_timer.get(), &QTimer::timeout, [this]() {
+ Common::ParamPackage params;
+ for (auto& poller : device_pollers) {
+ params = poller->GetNextInput();
+ if (params.Has("engine")) {
+ setPollingResult(params, false);
+ return;
+ }
+ }
+ });
+
+ loadConfiguration();
+ resize(0, 0);
+}
+
+ConfigureMouseAdvanced::~ConfigureMouseAdvanced() = default;
+
+void ConfigureMouseAdvanced::applyConfiguration() {
+ std::transform(buttons_param.begin(), buttons_param.end(),
+ Settings::values.mouse_buttons.begin(),
+ [](const Common::ParamPackage& param) { return param.Serialize(); });
+}
+
+void ConfigureMouseAdvanced::loadConfiguration() {
+ std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
+ buttons_param.begin(),
+ [](const std::string& str) { return Common::ParamPackage(str); });
+ updateButtonLabels();
+}
+
+void ConfigureMouseAdvanced::restoreDefaults() {
+ for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
+ buttons_param[button_id] = Common::ParamPackage{
+ InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
+ }
+
+ updateButtonLabels();
+}
+
+void ConfigureMouseAdvanced::ClearAll() {
+ for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
+ if (button_map[i] && button_map[i]->isEnabled())
+ buttons_param[i].Clear();
+ }
+
+ updateButtonLabels();
+}
+
+void ConfigureMouseAdvanced::updateButtonLabels() {
+ for (int button = 0; button < Settings::NativeMouseButton::NumMouseButtons; button++) {
+ button_map[button]->setText(ButtonToText(buttons_param[button]));
+ }
+}
+
+void ConfigureMouseAdvanced::handleClick(
+ QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
+ InputCommon::Polling::DeviceType type) {
+ button->setText(tr("[press key]"));
+ button->setFocus();
+
+ const auto iter = std::find(button_map.begin(), button_map.end(), button);
+ ASSERT(iter != button_map.end());
+ const auto index = std::distance(button_map.begin(), iter);
+ ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
+
+ input_setter = new_input_setter;
+
+ device_pollers = InputCommon::Polling::GetPollers(type);
+
+ // Keyboard keys can only be used as button devices
+ want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
+
+ for (auto& poller : device_pollers) {
+ poller->Start();
+ }
+
+ grabKeyboard();
+ grabMouse();
+ timeout_timer->start(5000); // Cancel after 5 seconds
+ poll_timer->start(200); // Check for new inputs every 200ms
+}
+
+void ConfigureMouseAdvanced::setPollingResult(const Common::ParamPackage& params, bool abort) {
+ releaseKeyboard();
+ releaseMouse();
+ timeout_timer->stop();
+ poll_timer->stop();
+ for (auto& poller : device_pollers) {
+ poller->Stop();
+ }
+
+ if (!abort) {
+ (*input_setter)(params);
+ }
+
+ updateButtonLabels();
+ input_setter = std::nullopt;
+}
+
+void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
+ if (!input_setter || !event)
+ return;
+
+ if (event->key() != Qt::Key_Escape) {
+ if (want_keyboard_keys) {
+ setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
+ false);
+ } else {
+ // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
+ return;
+ }
+ }
+ setPollingResult({}, true);
+}
diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h
new file mode 100644
index 000000000..e04da4bf2
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.h
@@ -0,0 +1,68 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <optional>
+#include <QDialog>
+
+#include "core/settings.h"
+
+class QCheckBox;
+class QPushButton;
+class QTimer;
+
+namespace Ui {
+class ConfigureMouseAdvanced;
+}
+
+class ConfigureMouseAdvanced : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigureMouseAdvanced(QWidget* parent);
+ ~ConfigureMouseAdvanced() override;
+
+ void applyConfiguration();
+
+private:
+ /// Load configuration settings.
+ void loadConfiguration();
+ /// Restore all buttons to their default values.
+ void restoreDefaults();
+ /// Clear all input configuration
+ void ClearAll();
+
+ /// Update UI to reflect current configuration.
+ void updateButtonLabels();
+
+ /// Called when the button was pressed.
+ void handleClick(QPushButton* button,
+ std::function<void(const Common::ParamPackage&)> new_input_setter,
+ InputCommon::Polling::DeviceType type);
+
+ /// Finish polling and configure input using the input_setter
+ void setPollingResult(const Common::ParamPackage& params, bool abort);
+
+ /// Handle key press events.
+ void keyPressEvent(QKeyEvent* event) override;
+
+ std::unique_ptr<Ui::ConfigureMouseAdvanced> ui;
+
+ /// This will be the the setting function when an input is awaiting configuration.
+ std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
+
+ std::array<QPushButton*, Settings::NativeMouseButton::NumMouseButtons> button_map;
+ std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons> buttons_param;
+
+ std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
+
+ std::unique_ptr<QTimer> timeout_timer;
+ std::unique_ptr<QTimer> poll_timer;
+
+ /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
+ /// keyboard events are ignored.
+ bool want_keyboard_keys = false;
+};
diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui
new file mode 100644
index 000000000..08245ecf0
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.ui
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureMouseAdvanced</class>
+ <widget class="QDialog" name="ConfigureMouseAdvanced">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>250</width>
+ <height>261</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Mouse</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="gridGroupBox">
+ <property name="title">
+ <string>Mouse Buttons</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="4">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="3">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Right:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="right_button">
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Middle:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="middle_button">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="1">
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="minimumSize">
+ <size>
+ <width>54</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Back:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="back_button">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Left:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="left_button">
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="3">
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Forward:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="forward_button">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QPushButton" name="buttonClearAll">
+ <property name="text">
+ <string>Clear All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonRestoreDefaults">
+ <property name="text">
+ <string>Restore Defaults</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ConfigureMouseAdvanced</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>124</x>
+ <y>266</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>124</x>
+ <y>143</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ConfigureMouseAdvanced</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>124</x>
+ <y>266</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>124</x>
+ <y>143</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 4803d43bb..ab5d46492 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -137,6 +137,12 @@ ConfigureSystem::ConfigureSystem(QWidget* parent)
connect(ui->pm_remove, &QPushButton::pressed, this, &ConfigureSystem::DeleteUser);
connect(ui->pm_set_image, &QPushButton::pressed, this, &ConfigureSystem::SetUserImage);
+ connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) {
+ ui->rng_seed_edit->setEnabled(checked);
+ if (!checked)
+ ui->rng_seed_edit->setText(QStringLiteral("00000000"));
+ });
+
scene = new QGraphicsScene;
ui->current_user_icon->setScene(scene);
@@ -155,6 +161,13 @@ void ConfigureSystem::setConfiguration() {
PopulateUserList();
UpdateCurrentUser();
+
+ ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value());
+ ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value());
+
+ const auto rng_seed =
+ QString("%1").arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'}).toUpper();
+ ui->rng_seed_edit->setText(rng_seed);
}
void ConfigureSystem::PopulateUserList() {
@@ -195,6 +208,12 @@ void ConfigureSystem::applyConfiguration() {
return;
Settings::values.language_index = ui->combo_language->currentIndex();
+
+ if (ui->rng_seed_checkbox->isChecked())
+ Settings::values.rng_seed = ui->rng_seed_edit->text().toULongLong(nullptr, 16);
+ else
+ Settings::values.rng_seed = std::nullopt;
+
Settings::Apply();
}
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 020b32a37..a91580893 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>360</width>
+ <width>366</width>
<height>483</height>
</rect>
</property>
@@ -22,98 +22,6 @@
<string>System Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
- <item row="1" column="0">
- <widget class="QLabel" name="label_language">
- <property name="text">
- <string>Language</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_birthday">
- <property name="text">
- <string>Birthday</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_console_id">
- <property name="text">
- <string>Console ID:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_birthday2">
- <item>
- <widget class="QComboBox" name="combo_birthmonth">
- <item>
- <property name="text">
- <string>January</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>February</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>March</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>April</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>May</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>June</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>July</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>August</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>September</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>October</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>November</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>December</string>
- </property>
- </item>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="combo_birthday"/>
- </item>
- </layout>
- </item>
<item row="1" column="1">
<widget class="QComboBox" name="combo_language">
<property name="toolTip">
@@ -206,6 +114,13 @@
</item>
</widget>
</item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_console_id">
+ <property name="text">
+ <string>Console ID:</string>
+ </property>
+ </widget>
+ </item>
<item row="2" column="0">
<widget class="QLabel" name="label_sound">
<property name="text">
@@ -213,6 +128,100 @@
</property>
</widget>
</item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_birthday">
+ <property name="text">
+ <string>Birthday</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_birthday2">
+ <item>
+ <widget class="QComboBox" name="combo_birthmonth">
+ <item>
+ <property name="text">
+ <string>January</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>February</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>March</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>April</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>May</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>June</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>July</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>August</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>September</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>October</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>November</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>December</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="combo_birthday"/>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="1">
+ <widget class="QPushButton" name="button_regenerate_console_id">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string>Regenerate</string>
+ </property>
+ </widget>
+ </item>
<item row="2" column="1">
<widget class="QComboBox" name="combo_sound">
<item>
@@ -232,19 +241,38 @@
</item>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QPushButton" name="button_regenerate_console_id">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_language">
+ <property name="text">
+ <string>Language</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QCheckBox" name="rng_seed_checkbox">
+ <property name="text">
+ <string>RNG Seed</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="rng_seed_edit">
<property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="layoutDirection">
- <enum>Qt::RightToLeft</enum>
+ <property name="font">
+ <font>
+ <family>Lucida Console</family>
+ </font>
</property>
- <property name="text">
- <string>Regenerate</string>
+ <property name="inputMask">
+ <string notr="true">HHHHHHHH</string>
+ </property>
+ <property name="maxLength">
+ <number>8</number>
</property>
</widget>
</item>
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.cpp b/src/yuzu/configuration/configure_touchscreen_advanced.cpp
new file mode 100644
index 000000000..9c1561e9d
--- /dev/null
+++ b/src/yuzu/configuration/configure_touchscreen_advanced.cpp
@@ -0,0 +1,42 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+#include "ui_configure_touchscreen_advanced.h"
+#include "yuzu/configuration/config.h"
+#include "yuzu/configuration/configure_touchscreen_advanced.h"
+
+ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigureTouchscreenAdvanced>()) {
+ ui->setupUi(this);
+
+ connect(ui->restore_defaults_button, &QPushButton::pressed, this,
+ &ConfigureTouchscreenAdvanced::restoreDefaults);
+
+ loadConfiguration();
+ resize(0, 0);
+}
+
+ConfigureTouchscreenAdvanced::~ConfigureTouchscreenAdvanced() = default;
+
+void ConfigureTouchscreenAdvanced::applyConfiguration() {
+ Settings::values.touchscreen.finger = ui->finger_box->value();
+ Settings::values.touchscreen.diameter_x = ui->diameter_x_box->value();
+ Settings::values.touchscreen.diameter_y = ui->diameter_y_box->value();
+ Settings::values.touchscreen.rotation_angle = ui->angle_box->value();
+}
+
+void ConfigureTouchscreenAdvanced::loadConfiguration() {
+ ui->finger_box->setValue(Settings::values.touchscreen.finger);
+ ui->diameter_x_box->setValue(Settings::values.touchscreen.diameter_x);
+ ui->diameter_y_box->setValue(Settings::values.touchscreen.diameter_y);
+ ui->angle_box->setValue(Settings::values.touchscreen.rotation_angle);
+}
+
+void ConfigureTouchscreenAdvanced::restoreDefaults() {
+ ui->finger_box->setValue(0);
+ ui->diameter_x_box->setValue(15);
+ ui->diameter_y_box->setValue(15);
+ ui->angle_box->setValue(0);
+}
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.h b/src/yuzu/configuration/configure_touchscreen_advanced.h
new file mode 100644
index 000000000..41cd255fb
--- /dev/null
+++ b/src/yuzu/configuration/configure_touchscreen_advanced.h
@@ -0,0 +1,32 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QDialog>
+#include <QWidget>
+#include "yuzu/configuration/config.h"
+
+namespace Ui {
+class ConfigureTouchscreenAdvanced;
+}
+
+class ConfigureTouchscreenAdvanced : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigureTouchscreenAdvanced(QWidget* parent);
+ ~ConfigureTouchscreenAdvanced() override;
+
+ void applyConfiguration();
+
+private:
+ /// Load configuration settings.
+ void loadConfiguration();
+ /// Restore all buttons to their default values.
+ void restoreDefaults();
+
+ std::unique_ptr<Ui::ConfigureTouchscreenAdvanced> ui;
+};
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.ui b/src/yuzu/configuration/configure_touchscreen_advanced.ui
new file mode 100644
index 000000000..1171c2dd1
--- /dev/null
+++ b/src/yuzu/configuration/configure_touchscreen_advanced.ui
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureTouchscreenAdvanced</class>
+ <widget class="QDialog" name="ConfigureTouchscreenAdvanced">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>298</width>
+ <height>339</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Touchscreen</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="minimumSize">
+ <size>
+ <width>280</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Warning: The settings in this page affect the inner workings of yuzu's emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="gridGroupBox">
+ <property name="title">
+ <string>Touch Parameters</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Touch Diameter Y</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Finger</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Touch Diameter X</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QSpinBox" name="finger_box">
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Rotational Angle</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QSpinBox" name="diameter_x_box"/>
+ </item>
+ <item row="2" column="2">
+ <widget class="QSpinBox" name="diameter_y_box"/>
+ </item>
+ <item row="3" column="2">
+ <widget class="QSpinBox" name="angle_box"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="restore_defaults_button">
+ <property name="text">
+ <string>Restore Defaults</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ConfigureTouchscreenAdvanced</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>140</x>
+ <y>318</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>140</x>
+ <y>169</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ConfigureTouchscreenAdvanced</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>140</x>
+ <y>318</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>140</x>
+ <y>169</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/configuration/configure_web.h b/src/yuzu/configuration/configure_web.h
index 7741ab95d..7752ae4a1 100644
--- a/src/yuzu/configuration/configure_web.h
+++ b/src/yuzu/configuration/configure_web.h
@@ -17,18 +17,17 @@ class ConfigureWeb : public QWidget {
public:
explicit ConfigureWeb(QWidget* parent = nullptr);
- ~ConfigureWeb();
+ ~ConfigureWeb() override;
void applyConfiguration();
void retranslateUi();
-public slots:
+private:
void RefreshTelemetryID();
void OnLoginChanged();
void VerifyLogin();
void OnLoginVerified();
-private:
void setConfiguration();
bool user_verified = true;