From d2f9412cf1717f884855af22793f3a1e5815c967 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 8 Jan 2022 23:23:40 -0600 Subject: yuzu: Add custom ringcon configuration --- src/yuzu/CMakeLists.txt | 3 + src/yuzu/configuration/config.cpp | 34 ++ src/yuzu/configuration/config.h | 3 + src/yuzu/configuration/configure_input.cpp | 5 + .../configuration/configure_input_advanced.cpp | 9 +- src/yuzu/configuration/configure_input_advanced.h | 1 + src/yuzu/configuration/configure_input_advanced.ui | 14 + src/yuzu/configuration/configure_ringcon.cpp | 424 +++++++++++++++++++++ src/yuzu/configuration/configure_ringcon.h | 85 +++++ src/yuzu/configuration/configure_ringcon.ui | 278 ++++++++++++++ 10 files changed, 855 insertions(+), 1 deletion(-) create mode 100644 src/yuzu/configuration/configure_ringcon.cpp create mode 100644 src/yuzu/configuration/configure_ringcon.h create mode 100644 src/yuzu/configuration/configure_ringcon.ui (limited to 'src/yuzu') diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index b1467d016..2ee21f751 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -99,6 +99,9 @@ add_executable(yuzu configuration/configure_profile_manager.cpp configuration/configure_profile_manager.h configuration/configure_profile_manager.ui + configuration/configure_ringcon.cpp + configuration/configure_ringcon.h + configuration/configure_ringcon.ui configuration/configure_network.cpp configuration/configure_network.h configuration/configure_network.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index d2e735f48..ac26b885b 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -60,6 +60,11 @@ const std::array Config::default_stick_mod = { 0, }; +const std::array Config::default_ringcon_analogs{{ + Qt::Key_A, + Qt::Key_D, +}}; + // This shouldn't have anything except static initializers (no functions). So // QKeySequence(...).toString() is NOT ALLOWED HERE. // This must be in alphabetical order according to action name as it must have the same order as @@ -346,6 +351,23 @@ void Config::ReadTouchscreenValues() { ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt(); } +void Config::ReadHidbusValues() { + Settings::values.enable_ring_controller = + ReadSetting(QStringLiteral("enable_ring_controller"), true).toBool(); + + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + auto& ringcon_analogs = Settings::values.ringcon_analogs; + + ringcon_analogs = + qt_config->value(QStringLiteral("ring_controller"), QString::fromStdString(default_param)) + .toString() + .toStdString(); + if (ringcon_analogs.empty()) { + ringcon_analogs = default_param; + } +} + void Config::ReadAudioValues() { qt_config->beginGroup(QStringLiteral("Audio")); @@ -369,6 +391,7 @@ void Config::ReadControlValues() { ReadMouseValues(); ReadTouchscreenValues(); ReadMotionTouchValues(); + ReadHidbusValues(); #ifdef _WIN32 ReadBasicSetting(Settings::values.enable_raw_input); @@ -962,6 +985,16 @@ void Config::SaveMotionTouchValues() { qt_config->endArray(); } +void Config::SaveHidbusValues() { + WriteBasicSetting(Settings::values.enable_ring_controller); + + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + WriteSetting(QStringLiteral("ring_controller"), + QString::fromStdString(Settings::values.ringcon_analogs), + QString::fromStdString(default_param)); +} + void Config::SaveValues() { if (global) { SaveControlValues(); @@ -1002,6 +1035,7 @@ void Config::SaveControlValues() { SaveMouseValues(); SaveTouchscreenValues(); SaveMotionTouchValues(); + SaveHidbusValues(); WriteGlobalSetting(Settings::values.use_docked_mode); WriteGlobalSetting(Settings::values.vibration_enabled); diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index ae3e36a11..f0ab6bdaa 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -42,6 +42,7 @@ public: static const std::array default_motions; static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; static const std::array default_stick_mod; + static const std::array default_ringcon_analogs; static const std::array default_mouse_buttons; static const std::array default_keyboard_keys; @@ -66,6 +67,7 @@ private: void ReadMouseValues(); void ReadTouchscreenValues(); void ReadMotionTouchValues(); + void ReadHidbusValues(); // Read functions bases off the respective config section names. void ReadAudioValues(); @@ -93,6 +95,7 @@ private: void SaveMouseValues(); void SaveTouchscreenValues(); void SaveMotionTouchValues(); + void SaveHidbusValues(); // Save functions based off the respective config section names. void SaveAudioValues(); diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 4ca74a5f7..73d7ba24b 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -20,6 +20,7 @@ #include "yuzu/configuration/configure_input_advanced.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_motion_touch.h" +#include "yuzu/configuration/configure_ringcon.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" #include "yuzu/configuration/configure_vibration.h" #include "yuzu/configuration/input_profiles.h" @@ -158,6 +159,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, [this, input_subsystem] { CallConfigureDialog(*this, input_subsystem); }); + connect(advanced, &ConfigureInputAdvanced::CallRingControllerDialog, + [this, input_subsystem, &hid_core] { + CallConfigureDialog(*this, input_subsystem, hid_core); + }); connect(ui->vibrationButton, &QPushButton::clicked, [this, &hid_core] { CallConfigureDialog(*this, hid_core); }); diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index 20fc2599d..8fd1f4a38 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -79,13 +79,17 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) &ConfigureInputAdvanced::UpdateUIEnabled); connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this, &ConfigureInputAdvanced::UpdateUIEnabled); + connect(ui->enable_ring_controller, &QCheckBox::stateChanged, this, + &ConfigureInputAdvanced::UpdateUIEnabled); connect(ui->debug_configure, &QPushButton::clicked, this, [this] { CallDebugControllerDialog(); }); connect(ui->touchscreen_advanced, &QPushButton::clicked, this, [this] { CallTouchscreenConfigDialog(); }); connect(ui->buttonMotionTouch, &QPushButton::clicked, this, - &ConfigureInputAdvanced::CallMotionTouchConfigDialog); + [this] { CallMotionTouchConfigDialog(); }); + connect(ui->ring_controller_configure, &QPushButton::clicked, this, + [this] { CallRingControllerDialog(); }); #ifndef _WIN32 ui->enable_raw_input->setVisible(false); @@ -132,6 +136,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); Settings::values.controller_navigation = ui->controller_navigation->isChecked(); + Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); } void ConfigureInputAdvanced::LoadConfiguration() { @@ -164,6 +169,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); + ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); UpdateUIEnabled(); } @@ -185,4 +191,5 @@ void ConfigureInputAdvanced::UpdateUIEnabled() { ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); ui->mouse_panning->setEnabled(!ui->mouse_enabled->isChecked()); ui->mouse_panning_sensitivity->setEnabled(!ui->mouse_enabled->isChecked()); + ui->ring_controller_configure->setEnabled(ui->enable_ring_controller->isChecked()); } diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h index 3083d55c1..4472cb846 100644 --- a/src/yuzu/configuration/configure_input_advanced.h +++ b/src/yuzu/configuration/configure_input_advanced.h @@ -29,6 +29,7 @@ signals: void CallMouseConfigDialog(); void CallTouchscreenConfigDialog(); void CallMotionTouchConfigDialog(); + void CallRingControllerDialog(); private: void changeEvent(QEvent* event) override; diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 66f2075f2..14403cb10 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2603,6 +2603,20 @@ + + + + Ring Controller + + + + + + + Configure + + + diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp new file mode 100644 index 000000000..144e2b83f --- /dev/null +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -0,0 +1,424 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include + +#include "core/hid/emulated_devices.h" +#include "core/hid/hid_core.h" +#include "input_common/drivers/keyboard.h" +#include "input_common/drivers/mouse.h" +#include "input_common/main.h" +#include "ui_configure_ringcon.h" +#include "yuzu/bootmanager.h" +#include "yuzu/configuration/config.h" +#include "yuzu/configuration/configure_ringcon.h" + +const std::array + ConfigureRingController::analog_sub_buttons{{ + "left", + "right", + }}; + +namespace { + +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(); + } +} + +QString GetButtonName(Common::Input::ButtonNames button_name) { + switch (button_name) { + case Common::Input::ButtonNames::ButtonLeft: + return QObject::tr("Left"); + case Common::Input::ButtonNames::ButtonRight: + return QObject::tr("Right"); + case Common::Input::ButtonNames::ButtonDown: + return QObject::tr("Down"); + case Common::Input::ButtonNames::ButtonUp: + return QObject::tr("Up"); + case Common::Input::ButtonNames::TriggerZ: + return QObject::tr("Z"); + case Common::Input::ButtonNames::TriggerR: + return QObject::tr("R"); + case Common::Input::ButtonNames::TriggerL: + return QObject::tr("L"); + case Common::Input::ButtonNames::ButtonA: + return QObject::tr("A"); + case Common::Input::ButtonNames::ButtonB: + return QObject::tr("B"); + case Common::Input::ButtonNames::ButtonX: + return QObject::tr("X"); + case Common::Input::ButtonNames::ButtonY: + return QObject::tr("Y"); + case Common::Input::ButtonNames::ButtonStart: + return QObject::tr("Start"); + case Common::Input::ButtonNames::L1: + return QObject::tr("L1"); + case Common::Input::ButtonNames::L2: + return QObject::tr("L2"); + case Common::Input::ButtonNames::L3: + return QObject::tr("L3"); + case Common::Input::ButtonNames::R1: + return QObject::tr("R1"); + case Common::Input::ButtonNames::R2: + return QObject::tr("R2"); + case Common::Input::ButtonNames::R3: + return QObject::tr("R3"); + case Common::Input::ButtonNames::Circle: + return QObject::tr("Circle"); + case Common::Input::ButtonNames::Cross: + return QObject::tr("Cross"); + case Common::Input::ButtonNames::Square: + return QObject::tr("Square"); + case Common::Input::ButtonNames::Triangle: + return QObject::tr("Triangle"); + case Common::Input::ButtonNames::Share: + return QObject::tr("Share"); + case Common::Input::ButtonNames::Options: + return QObject::tr("Options"); + default: + return QObject::tr("[undefined]"); + } +} + +void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackage& analog_param, + const std::string& button_name) { + // The poller returned a complete axis, so set all the buttons + if (input_param.Has("axis_x") && input_param.Has("axis_y")) { + analog_param = input_param; + return; + } + // Check if the current configuration has either no engine or an axis binding. + // Clears out the old binding and adds one with analog_from_button. + if (!analog_param.Has("engine") || analog_param.Has("axis_x") || analog_param.Has("axis_y")) { + analog_param = { + {"engine", "analog_from_button"}, + }; + } + analog_param.Set(button_name, input_param.Serialize()); +} +} // namespace + +ConfigureRingController::ConfigureRingController(QWidget* parent, + InputCommon::InputSubsystem* input_subsystem_, + Core::HID::HIDCore& hid_core_) + : QDialog(parent), timeout_timer(std::make_unique()), + poll_timer(std::make_unique()), input_subsystem{input_subsystem_}, + + ui(std::make_unique()) { + ui->setupUi(this); + + analog_map_buttons = { + ui->buttonRingAnalogPull, + ui->buttonRingAnalogPush, + }; + + emulated_device = hid_core_.GetEmulatedDevices(); + emulated_device->SaveCurrentConfig(); + emulated_device->EnableConfiguration(); + + LoadConfiguration(); + + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { + auto* const analog_button = analog_map_buttons[sub_button_id]; + + if (analog_button == nullptr) { + continue; + } + + connect(analog_button, &QPushButton::clicked, [=, this] { + HandleClick( + analog_map_buttons[sub_button_id], + [=, this](const Common::ParamPackage& params) { + Common::ParamPackage param = emulated_device->GetRingParam(); + SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]); + emulated_device->SetRingParam(param); + }, + InputCommon::Polling::InputType::Stick); + }); + + analog_button->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(analog_button, &QPushButton::customContextMenuRequested, + [=, this](const QPoint& menu_location) { + QMenu context_menu; + Common::ParamPackage param = emulated_device->GetRingParam(); + context_menu.addAction(tr("Clear"), [&] { + emulated_device->SetRingParam({}); + analog_map_buttons[sub_button_id]->setText(tr("[not set]")); + }); + context_menu.addAction(tr("Invert axis"), [&] { + const bool invert_value = param.Get("invert_x", "+") == "-"; + const std::string invert_str = invert_value ? "+" : "-"; + param.Set("invert_x", invert_str); + emulated_device->SetRingParam(param); + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; + ++sub_button_id) { + analog_map_buttons[sub_button_id]->setText( + AnalogToText(param, analog_sub_buttons[sub_button_id])); + } + }); + context_menu.exec( + analog_map_buttons[sub_button_id]->mapToGlobal(menu_location)); + }); + } + + connect(ui->sliderRingAnalogDeadzone, &QSlider::valueChanged, [=, this] { + Common::ParamPackage param = emulated_device->GetRingParam(); + const auto slider_value = ui->sliderRingAnalogDeadzone->value(); + ui->labelRingAnalogDeadzone->setText(tr("Deadzone: %1%").arg(slider_value)); + param.Set("deadzone", slider_value / 100.0f); + emulated_device->SetRingParam(param); + }); + + connect(ui->restore_defaults_button, &QPushButton::clicked, this, + &ConfigureRingController::RestoreDefaults); + + timeout_timer->setSingleShot(true); + connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); + + connect(poll_timer.get(), &QTimer::timeout, [this] { + const auto& params = input_subsystem->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + }); + + resize(0, 0); +} + +ConfigureRingController::~ConfigureRingController() { + emulated_device->DisableConfiguration(); +}; + +void ConfigureRingController::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QDialog::changeEvent(event); +} + +void ConfigureRingController::RetranslateUI() { + ui->retranslateUi(this); +} + +void ConfigureRingController::UpdateUI() { + RetranslateUI(); + const Common::ParamPackage param = emulated_device->GetRingParam(); + + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { + auto* const analog_button = analog_map_buttons[sub_button_id]; + + if (analog_button == nullptr) { + continue; + } + + analog_button->setText(AnalogToText(param, analog_sub_buttons[sub_button_id])); + } + + const auto deadzone_label = ui->labelRingAnalogDeadzone; + const auto deadzone_slider = ui->sliderRingAnalogDeadzone; + + int slider_value = static_cast(param.Get("deadzone", 0.15f) * 100); + deadzone_label->setText(tr("Deadzone: %1%").arg(slider_value)); + deadzone_slider->setValue(slider_value); +} + +void ConfigureRingController::ApplyConfiguration() { + emulated_device->DisableConfiguration(); + emulated_device->SaveCurrentConfig(); + emulated_device->EnableConfiguration(); +} + +void ConfigureRingController::LoadConfiguration() { + UpdateUI(); +} + +void ConfigureRingController::RestoreDefaults() { + const std::string default_ring_string = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, Config::default_ringcon_analogs[0], Config::default_ringcon_analogs[1], 0, 0.05f); + emulated_device->SetRingParam(Common::ParamPackage(default_ring_string)); + UpdateUI(); +} + +void ConfigureRingController::HandleClick( + QPushButton* button, std::function new_input_setter, + InputCommon::Polling::InputType type) { + button->setText(tr("[waiting]")); + button->setFocus(); + + input_setter = new_input_setter; + + input_subsystem->BeginMapping(type); + + QWidget::grabMouse(); + QWidget::grabKeyboard(); + + timeout_timer->start(2500); // Cancel after 2.5 seconds + poll_timer->start(25); // Check for new inputs every 25ms +} + +void ConfigureRingController::SetPollingResult(const Common::ParamPackage& params, bool abort) { + timeout_timer->stop(); + poll_timer->stop(); + input_subsystem->StopMapping(); + + QWidget::releaseMouse(); + QWidget::releaseKeyboard(); + + if (!abort) { + (*input_setter)(params); + } + + UpdateUI(); + + input_setter = std::nullopt; +} + +bool ConfigureRingController::IsInputAcceptable(const Common::ParamPackage& params) const { + return true; +} + +void ConfigureRingController::mousePressEvent(QMouseEvent* event) { + if (!input_setter || !event) { + return; + } + + const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); + input_subsystem->GetMouse()->PressButton(0, 0, 0, 0, button); +} + +void ConfigureRingController::keyPressEvent(QKeyEvent* event) { + event->ignore(); + if (!input_setter || !event) { + return; + } + if (event->key() != Qt::Key_Escape) { + input_subsystem->GetKeyboard()->PressKey(event->key()); + } +} + +QString ConfigureRingController::ButtonToText(const Common::ParamPackage& param) { + if (!param.Has("engine")) { + return QObject::tr("[not set]"); + } + + const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); + const QString inverted = QString::fromStdString(param.Get("inverted", false) ? "!" : ""); + const auto common_button_name = input_subsystem->GetButtonName(param); + + // Retrieve the names from Qt + if (param.Get("engine", "") == "keyboard") { + const QString button_str = GetKeyName(param.Get("code", 0)); + return QObject::tr("%1%2").arg(toggle, button_str); + } + + if (common_button_name == Common::Input::ButtonNames::Invalid) { + return QObject::tr("[invalid]"); + } + + if (common_button_name == Common::Input::ButtonNames::Engine) { + return QString::fromStdString(param.Get("engine", "")); + } + + if (common_button_name == Common::Input::ButtonNames::Value) { + if (param.Has("hat")) { + const QString hat = QString::fromStdString(param.Get("direction", "")); + return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat); + } + if (param.Has("axis")) { + const QString axis = QString::fromStdString(param.Get("axis", "")); + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, axis); + } + if (param.Has("axis_x") && param.Has("axis_y") && param.Has("axis_z")) { + const QString axis_x = QString::fromStdString(param.Get("axis_x", "")); + const QString axis_y = QString::fromStdString(param.Get("axis_y", "")); + const QString axis_z = QString::fromStdString(param.Get("axis_z", "")); + return QObject::tr("%1%2Axis %3,%4,%5").arg(toggle, inverted, axis_x, axis_y, axis_z); + } + if (param.Has("motion")) { + const QString motion = QString::fromStdString(param.Get("motion", "")); + return QObject::tr("%1%2Motion %3").arg(toggle, inverted, motion); + } + if (param.Has("button")) { + const QString button = QString::fromStdString(param.Get("button", "")); + return QObject::tr("%1%2Button %3").arg(toggle, inverted, button); + } + } + + QString button_name = GetButtonName(common_button_name); + if (param.Has("hat")) { + return QObject::tr("%1%2Hat %3").arg(toggle, inverted, button_name); + } + if (param.Has("axis")) { + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); + } + if (param.Has("motion")) { + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); + } + if (param.Has("button")) { + return QObject::tr("%1%2Button %3").arg(toggle, inverted, button_name); + } + + return QObject::tr("[unknown]"); +} + +QString ConfigureRingController::AnalogToText(const Common::ParamPackage& param, + const std::string& dir) { + if (!param.Has("engine")) { + return QObject::tr("[not set]"); + } + + if (param.Get("engine", "") == "analog_from_button") { + return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); + } + + if (!param.Has("axis_x") || !param.Has("axis_y")) { + return QObject::tr("[unknown]"); + } + + const auto engine_str = param.Get("engine", ""); + const QString axis_x_str = QString::fromStdString(param.Get("axis_x", "")); + const QString axis_y_str = QString::fromStdString(param.Get("axis_y", "")); + const bool invert_x = param.Get("invert_x", "+") == "-"; + const bool invert_y = param.Get("invert_y", "+") == "-"; + + if (dir == "modifier") { + return QObject::tr("[unused]"); + } + + if (dir == "left") { + const QString invert_x_str = QString::fromStdString(invert_x ? "+" : "-"); + return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); + } + if (dir == "right") { + const QString invert_x_str = QString::fromStdString(invert_x ? "-" : "+"); + return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); + } + if (dir == "up") { + const QString invert_y_str = QString::fromStdString(invert_y ? "-" : "+"); + return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); + } + if (dir == "down") { + const QString invert_y_str = QString::fromStdString(invert_y ? "+" : "-"); + return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); + } + + return QObject::tr("[unknown]"); +} \ No newline at end of file diff --git a/src/yuzu/configuration/configure_ringcon.h b/src/yuzu/configuration/configure_ringcon.h new file mode 100644 index 000000000..cf9e54f09 --- /dev/null +++ b/src/yuzu/configuration/configure_ringcon.h @@ -0,0 +1,85 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +namespace InputCommon { +class InputSubsystem; +} // namespace InputCommon + +namespace Core::HID { +class HIDCore; +class EmulatedDevices; +} // namespace Core::HID + +namespace Ui { +class ConfigureRingController; +} // namespace Ui + +class ConfigureRingController : public QDialog { + Q_OBJECT + +public: + explicit ConfigureRingController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_, + Core::HID::HIDCore& hid_core_); + ~ConfigureRingController() override; + + void ApplyConfiguration(); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + + void UpdateUI(); + + /// Load configuration settings. + void LoadConfiguration(); + + /// Restore all buttons to their default values. + void RestoreDefaults(); + + /// Called when the button was pressed. + void HandleClick(QPushButton* button, + std::function new_input_setter, + InputCommon::Polling::InputType type); + + /// Finish polling and configure input using the input_setter. + void SetPollingResult(const Common::ParamPackage& params, bool abort); + + /// Checks whether a given input can be accepted. + bool IsInputAcceptable(const Common::ParamPackage& params) const; + + /// Handle mouse button press events. + void mousePressEvent(QMouseEvent* event) override; + + /// Handle key press events. + void keyPressEvent(QKeyEvent* event) override; + + QString ButtonToText(const Common::ParamPackage& param); + + QString AnalogToText(const Common::ParamPackage& param, const std::string& dir); + + static constexpr int ANALOG_SUB_BUTTONS_NUM = 2; + + // A group of four QPushButtons represent one analog input. The buttons each represent left, + // right, respectively. + std::array analog_map_buttons; + + static const std::array analog_sub_buttons; + + std::unique_ptr timeout_timer; + std::unique_ptr poll_timer; + + /// This will be the the setting function when an input is awaiting configuration. + std::optional> input_setter; + + InputCommon::InputSubsystem* input_subsystem; + Core::HID::EmulatedDevices* emulated_device; + + std::unique_ptr ui; +}; diff --git a/src/yuzu/configuration/configure_ringcon.ui b/src/yuzu/configuration/configure_ringcon.ui new file mode 100644 index 000000000..9ec634dd4 --- /dev/null +++ b/src/yuzu/configuration/configure_ringcon.ui @@ -0,0 +1,278 @@ + + + ConfigureRingController + + + + 0 + 0 + 298 + 339 + + + + Configure Ring Controller + + + + + + + 280 + 0 + + + + If you want to use this controller configure player 1 as right controller and player 2 as dual joycon before starting the game to allow this controller to be detected properly. + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Ring Sensor Parameters + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + 0 + + + QLayout::SetDefaultConstraint + + + 3 + + + 6 + + + 3 + + + 0 + + + + + 3 + + + + + Pull + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Pull + + + + + + + + + + Push + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Push + + + + + + + + + + + + 3 + + + QLayout::SetDefaultConstraint + + + 0 + + + 10 + + + 0 + + + 3 + + + + + + + Deadzone: 0% + + + Qt::AlignHCenter + + + + + + + + + 100 + + + Qt::Horizontal + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Restore Defaults + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + ConfigureRingController + accept() + + + buttonBox + rejected() + ConfigureRingController + reject() + + + -- cgit v1.2.3 From 46e1c5bc373734e29842ad1781a1ff266a4cd43d Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 18 Jan 2022 18:45:57 -0600 Subject: yuzu: Call ignore event after ensuring it's initialized --- src/yuzu/configuration/configure_input_player.cpp | 2 +- src/yuzu/configuration/configure_ringcon.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/yuzu') diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 8ef3596dd..291e37acf 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -1407,10 +1407,10 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { } void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { - event->ignore(); if (!input_setter || !event) { return; } + event->ignore(); if (event->key() != Qt::Key_Escape) { input_subsystem->GetKeyboard()->PressKey(event->key()); } diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 144e2b83f..f1cdd4fed 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -305,10 +305,10 @@ void ConfigureRingController::mousePressEvent(QMouseEvent* event) { } void ConfigureRingController::keyPressEvent(QKeyEvent* event) { - event->ignore(); if (!input_setter || !event) { return; } + event->ignore(); if (event->key() != Qt::Key_Escape) { input_subsystem->GetKeyboard()->PressKey(event->key()); } -- cgit v1.2.3