Browse Source
qt: Move controller button config to separate dialog
qt: Move controller button config to separate dialog
Handles button configuration for all controller layouts and debug pads. Configurable at construction.pull/15/merge
4 changed files with 1767 additions and 0 deletions
-
3src/yuzu/CMakeLists.txt
-
506src/yuzu/configuration/configure_input_player.cpp
-
102src/yuzu/configuration/configure_input_player.h
-
1156src/yuzu/configuration/configure_input_player.ui
@ -0,0 +1,506 @@ |
|||
// 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 MoveGridElement(QGridLayout* grid, int row_old, int column_old, int row_new, |
|||
int column_new) { |
|||
const auto item = grid->itemAtPosition(row_old, column_old); |
|||
// grid->removeItem(item);
|
|||
grid->addItem(item, row_new, column_new); |
|||
} |
|||
|
|||
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, u8 player_index, bool debug) |
|||
: QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), |
|||
timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()), |
|||
player_index(player_index), debug(debug) { |
|||
|
|||
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, |
|||
std::bind(&ConfigureInputPlayer::OnControllerButtonClick, this, i)); |
|||
} |
|||
|
|||
this->loadConfiguration(); |
|||
this->resize(0, 0); |
|||
|
|||
// TODO(wwylele): enable this when we actually emulate it
|
|||
ui->buttonHome->setEnabled(false); |
|||
} |
|||
|
|||
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 = boost::none; |
|||
} |
|||
|
|||
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); |
|||
} |
|||
@ -0,0 +1,102 @@ |
|||
// 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 <string> |
|||
#include <unordered_map> |
|||
#include <QDialog> |
|||
#include <QKeyEvent> |
|||
#include <boost/optional.hpp> |
|||
#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, u8 player_index, bool debug = false); |
|||
|
|||
/// Save all button configurations to settings file |
|||
void applyConfiguration(); |
|||
|
|||
private: |
|||
std::unique_ptr<Ui::ConfigureInputPlayer> ui; |
|||
|
|||
u8 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. |
|||
boost::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; |
|||
|
|||
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; |
|||
}; |
|||
1156
src/yuzu/configuration/configure_input_player.ui
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue