Download Source Code/Citra/src/citra_qt/configuration/configure_input.cpp from GilbertClaus/Emulator: direct link, hf CLI and curl.
- Browser
- Download file 29.9 kB
-
https://huggingface.co/GilbertClaus/Emulator/resolve/main/Source%20Code/Citra/src/citra_qt/configuration/configure_input.cpp
- Command line
-
hf download 'hf://GilbertClaus/Emulator/Source Code/Citra/src/citra_qt/configuration/configure_input.cpp'
-
curl -L -o configure_input.cpp https://huggingface.co/GilbertClaus/Emulator/resolve/main/Source%20Code/Citra/src/citra_qt/configuration/configure_input.cpp
29.9 kB
| // Copyright 2016 Citra Emulator Project | |
| // Licensed under GPLv2 or any later version | |
| // Refer to the license.txt file included. | |
| const std::array<std::string, ConfigureInput::ANALOG_SUB_BUTTONS_NUM> | |
| ConfigureInput::analog_sub_buttons{{ | |
| "up", | |
| "down", | |
| "left", | |
| "right", | |
| "modifier", | |
| }}; | |
| enum class AnalogSubButtons { | |
| 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 QString{}; | |
| 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"}, | |
| }; | |
| } | |
| analog_param.Set(button_name, input_param.Serialize()); | |
| } | |
| static QString ButtonToText(const Common::ParamPackage& param) { | |
| if (!param.Has("engine")) { | |
| return QObject::tr("[not set]"); | |
| } | |
| const auto engine_str = param.Get("engine", ""); | |
| if (engine_str == "keyboard") { | |
| return GetKeyName(param.Get("code", 0)); | |
| } | |
| if (engine_str == "sdl") { | |
| if (param.Has("hat")) { | |
| const QString hat_str = QString::fromStdString(param.Get("hat", "")); | |
| const QString direction_str = QString::fromStdString(param.Get("direction", "")); | |
| return QObject::tr("Hat %1 %2").arg(hat_str, direction_str); | |
| } | |
| if (param.Has("axis")) { | |
| const QString axis_str = QString::fromStdString(param.Get("axis", "")); | |
| const QString direction_str = QString::fromStdString(param.Get("direction", "")); | |
| return QObject::tr("Axis %1%2").arg(axis_str, direction_str); | |
| } | |
| if (param.Has("button")) { | |
| const QString button_str = QString::fromStdString(param.Get("button", "")); | |
| return QObject::tr("Button %1").arg(button_str); | |
| } | |
| return {}; | |
| } | |
| if (engine_str == "gcpad") { | |
| if (param.Has("axis")) { | |
| const QString axis_str = QString::fromStdString(param.Get("axis", "")); | |
| const QString direction_str = QString::fromStdString(param.Get("direction", "")); | |
| return QObject::tr("GC Axis %1%2").arg(axis_str, direction_str); | |
| } | |
| if (param.Has("button")) { | |
| const QString button_str = QString::number(int(std::log2(param.Get("button", 0)))); | |
| return QObject::tr("GC Button %1").arg(button_str); | |
| } | |
| return GetKeyName(param.Get("code", 0)); | |
| } | |
| return QObject::tr("[unknown]"); | |
| } | |
| static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { | |
| if (!param.Has("engine")) { | |
| return QObject::tr("[not set]"); | |
| } | |
| const auto engine_str = param.Get("engine", ""); | |
| if (engine_str == "analog_from_button") { | |
| return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); | |
| } | |
| const QString axis_x_str{QString::fromStdString(param.Get("axis_x", ""))}; | |
| const QString axis_y_str{QString::fromStdString(param.Get("axis_y", ""))}; | |
| static const QString plus_str{QString::fromStdString("+")}; | |
| static const QString minus_str{QString::fromStdString("-")}; | |
| if (engine_str == "sdl" || engine_str == "gcpad") { | |
| if (dir == "modifier") { | |
| return QObject::tr("[unused]"); | |
| } | |
| if (dir == "left") { | |
| return QObject::tr("Axis %1%2").arg(axis_x_str, minus_str); | |
| } | |
| if (dir == "right") { | |
| return QObject::tr("Axis %1%2").arg(axis_x_str, plus_str); | |
| } | |
| if (dir == "up") { | |
| return QObject::tr("Axis %1%2").arg(axis_y_str, plus_str); | |
| } | |
| if (dir == "down") { | |
| return QObject::tr("Axis %1%2").arg(axis_y_str, minus_str); | |
| } | |
| return {}; | |
| } | |
| return QObject::tr("[unknown]"); | |
| } | |
| ConfigureInput::ConfigureInput(QWidget* parent) | |
| : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()), | |
| timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) { | |
| ui->setupUi(this); | |
| setFocusPolicy(Qt::ClickFocus); | |
| for (const auto& profile : Settings::values.input_profiles) { | |
| ui->profile->addItem(QString::fromStdString(profile.name)); | |
| } | |
| ui->profile->setCurrentIndex(Settings::values.current_input_profile_index); | |
| button_map = { | |
| ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, | |
| ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, | |
| ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect, | |
| ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR, | |
| ui->buttonHome, ui->buttonPower, | |
| }; | |
| analog_map_buttons = {{ | |
| { | |
| ui->buttonCircleUp, | |
| ui->buttonCircleDown, | |
| ui->buttonCircleLeft, | |
| ui->buttonCircleRight, | |
| nullptr, | |
| }, | |
| { | |
| ui->buttonCStickUp, | |
| ui->buttonCStickDown, | |
| ui->buttonCStickLeft, | |
| ui->buttonCStickRight, | |
| nullptr, | |
| }, | |
| }}; | |
| analog_map_stick = {ui->buttonCircleAnalog, ui->buttonCStickAnalog}; | |
| analog_map_deadzone_and_modifier_slider = {ui->sliderCirclePadDeadzoneAndModifier, | |
| ui->sliderCStickDeadzoneAndModifier}; | |
| analog_map_deadzone_and_modifier_slider_label = {ui->labelCirclePadDeadzoneAndModifier, | |
| ui->labelCStickDeadzoneAndModifier}; | |
| 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::clicked, [this, button_id]() { | |
| HandleClick( | |
| button_map[button_id], | |
| [this, button_id](Common::ParamPackage params) { | |
| // Workaround for ZL & ZR for analog triggers like on XBOX controllors. | |
| // Analog triggers (from controllers like the XBOX controller) would not | |
| // work due to a different range of their signals (from 0 to 255 on | |
| // analog triggers instead of -32768 to 32768 on analog joysticks). The | |
| // SDL driver misinterprets analog triggers as analog joysticks. | |
| // TODO: reinterpret the signal range for analog triggers to map the | |
| // values correctly. This is required for the correct emulation of the | |
| // analog triggers of the GameCube controller. | |
| if (button_id == Settings::NativeButton::ZL || | |
| button_id == Settings::NativeButton::ZR) { | |
| params.Set("direction", "+"); | |
| params.Set("threshold", "0.5"); | |
| } | |
| buttons_param[button_id] = std::move(params); | |
| // If the user closes the dialog, the changes are reverted in | |
| // `GMainWindow::OnConfigure()` | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }, | |
| InputCommon::Polling::DeviceType::Button); | |
| }); | |
| connect(button_map[button_id], &QPushButton::customContextMenuRequested, this, | |
| [this, button_id](const QPoint& menu_location) { | |
| QMenu context_menu; | |
| context_menu.addAction(tr("Clear"), this, [&] { | |
| buttons_param[button_id].Clear(); | |
| button_map[button_id]->setText(tr("[not set]")); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }); | |
| context_menu.addAction(tr("Restore Default"), this, [&] { | |
| buttons_param[button_id] = Common::ParamPackage{ | |
| InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; | |
| button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }); | |
| 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::clicked, this, | |
| [this, analog_id, sub_button_id]() { | |
| HandleClick( | |
| analog_map_buttons[analog_id][sub_button_id], | |
| [this, analog_id, sub_button_id](const Common::ParamPackage& params) { | |
| SetAnalogButton(params, analogs_param[analog_id], | |
| analog_sub_buttons[sub_button_id]); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }, | |
| InputCommon::Polling::DeviceType::Button); | |
| }); | |
| connect(analog_map_buttons[analog_id][sub_button_id], | |
| &QPushButton::customContextMenuRequested, this, | |
| [this, analog_id, sub_button_id](const QPoint& menu_location) { | |
| QMenu context_menu; | |
| context_menu.addAction(tr("Clear"), this, [&] { | |
| analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); | |
| analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }); | |
| context_menu.addAction(tr("Restore Default"), this, [&] { | |
| 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])); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }); | |
| context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( | |
| menu_location)); | |
| }); | |
| } | |
| connect(analog_map_stick[analog_id], &QPushButton::clicked, this, [this, analog_id]() { | |
| if (QMessageBox::information( | |
| this, tr("Information"), | |
| tr("After pressing OK, first move your joystick horizontally, " | |
| "and then vertically."), | |
| QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { | |
| HandleClick( | |
| analog_map_stick[analog_id], | |
| [this, analog_id](const Common::ParamPackage& params) { | |
| analogs_param[analog_id] = params; | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }, | |
| InputCommon::Polling::DeviceType::Analog); | |
| } | |
| }); | |
| connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, this, | |
| [this, analog_id] { | |
| const int slider_value = | |
| analog_map_deadzone_and_modifier_slider[analog_id]->value(); | |
| const auto engine = analogs_param[analog_id].Get("engine", ""); | |
| if (engine == "sdl" || engine == "gcpad") { | |
| analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | |
| tr("Deadzone: %1%").arg(slider_value)); | |
| analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); | |
| } else { | |
| analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | |
| tr("Modifier Scale: %1%").arg(slider_value)); | |
| analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); | |
| } | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }); | |
| } | |
| // The Circle Mod button is common for both the sticks, so update the modifier settings | |
| // for both the sticks. | |
| connect(ui->buttonCircleMod, &QPushButton::clicked, this, [this]() { | |
| HandleClick( | |
| ui->buttonCircleMod, | |
| [this](const Common::ParamPackage& params) { | |
| for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; | |
| analog_id++) { | |
| SetAnalogButton(params, analogs_param[analog_id], "modifier"); | |
| } | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }, | |
| InputCommon::Polling::DeviceType::Button); | |
| }); | |
| connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, this, | |
| [&](const QPoint& menu_location) { | |
| QMenu context_menu; | |
| context_menu.addAction(tr("Clear"), this, [&] { | |
| for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; | |
| analog_id++) { | |
| analogs_param[analog_id].Erase("modifier"); | |
| } | |
| ui->buttonCircleMod->setText(tr("[not set]")); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }); | |
| context_menu.addAction(tr("Restore Default"), this, [&] { | |
| for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; | |
| analog_id++) { | |
| Common::ParamPackage params{InputCommon::GenerateKeyboardParam( | |
| Config::default_analogs[analog_id] | |
| [static_cast<u32>(AnalogSubButtons::modifier)])}; | |
| SetAnalogButton(params, analogs_param[analog_id], "modifier"); | |
| ui->buttonCircleMod->setText( | |
| AnalogToText(analogs_param[analog_id], "modifier")); | |
| } | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }); | |
| context_menu.exec(ui->buttonCircleMod->mapToGlobal(menu_location)); | |
| }); | |
| connect(ui->buttonMotionTouch, &QPushButton::clicked, this, [this] { | |
| QDialog* motion_touch_dialog = new ConfigureMotionTouch(this); | |
| return motion_touch_dialog->exec(); | |
| }); | |
| ui->buttonDelete->setEnabled(ui->profile->count() > 1); | |
| connect(ui->buttonAutoMap, &QPushButton::clicked, this, &ConfigureInput::AutoMap); | |
| connect(ui->buttonClearAll, &QPushButton::clicked, this, &ConfigureInput::ClearAll); | |
| connect(ui->buttonRestoreDefaults, &QPushButton::clicked, this, | |
| &ConfigureInput::RestoreDefaults); | |
| connect(ui->buttonNew, &QPushButton::clicked, this, &ConfigureInput::NewProfile); | |
| connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile); | |
| connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile); | |
| connect(ui->profile, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int i) { | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(Settings::values.current_input_profile_index); | |
| Settings::LoadProfile(i); | |
| LoadConfiguration(); | |
| }); | |
| timeout_timer->setSingleShot(true); | |
| connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); }); | |
| connect(poll_timer.get(), &QTimer::timeout, this, [this]() { | |
| Common::ParamPackage params; | |
| for (auto& poller : device_pollers) { | |
| params = poller->GetNextInput(); | |
| if (params.Has("engine")) { | |
| SetPollingResult(params, false); | |
| return; | |
| } | |
| } | |
| }); | |
| LoadConfiguration(); | |
| } | |
| ConfigureInput::~ConfigureInput() = default; | |
| void ConfigureInput::ApplyConfiguration() { | |
| std::transform(buttons_param.begin(), buttons_param.end(), | |
| Settings::values.current_input_profile.buttons.begin(), | |
| [](const Common::ParamPackage& param) { return param.Serialize(); }); | |
| std::transform(analogs_param.begin(), analogs_param.end(), | |
| Settings::values.current_input_profile.analogs.begin(), | |
| [](const Common::ParamPackage& param) { return param.Serialize(); }); | |
| } | |
| void ConfigureInput::ApplyProfile() { | |
| Settings::values.current_input_profile_index = ui->profile->currentIndex(); | |
| } | |
| void ConfigureInput::EmitInputKeysChanged() { | |
| emit InputKeysChanged(GetUsedKeyboardKeys()); | |
| } | |
| void ConfigureInput::OnHotkeysChanged(QList<QKeySequence> new_key_list) { | |
| hotkey_list = new_key_list; | |
| } | |
| QList<QKeySequence> ConfigureInput::GetUsedKeyboardKeys() { | |
| QList<QKeySequence> list; | |
| for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { | |
| const auto& button_param = buttons_param[button]; | |
| if (button_param.Get("engine", "") == "keyboard") { | |
| list << QKeySequence(button_param.Get("code", 0)); | |
| } | |
| } | |
| for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { | |
| const auto& analog_param = analogs_param[analog_id]; | |
| if (analog_param.Get("engine", "") == "analog_from_button") { | |
| for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { | |
| const Common::ParamPackage sub_button{ | |
| analog_param.Get(analog_sub_buttons[sub_button_id], "")}; | |
| list << QKeySequence(sub_button.Get("code", 0)); | |
| } | |
| } | |
| } | |
| return list; | |
| } | |
| void ConfigureInput::LoadConfiguration() { | |
| std::transform(Settings::values.current_input_profile.buttons.begin(), | |
| Settings::values.current_input_profile.buttons.end(), buttons_param.begin(), | |
| [](const std::string& str) { return Common::ParamPackage(str); }); | |
| std::transform(Settings::values.current_input_profile.analogs.begin(), | |
| Settings::values.current_input_profile.analogs.end(), analogs_param.begin(), | |
| [](const std::string& str) { return Common::ParamPackage(str); }); | |
| UpdateButtonLabels(); | |
| } | |
| 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])}; | |
| } | |
| 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]); | |
| } | |
| analogs_param[analog_id].Set("modifier_scale", 0.5f); | |
| } | |
| UpdateButtonLabels(); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(Settings::values.current_input_profile_index); | |
| } | |
| 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(); | |
| } | |
| for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { | |
| analogs_param[analog_id].Clear(); | |
| } | |
| UpdateButtonLabels(); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(Settings::values.current_input_profile_index); | |
| } | |
| void ConfigureInput::UpdateButtonLabels() { | |
| for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { | |
| if (button_map[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")); | |
| auto& param = analogs_param[analog_id]; | |
| auto* const analog_stick_slider = analog_map_deadzone_and_modifier_slider[analog_id]; | |
| auto* const analog_stick_slider_label = | |
| analog_map_deadzone_and_modifier_slider_label[analog_id]; | |
| if (param.Has("engine")) { | |
| const auto engine{param.Get("engine", "")}; | |
| if (engine == "sdl" || engine == "gcpad") { | |
| if (!param.Has("deadzone")) { | |
| param.Set("deadzone", 0.1f); | |
| } | |
| const auto slider_value = static_cast<int>(param.Get("deadzone", 0.1f) * 100); | |
| analog_stick_slider_label->setText(tr("Deadzone: %1%").arg(slider_value)); | |
| analog_stick_slider->setValue(slider_value); | |
| } else { | |
| if (!param.Has("modifier_scale")) { | |
| param.Set("modifier_scale", 0.5f); | |
| } | |
| const auto slider_value = static_cast<int>(param.Get("modifier_scale", 0.5f) * 100); | |
| analog_stick_slider_label->setText(tr("Modifier Scale: %1%").arg(slider_value)); | |
| analog_stick_slider->setValue(slider_value); | |
| } | |
| } | |
| } | |
| ui->buttonCircleMod->setText(AnalogToText(analogs_param[0], "modifier")); | |
| EmitInputKeysChanged(); | |
| } | |
| void ConfigureInput::MapFromButton(const Common::ParamPackage& params) { | |
| Common::ParamPackage aux_param; | |
| bool mapped = false; | |
| for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { | |
| aux_param = InputCommon::GetControllerButtonBinds(params, button_id); | |
| if (aux_param.Has("engine")) { | |
| buttons_param[button_id] = aux_param; | |
| mapped = true; | |
| } | |
| } | |
| for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { | |
| aux_param = InputCommon::GetControllerAnalogBinds(params, analog_id); | |
| if (aux_param.Has("engine")) { | |
| analogs_param[analog_id] = aux_param; | |
| mapped = true; | |
| } | |
| } | |
| if (!mapped) { | |
| QMessageBox::warning( | |
| this, tr("Warning"), | |
| tr("Auto mapping failed. Your controller may not have a corresponding mapping")); | |
| } | |
| } | |
| void ConfigureInput::AutoMap() { | |
| if (QMessageBox::information(this, tr("Information"), | |
| tr("After pressing OK, press any button on your joystick"), | |
| QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { | |
| return; | |
| } | |
| input_setter = [this](const Common::ParamPackage& params) { | |
| MapFromButton(params); | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| }; | |
| device_pollers = InputCommon::Polling::GetPollers(InputCommon::Polling::DeviceType::Button); | |
| want_keyboard_keys = false; | |
| for (auto& poller : device_pollers) { | |
| poller->Start(); | |
| } | |
| timeout_timer->start(5000); // Cancel after 5 seconds | |
| poll_timer->start(200); // Check for new inputs every 200ms | |
| } | |
| void ConfigureInput::HandleClick(QPushButton* button, | |
| std::function<void(const Common::ParamPackage&)> new_input_setter, | |
| InputCommon::Polling::DeviceType type) { | |
| previous_key_code = QKeySequence(button->text())[0].toCombined(); | |
| button->setText(tr("[press key]")); | |
| button->setFocus(); | |
| 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 ConfigureInput::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) { | |
| (*input_setter)(params); | |
| } | |
| UpdateButtonLabels(); | |
| input_setter.reset(); | |
| } | |
| void ConfigureInput::keyPressEvent(QKeyEvent* event) { | |
| if (!input_setter || !event) | |
| return; | |
| if (event->key() != Qt::Key_Escape && event->key() != previous_key_code) { | |
| if (want_keyboard_keys) { | |
| // Check if key is already bound | |
| if (hotkey_list.contains(QKeySequence(event->key())) || | |
| GetUsedKeyboardKeys().contains(QKeySequence(event->key()))) { | |
| SetPollingResult({}, true); | |
| QMessageBox::critical(this, tr("Error!"), | |
| tr("You're using a key that's already bound.")); | |
| return; | |
| } | |
| 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); | |
| previous_key_code = 0; | |
| } | |
| void ConfigureInput::RetranslateUI() { | |
| ui->retranslateUi(this); | |
| } | |
| void ConfigureInput::NewProfile() { | |
| const QString name = | |
| QInputDialog::getText(this, tr("New Profile"), tr("Enter the name for the new profile.")); | |
| if (name.isEmpty()) { | |
| return; | |
| } | |
| if (IsProfileNameDuplicate(name)) { | |
| WarnProposedProfileNameIsDuplicate(); | |
| return; | |
| } | |
| ApplyConfiguration(); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| Settings::CreateProfile(name.toStdString()); | |
| ui->profile->addItem(name); | |
| ui->profile->setCurrentIndex(Settings::values.current_input_profile_index); | |
| LoadConfiguration(); | |
| ui->buttonDelete->setEnabled(ui->profile->count() > 1); | |
| } | |
| void ConfigureInput::DeleteProfile() { | |
| const auto answer = QMessageBox::question( | |
| this, tr("Delete Profile"), tr("Delete profile %1?").arg(ui->profile->currentText())); | |
| if (answer != QMessageBox::Yes) { | |
| return; | |
| } | |
| const int index = ui->profile->currentIndex(); | |
| ui->profile->removeItem(index); | |
| ui->profile->setCurrentIndex(0); | |
| Settings::DeleteProfile(index); | |
| LoadConfiguration(); | |
| ui->buttonDelete->setEnabled(ui->profile->count() > 1); | |
| } | |
| void ConfigureInput::RenameProfile() { | |
| const QString new_name = QInputDialog::getText(this, tr("Rename Profile"), tr("New name:")); | |
| if (new_name.isEmpty()) { | |
| return; | |
| } | |
| if (IsProfileNameDuplicate(new_name)) { | |
| WarnProposedProfileNameIsDuplicate(); | |
| return; | |
| } | |
| ui->profile->setItemText(ui->profile->currentIndex(), new_name); | |
| Settings::RenameCurrentProfile(new_name.toStdString()); | |
| Settings::SaveProfile(ui->profile->currentIndex()); | |
| } | |
| bool ConfigureInput::IsProfileNameDuplicate(const QString& name) const { | |
| return ui->profile->findText(name, Qt::MatchFixedString | Qt::MatchCaseSensitive) != -1; | |
| } | |
| void ConfigureInput::WarnProposedProfileNameIsDuplicate() { | |
| QMessageBox::warning(this, tr("Duplicate profile name"), | |
| tr("Profile name already exists. Please choose a different name.")); | |
| } | |