From e6bd1fd1b8487e421f71d43b6073ee56de1a043d Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Tue, 14 Jul 2020 19:01:36 +0200 Subject: [PATCH 1/4] yuzu: Add motion and touch configuration --- dist/qt_themes/qdarkstyle/style.qss | 5 + .../service/hid/controllers/touchscreen.cpp | 12 +- .../hle/service/hid/controllers/touchscreen.h | 1 + src/core/settings.h | 12 +- src/input_common/CMakeLists.txt | 2 + src/input_common/main.cpp | 9 + src/input_common/main.h | 3 + src/input_common/touch_from_button.cpp | 49 ++ src/input_common/touch_from_button.h | 25 + src/yuzu/CMakeLists.txt | 7 + src/yuzu/configuration/config.cpp | 68 ++ src/yuzu/configuration/configure_input.cpp | 6 + .../configuration/configure_motion_touch.cpp | 304 +++++++++ .../configuration/configure_motion_touch.h | 77 +++ .../configuration/configure_motion_touch.ui | 327 ++++++++++ .../configure_touch_from_button.cpp | 612 ++++++++++++++++++ .../configure_touch_from_button.h | 86 +++ .../configure_touch_from_button.ui | 231 +++++++ .../configuration/configure_touch_widget.h | 61 ++ 19 files changed, 1894 insertions(+), 3 deletions(-) create mode 100644 src/input_common/touch_from_button.cpp create mode 100644 src/input_common/touch_from_button.h create mode 100644 src/yuzu/configuration/configure_motion_touch.cpp create mode 100644 src/yuzu/configuration/configure_motion_touch.h create mode 100644 src/yuzu/configuration/configure_motion_touch.ui create mode 100644 src/yuzu/configuration/configure_touch_from_button.cpp create mode 100644 src/yuzu/configuration/configure_touch_from_button.h create mode 100644 src/yuzu/configuration/configure_touch_from_button.ui create mode 100644 src/yuzu/configuration/configure_touch_widget.h diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss index 7755426f83..16218f0c22 100644 --- a/dist/qt_themes/qdarkstyle/style.qss +++ b/dist/qt_themes/qdarkstyle/style.qss @@ -1371,3 +1371,8 @@ QGroupBox#vibrationGroup::title { padding-left: 1px; padding-right: 1px; } + +/* touchscreen mapping widget */ +TouchScreenPreview { + qproperty-dotHighlightColor: #3daee9; +} diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index e326f8f5c4..0df395e85b 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -40,9 +40,14 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin cur_entry.sampling_number = last_entry.sampling_number + 1; cur_entry.sampling_number2 = cur_entry.sampling_number; - const auto [x, y, pressed] = touch_device->GetStatus(); + bool pressed = false; + float x, y; + std::tie(x, y, pressed) = touch_device->GetStatus(); auto& touch_entry = cur_entry.states[0]; touch_entry.attribute.raw = 0; + if (!pressed && touch_btn_device) { + std::tie(x, y, pressed) = touch_btn_device->GetStatus(); + } if (pressed && Settings::values.touchscreen.enabled) { touch_entry.x = static_cast(x * Layout::ScreenUndocked::Width); touch_entry.y = static_cast(y * Layout::ScreenUndocked::Height); @@ -63,5 +68,10 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin void Controller_Touchscreen::OnLoadInputDevices() { touch_device = Input::CreateDevice(Settings::values.touchscreen.device); + if (Settings::values.use_touch_from_button) { + touch_btn_device = Input::CreateDevice("engine:touch_from_button"); + } else { + touch_btn_device.reset(); + } } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index a1d97269e0..4d9042adc2 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -68,6 +68,7 @@ private: "TouchScreenSharedMemory is an invalid size"); TouchScreenSharedMemory shared_memory{}; std::unique_ptr touch_device; + std::unique_ptr touch_btn_device; s64_le last_touch{}; }; } // namespace Service::HID diff --git a/src/core/settings.h b/src/core/settings.h index 732c6a8948..80f0d95a7e 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -67,6 +67,11 @@ private: Type local{}; }; +struct TouchFromButtonMap { + std::string name; + std::vector buttons; +}; + struct Values { // Audio std::string audio_device_id; @@ -145,15 +150,18 @@ struct Values { ButtonsRaw debug_pad_buttons; AnalogsRaw debug_pad_analogs; - std::string motion_device; - bool vibration_enabled; + std::string motion_device; + std::string touch_device; TouchscreenInput touchscreen; std::atomic_bool is_device_reload_pending{true}; + bool use_touch_from_button; + int touch_from_button_map_index; std::string udp_input_address; u16 udp_input_port; u8 udp_pad_index; + std::vector touch_from_button_maps; // Data Storage bool use_virtual_sd; diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 56267c8a81..32433df252 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -9,6 +9,8 @@ add_library(input_common STATIC motion_emu.h settings.cpp settings.h + touch_from_button.cpp + touch_from_button.h gcadapter/gc_adapter.cpp gcadapter/gc_adapter.h gcadapter/gc_poller.cpp diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 57e7a25fe8..f9d7b408f0 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -11,6 +11,7 @@ #include "input_common/keyboard.h" #include "input_common/main.h" #include "input_common/motion_emu.h" +#include "input_common/touch_from_button.h" #include "input_common/udp/udp.h" #ifdef HAVE_SDL2 #include "input_common/sdl/sdl.h" @@ -32,6 +33,8 @@ struct InputSubsystem::Impl { std::make_shared()); motion_emu = std::make_shared(); Input::RegisterFactory("motion_emu", motion_emu); + Input::RegisterFactory("touch_from_button", + std::make_shared()); #ifdef HAVE_SDL2 sdl = SDL::Init(); @@ -46,6 +49,7 @@ struct InputSubsystem::Impl { Input::UnregisterFactory("analog_from_button"); Input::UnregisterFactory("motion_emu"); motion_emu.reset(); + Input::UnregisterFactory("touch_from_button"); #ifdef HAVE_SDL2 sdl.reset(); #endif @@ -171,6 +175,11 @@ const GCButtonFactory* InputSubsystem::GetGCButtons() const { return impl->gcbuttons.get(); } +void ReloadInputDevices() { + if (udp) + udp->ReloadUDPClient(); +} + std::vector> InputSubsystem::GetPollers( Polling::DeviceType type) const { #ifdef HAVE_SDL2 diff --git a/src/input_common/main.h b/src/input_common/main.h index 58e5dc2500..269735c430 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -21,6 +21,9 @@ namespace Settings::NativeButton { enum Values : int; } +/// Reloads the input devices +void ReloadInputDevices(); + namespace InputCommon { namespace Polling { diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp new file mode 100644 index 0000000000..8e7f902535 --- /dev/null +++ b/src/input_common/touch_from_button.cpp @@ -0,0 +1,49 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/settings.h" +#include "input_common/touch_from_button.h" + +namespace InputCommon { + +class TouchFromButtonDevice final : public Input::TouchDevice { +public: + TouchFromButtonDevice() { + for (const auto& config_entry : + Settings::values.touch_from_button_maps[Settings::values.touch_from_button_map_index] + .buttons) { + const Common::ParamPackage package{config_entry}; + map.emplace_back( + Input::CreateDevice(config_entry), + std::clamp(package.Get("x", 0), 0, static_cast(Layout::ScreenUndocked::Width)), + std::clamp(package.Get("y", 0), 0, + static_cast(Layout::ScreenUndocked::Height))); + } + } + + std::tuple GetStatus() const override { + for (const auto& m : map) { + const bool state = std::get<0>(m)->GetStatus(); + if (state) { + const float x = static_cast(std::get<1>(m)) / + static_cast(Layout::ScreenUndocked::Width); + const float y = static_cast(std::get<2>(m)) / + static_cast(Layout::ScreenUndocked::Height); + return std::make_tuple(x, y, true); + } + } + return std::make_tuple(0.0f, 0.0f, false); + } + +private: + std::vector, int, int>> map; // button, x, y +}; + +std::unique_ptr TouchFromButtonFactory::Create( + const Common::ParamPackage& params) { + + return std::make_unique(); +} + +} // namespace InputCommon diff --git a/src/input_common/touch_from_button.h b/src/input_common/touch_from_button.h new file mode 100644 index 0000000000..cfb82f108f --- /dev/null +++ b/src/input_common/touch_from_button.h @@ -0,0 +1,25 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "core/frontend/framebuffer_layout.h" +#include "core/frontend/input.h" + +namespace InputCommon { + +/** + * A touch device factory that takes a list of button devices and combines them into a touch device. + */ +class TouchFromButtonFactory final : public Input::Factory { +public: + /** + * Creates a touch device from a list of button devices + * @param unused + */ + std::unique_ptr Create(const Common::ParamPackage& params) override; +}; + +} // namespace InputCommon diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 6987e85e17..3ea4e56017 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -68,6 +68,9 @@ add_executable(yuzu configuration/configure_input_advanced.cpp configuration/configure_input_advanced.h configuration/configure_input_advanced.ui + configuration/configure_motion_touch.cpp + configuration/configure_motion_touch.h + configuration/configure_motion_touch.ui configuration/configure_mouse_advanced.cpp configuration/configure_mouse_advanced.h configuration/configure_mouse_advanced.ui @@ -86,9 +89,13 @@ add_executable(yuzu configuration/configure_system.cpp configuration/configure_system.h configuration/configure_system.ui + configuration/configure_touch_from_button.cpp + configuration/configure_touch_from_button.h + configuration/configure_touch_from_button.ui configuration/configure_touchscreen_advanced.cpp configuration/configure_touchscreen_advanced.h configuration/configure_touchscreen_advanced.ui + configuration/configure_touch_widget.h configuration/configure_ui.cpp configuration/configure_ui.h configuration/configure_ui.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 588bbd677d..ead19a870a 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -423,11 +423,54 @@ void Config::ReadControlValues() { Settings::values.vibration_enabled = ReadSetting(QStringLiteral("vibration_enabled"), true).toBool(); + + int num_touch_from_button_maps = + qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); + + if (num_touch_from_button_maps > 0) { + const auto append_touch_from_button_map = [this] { + Settings::TouchFromButtonMap map; + map.name = ReadSetting(QStringLiteral("name"), QStringLiteral("default")) + .toString() + .toStdString(); + const int num_touch_maps = qt_config->beginReadArray(QStringLiteral("entries")); + map.buttons.reserve(num_touch_maps); + for (int i = 0; i < num_touch_maps; i++) { + qt_config->setArrayIndex(i); + std::string touch_mapping = + ReadSetting(QStringLiteral("bind")).toString().toStdString(); + map.buttons.emplace_back(std::move(touch_mapping)); + } + qt_config->endArray(); // entries + Settings::values.touch_from_button_maps.emplace_back(std::move(map)); + }; + + for (int i = 0; i < num_touch_from_button_maps; ++i) { + qt_config->setArrayIndex(i); + append_touch_from_button_map(); + } + } else { + Settings::values.touch_from_button_maps.emplace_back( + Settings::TouchFromButtonMap{"default", {}}); + num_touch_from_button_maps = 1; + } + qt_config->endArray(); + Settings::values.motion_device = ReadSetting(QStringLiteral("motion_device"), QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")) .toString() .toStdString(); + Settings::values.touch_device = + ReadSetting(QStringLiteral("touch_device"), QStringLiteral("engine:emu_window")) + .toString() + .toStdString(); + Settings::values.use_touch_from_button = + ReadSetting(QStringLiteral("use_touch_from_button"), false).toBool(); + Settings::values.touch_from_button_map_index = + ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt(); + Settings::values.touch_from_button_map_index = + std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1); Settings::values.udp_input_address = ReadSetting(QStringLiteral("udp_input_address"), QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)) @@ -981,7 +1024,14 @@ void Config::SaveControlValues() { WriteSetting(QStringLiteral("motion_device"), QString::fromStdString(Settings::values.motion_device), QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")); + WriteSetting(QStringLiteral("touch_device"), + QString::fromStdString(Settings::values.touch_device), + QStringLiteral("engine:emu_window")); WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false); + WriteSetting(QStringLiteral("use_touch_from_button"), Settings::values.use_touch_from_button, + false); + WriteSetting(QStringLiteral("touch_from_button_map"), + Settings::values.touch_from_button_map_index, 0); WriteSetting(QStringLiteral("udp_input_address"), QString::fromStdString(Settings::values.udp_input_address), QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)); @@ -990,6 +1040,24 @@ void Config::SaveControlValues() { WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0); WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false); + qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); + for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { + qt_config->setArrayIndex(static_cast(p)); + WriteSetting(QStringLiteral("name"), + QString::fromStdString(Settings::values.touch_from_button_maps[p].name), + QStringLiteral("default")); + qt_config->beginWriteArray(QStringLiteral("entries")); + for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); + ++q) { + qt_config->setArrayIndex(static_cast(q)); + WriteSetting( + QStringLiteral("bind"), + QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q])); + } + qt_config->endArray(); + } + qt_config->endArray(); + qt_config->endGroup(); } diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 5223eed1d8..62c504286c 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -20,6 +20,7 @@ #include "yuzu/configuration/configure_input.h" #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_mouse_advanced.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" @@ -131,6 +132,11 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) { connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); }); + connect(ui->buttonMotionTouch, &QPushButton::clicked, [this] { + QDialog* motion_touch_dialog = new ConfigureMotionTouch(this); + return motion_touch_dialog->exec(); + }); + RetranslateUI(); LoadConfiguration(); } diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp new file mode 100644 index 0000000000..cb79e47cec --- /dev/null +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -0,0 +1,304 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include "input_common/main.h" +#include "ui_configure_motion_touch.h" +#include "yuzu/configuration/configure_motion_touch.h" +#include "yuzu/configuration/configure_touch_from_button.h" + +CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, + const std::string& host, u16 port, + u8 pad_index, u16 client_id) + : QDialog(parent) { + layout = new QVBoxLayout; + status_label = new QLabel(tr("Communicating with the server...")); + cancel_button = new QPushButton(tr("Cancel")); + connect(cancel_button, &QPushButton::clicked, this, [this] { + if (!completed) + job->Stop(); + accept(); + }); + layout->addWidget(status_label); + layout->addWidget(cancel_button); + setLayout(layout); + + using namespace InputCommon::CemuhookUDP; + job = std::make_unique( + host, port, pad_index, client_id, + [this](CalibrationConfigurationJob::Status status) { + QString text; + switch (status) { + case CalibrationConfigurationJob::Status::Ready: + text = tr("Touch the top left corner
of your touchpad."); + break; + case CalibrationConfigurationJob::Status::Stage1Completed: + text = tr("Now touch the bottom right corner
of your touchpad."); + break; + case CalibrationConfigurationJob::Status::Completed: + text = tr("Configuration completed!"); + break; + } + QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text)); + if (status == CalibrationConfigurationJob::Status::Completed) { + QMetaObject::invokeMethod(this, "UpdateButtonText", Q_ARG(QString, tr("OK"))); + } + }, + [this](u16 min_x_, u16 min_y_, u16 max_x_, u16 max_y_) { + completed = true; + min_x = min_x_; + min_y = min_y_; + max_x = max_x_; + max_y = max_y_; + }); +} + +CalibrationConfigurationDialog::~CalibrationConfigurationDialog() = default; + +void CalibrationConfigurationDialog::UpdateLabelText(QString text) { + status_label->setText(text); +} + +void CalibrationConfigurationDialog::UpdateButtonText(QString text) { + cancel_button->setText(text); +} + +const std::array, 2> MotionProviders = { + {{"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")}, + {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}}}; + +const std::array, 2> TouchProviders = { + {{"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")}, + {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}}}; + +ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent) + : QDialog(parent), ui(std::make_unique()) { + ui->setupUi(this); + for (auto [provider, name] : MotionProviders) { + ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider)); + } + for (auto [provider, name] : TouchProviders) { + ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider)); + } + + ui->udp_learn_more->setOpenExternalLinks(true); + ui->udp_learn_more->setText( + tr("Learn More")); + + SetConfiguration(); + UpdateUiDisplay(); + ConnectEvents(); +} + +ConfigureMotionTouch::~ConfigureMotionTouch() = default; + +void ConfigureMotionTouch::SetConfiguration() { + Common::ParamPackage motion_param(Settings::values.motion_device); + Common::ParamPackage touch_param(Settings::values.touch_device); + std::string motion_engine = motion_param.Get("engine", "motion_emu"); + std::string touch_engine = touch_param.Get("engine", "emu_window"); + + ui->motion_provider->setCurrentIndex( + ui->motion_provider->findData(QString::fromStdString(motion_engine))); + ui->touch_provider->setCurrentIndex( + ui->touch_provider->findData(QString::fromStdString(touch_engine))); + ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button); + touch_from_button_maps = Settings::values.touch_from_button_maps; + for (const auto& touch_map : touch_from_button_maps) { + ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name)); + } + ui->touch_from_button_map->setCurrentIndex(Settings::values.touch_from_button_map_index); + ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f)); + + min_x = touch_param.Get("min_x", 100); + min_y = touch_param.Get("min_y", 50); + max_x = touch_param.Get("max_x", 1800); + max_y = touch_param.Get("max_y", 850); + + ui->udp_server->setText(QString::fromStdString(Settings::values.udp_input_address)); + ui->udp_port->setText(QString::number(Settings::values.udp_input_port)); + ui->udp_pad_index->setCurrentIndex(Settings::values.udp_pad_index); +} + +void ConfigureMotionTouch::UpdateUiDisplay() { + std::string motion_engine = ui->motion_provider->currentData().toString().toStdString(); + std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); + + if (motion_engine == "motion_emu") { + ui->motion_sensitivity_label->setVisible(true); + ui->motion_sensitivity->setVisible(true); + } else { + ui->motion_sensitivity_label->setVisible(false); + ui->motion_sensitivity->setVisible(false); + } + + if (touch_engine == "cemuhookudp") { + ui->touch_calibration->setVisible(true); + ui->touch_calibration_config->setVisible(true); + ui->touch_calibration_label->setVisible(true); + ui->touch_calibration->setText(QStringLiteral("(%1, %2) - (%3, %4)") + .arg(QString::number(min_x), QString::number(min_y), + QString::number(max_x), QString::number(max_y))); + } else { + ui->touch_calibration->setVisible(false); + ui->touch_calibration_config->setVisible(false); + ui->touch_calibration_label->setVisible(false); + } + + if (motion_engine == "cemuhookudp" || touch_engine == "cemuhookudp") { + ui->udp_config_group_box->setVisible(true); + } else { + ui->udp_config_group_box->setVisible(false); + } +} + +void ConfigureMotionTouch::ConnectEvents() { + connect(ui->motion_provider, + static_cast(&QComboBox::currentIndexChanged), this, + [this](int index) { UpdateUiDisplay(); }); + connect(ui->touch_provider, + static_cast(&QComboBox::currentIndexChanged), this, + [this](int index) { UpdateUiDisplay(); }); + connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); + connect(ui->touch_calibration_config, &QPushButton::clicked, this, + &ConfigureMotionTouch::OnConfigureTouchCalibration); + connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, + &ConfigureMotionTouch::OnConfigureTouchFromButton); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] { + if (CanCloseDialog()) + reject(); + }); +} + +void ConfigureMotionTouch::OnCemuhookUDPTest() { + ui->udp_test->setEnabled(false); + ui->udp_test->setText(tr("Testing")); + udp_test_in_progress = true; + InputCommon::CemuhookUDP::TestCommunication( + ui->udp_server->text().toStdString(), static_cast(ui->udp_port->text().toInt()), + static_cast(ui->udp_pad_index->currentIndex()), 24872, + [this] { + LOG_INFO(Frontend, "UDP input test success"); + QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); + }, + [this] { + LOG_ERROR(Frontend, "UDP input test failed"); + QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, false)); + }); +} + +void ConfigureMotionTouch::OnConfigureTouchCalibration() { + ui->touch_calibration_config->setEnabled(false); + ui->touch_calibration_config->setText(tr("Configuring")); + CalibrationConfigurationDialog* dialog = new CalibrationConfigurationDialog( + this, ui->udp_server->text().toStdString(), static_cast(ui->udp_port->text().toUInt()), + static_cast(ui->udp_pad_index->currentIndex()), 24872); + dialog->exec(); + if (dialog->completed) { + min_x = dialog->min_x; + min_y = dialog->min_y; + max_x = dialog->max_x; + max_y = dialog->max_y; + LOG_INFO(Frontend, + "UDP touchpad calibration config success: min_x={}, min_y={}, max_x={}, max_y={}", + min_x, min_y, max_x, max_y); + UpdateUiDisplay(); + } else { + LOG_ERROR(Frontend, "UDP touchpad calibration config failed"); + } + ui->touch_calibration_config->setEnabled(true); + ui->touch_calibration_config->setText(tr("Configure")); +} + +void ConfigureMotionTouch::closeEvent(QCloseEvent* event) { + if (CanCloseDialog()) + event->accept(); + else + event->ignore(); +} + +void ConfigureMotionTouch::ShowUDPTestResult(bool result) { + udp_test_in_progress = false; + if (result) { + QMessageBox::information(this, tr("Test Successful"), + tr("Successfully received data from the server.")); + } else { + QMessageBox::warning(this, tr("Test Failed"), + tr("Could not receive valid data from the server.
Please verify " + "that the server is set up correctly and " + "the address and port are correct.")); + } + ui->udp_test->setEnabled(true); + ui->udp_test->setText(tr("Test")); +} + +void ConfigureMotionTouch::OnConfigureTouchFromButton() { + ConfigureTouchFromButton dialog{this, touch_from_button_maps, + ui->touch_from_button_map->currentIndex()}; + if (dialog.exec() != QDialog::Accepted) { + return; + } + touch_from_button_maps = dialog.GetMaps(); + + while (ui->touch_from_button_map->count() > 0) { + ui->touch_from_button_map->removeItem(0); + } + for (const auto& touch_map : touch_from_button_maps) { + ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name)); + } + ui->touch_from_button_map->setCurrentIndex(dialog.GetSelectedIndex()); +} + +bool ConfigureMotionTouch::CanCloseDialog() { + if (udp_test_in_progress) { + QMessageBox::warning(this, tr("Citra"), + tr("UDP Test or calibration configuration is in progress.
Please " + "wait for them to finish.")); + return false; + } + return true; +} + +void ConfigureMotionTouch::ApplyConfiguration() { + if (!CanCloseDialog()) + return; + + std::string motion_engine = ui->motion_provider->currentData().toString().toStdString(); + std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); + + Common::ParamPackage motion_param{}, touch_param{}; + motion_param.Set("engine", motion_engine); + touch_param.Set("engine", touch_engine); + + if (motion_engine == "motion_emu") { + motion_param.Set("sensitivity", static_cast(ui->motion_sensitivity->value())); + } + + if (touch_engine == "cemuhookudp") { + touch_param.Set("min_x", min_x); + touch_param.Set("min_y", min_y); + touch_param.Set("max_x", max_x); + touch_param.Set("max_y", max_y); + } + + Settings::values.motion_device = motion_param.Serialize(); + Settings::values.touch_device = touch_param.Serialize(); + Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); + Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex(); + Settings::values.touch_from_button_maps = touch_from_button_maps; + Settings::values.udp_input_address = ui->udp_server->text().toStdString(); + Settings::values.udp_input_port = static_cast(ui->udp_port->text().toInt()); + Settings::values.udp_pad_index = static_cast(ui->udp_pad_index->currentIndex()); + InputCommon::ReloadInputDevices(); + + accept(); +} diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h new file mode 100644 index 0000000000..1a4f500224 --- /dev/null +++ b/src/yuzu/configuration/configure_motion_touch.h @@ -0,0 +1,77 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/param_package.h" +#include "core/settings.h" +#include "input_common/udp/client.h" +#include "input_common/udp/udp.h" + +class QVBoxLayout; +class QLabel; +class QPushButton; + +namespace Ui { +class ConfigureMotionTouch; +} + +/// A dialog for touchpad calibration configuration. +class CalibrationConfigurationDialog : public QDialog { + Q_OBJECT +public: + explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, + u8 pad_index, u16 client_id); + ~CalibrationConfigurationDialog(); + +private: + Q_INVOKABLE void UpdateLabelText(QString text); + Q_INVOKABLE void UpdateButtonText(QString text); + + QVBoxLayout* layout; + QLabel* status_label; + QPushButton* cancel_button; + std::unique_ptr job; + + // Configuration results + bool completed{}; + u16 min_x, min_y, max_x, max_y; + + friend class ConfigureMotionTouch; +}; + +class ConfigureMotionTouch : public QDialog { + Q_OBJECT + +public: + explicit ConfigureMotionTouch(QWidget* parent = nullptr); + ~ConfigureMotionTouch() override; + +public slots: + void ApplyConfiguration(); + +private slots: + void OnCemuhookUDPTest(); + void OnConfigureTouchCalibration(); + void OnConfigureTouchFromButton(); + +private: + void closeEvent(QCloseEvent* event) override; + Q_INVOKABLE void ShowUDPTestResult(bool result); + void SetConfiguration(); + void UpdateUiDisplay(); + void ConnectEvents(); + bool CanCloseDialog(); + + std::unique_ptr ui; + + // Coordinate system of the CemuhookUDP touch provider + int min_x, min_y, max_x, max_y; + + bool udp_test_in_progress{}; + + std::vector touch_from_button_maps; +}; diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui new file mode 100644 index 0000000000..602cf8cd83 --- /dev/null +++ b/src/yuzu/configuration/configure_motion_touch.ui @@ -0,0 +1,327 @@ + + + ConfigureMotionTouch + + + Configure Motion / Touch + + + + 0 + 0 + 500 + 450 + + + + + + + Motion + + + + + + + + Motion Provider: + + + + + + + + + + + + + + Sensitivity: + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + 0.010000000000000 + + + 10.000000000000000 + + + 0.001000000000000 + + + 0.010000000000000 + + + + + + + + + + + + Touch + + + + + + + + Touch Provider: + + + + + + + + + + + + + + Calibration: + + + + + + + (100, 50) - (1800, 850) + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + + + + + 0 + 0 + + + + Use button mapping: + + + + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + + + + + CemuhookUDP Config + + + + + + You may use any Cemuhook compatible UDP input source to provide motion and touch input. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Server: + + + + + + + + 0 + 0 + + + + + + + + + + + + Port: + + + + + + + + 0 + 0 + + + + + + + + + + + + Pad: + + + + + + + + Pad 1 + + + + + Pad 2 + + + + + Pad 3 + + + + + Pad 4 + + + + + + + + + + + + Learn More + + + + + + + + 0 + 0 + + + + Test + + + + + + + + + + + + Qt::Vertical + + + + 167 + 55 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ConfigureMotionTouch + ApplyConfiguration() + + + 220 + 380 + + + 220 + 200 + + + + + diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp new file mode 100644 index 0000000000..0a0448cea2 --- /dev/null +++ b/src/yuzu/configuration/configure_touch_from_button.cpp @@ -0,0 +1,612 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include +#include "common/param_package.h" +#include "input_common/main.h" +#include "ui_configure_touch_from_button.h" +#include "yuzu/configuration/configure_touch_from_button.h" +#include "yuzu/configuration/configure_touch_widget.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 QString{}; + default: + return QKeySequence(key_code).toString(); + } +} + +static QString ButtonToText(const Common::ParamPackage& param) { + if (!param.Has("engine")) { + return QObject::tr("[not set]"); + } + + if (param.Get("engine", "") == "keyboard") { + return GetKeyName(param.Get("code", 0)); + } + + if (param.Get("engine", "") == "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 {}; + } + + return QObject::tr("[unknown]"); +} + +ConfigureTouchFromButton::ConfigureTouchFromButton( + QWidget* parent, const std::vector& touch_maps, + const int default_index) + : QDialog(parent), ui(std::make_unique()), touch_maps(touch_maps), + selected_index(default_index), timeout_timer(std::make_unique()), + poll_timer(std::make_unique()) { + + ui->setupUi(this); + binding_list_model = std::make_unique(0, 3, this); + binding_list_model->setHorizontalHeaderLabels({tr("Button"), tr("X"), tr("Y")}); + ui->binding_list->setModel(binding_list_model.get()); + ui->bottom_screen->SetCoordLabel(ui->coord_label); + + SetConfiguration(); + UpdateUiDisplay(); + ConnectEvents(); +} + +ConfigureTouchFromButton::~ConfigureTouchFromButton() = default; + +void ConfigureTouchFromButton::showEvent(QShowEvent* ev) { + QWidget::showEvent(ev); + + // width values are not valid in the constructor + const int w = + ui->binding_list->viewport()->contentsRect().width() / binding_list_model->columnCount(); + if (w > 0) { + ui->binding_list->setColumnWidth(0, w); + ui->binding_list->setColumnWidth(1, w); + ui->binding_list->setColumnWidth(2, w); + } +} + +void ConfigureTouchFromButton::SetConfiguration() { + for (const auto& touch_map : touch_maps) { + ui->mapping->addItem(QString::fromStdString(touch_map.name)); + } + + ui->mapping->setCurrentIndex(selected_index); +} + +void ConfigureTouchFromButton::UpdateUiDisplay() { + ui->button_delete->setEnabled(touch_maps.size() > 1); + ui->button_delete_bind->setEnabled(false); + + binding_list_model->removeRows(0, binding_list_model->rowCount()); + + for (const auto& button_str : touch_maps[selected_index].buttons) { + Common::ParamPackage package{button_str}; + QStandardItem* button = new QStandardItem(ButtonToText(package)); + button->setData(QString::fromStdString(button_str)); + button->setEditable(false); + QStandardItem* xcoord = new QStandardItem(QString::number(package.Get("x", 0))); + QStandardItem* ycoord = new QStandardItem(QString::number(package.Get("y", 0))); + binding_list_model->appendRow({button, xcoord, ycoord}); + + int dot = ui->bottom_screen->AddDot(package.Get("x", 0), package.Get("y", 0)); + button->setData(dot, DataRoleDot); + } +} + +void ConfigureTouchFromButton::ConnectEvents() { + connect(ui->mapping, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) { + SaveCurrentMapping(); + selected_index = index; + UpdateUiDisplay(); + }); + connect(ui->button_new, &QPushButton::clicked, this, &ConfigureTouchFromButton::NewMapping); + connect(ui->button_delete, &QPushButton::clicked, this, + &ConfigureTouchFromButton::DeleteMapping); + connect(ui->button_rename, &QPushButton::clicked, this, + &ConfigureTouchFromButton::RenameMapping); + connect(ui->button_delete_bind, &QPushButton::clicked, this, + &ConfigureTouchFromButton::DeleteBinding); + connect(ui->binding_list, &QTreeView::doubleClicked, this, + &ConfigureTouchFromButton::EditBinding); + connect(ui->binding_list->selectionModel(), &QItemSelectionModel::selectionChanged, this, + &ConfigureTouchFromButton::OnBindingSelection); + connect(binding_list_model.get(), &QStandardItemModel::itemChanged, this, + &ConfigureTouchFromButton::OnBindingChanged); + connect(ui->binding_list->model(), &QStandardItemModel::rowsAboutToBeRemoved, this, + &ConfigureTouchFromButton::OnBindingDeleted); + connect(ui->bottom_screen, &TouchScreenPreview::DotAdded, this, + &ConfigureTouchFromButton::NewBinding); + connect(ui->bottom_screen, &TouchScreenPreview::DotSelected, this, + &ConfigureTouchFromButton::SetActiveBinding); + connect(ui->bottom_screen, &TouchScreenPreview::DotMoved, this, + &ConfigureTouchFromButton::SetCoordinates); + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, + &ConfigureTouchFromButton::ApplyConfiguration); + + 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; + } + } + }); +} + +void ConfigureTouchFromButton::SaveCurrentMapping() { + auto& map = touch_maps[selected_index]; + map.buttons.clear(); + for (int i = 0, rc = binding_list_model->rowCount(); i < rc; ++i) { + const auto bind_str = binding_list_model->index(i, 0) + .data(Qt::ItemDataRole::UserRole + 1) + .toString() + .toStdString(); + if (bind_str.empty()) { + continue; + } + Common::ParamPackage params{bind_str}; + if (!params.Has("engine")) { + continue; + } + params.Set("x", binding_list_model->index(i, 1).data().toInt()); + params.Set("y", binding_list_model->index(i, 2).data().toInt()); + map.buttons.emplace_back(params.Serialize()); + } +} + +void ConfigureTouchFromButton::NewMapping() { + const QString name = + QInputDialog::getText(this, tr("New Profile"), tr("Enter the name for the new profile.")); + if (name.isEmpty()) { + return; + } + touch_maps.emplace_back(Settings::TouchFromButtonMap{name.toStdString(), {}}); + ui->mapping->addItem(name); + ui->mapping->setCurrentIndex(ui->mapping->count() - 1); +} + +void ConfigureTouchFromButton::DeleteMapping() { + const auto answer = QMessageBox::question( + this, tr("Delete Profile"), tr("Delete profile %1?").arg(ui->mapping->currentText())); + if (answer != QMessageBox::Yes) { + return; + } + const bool blocked = ui->mapping->blockSignals(true); + ui->mapping->removeItem(selected_index); + ui->mapping->blockSignals(blocked); + touch_maps.erase(touch_maps.begin() + selected_index); + selected_index = ui->mapping->currentIndex(); + UpdateUiDisplay(); +} + +void ConfigureTouchFromButton::RenameMapping() { + const QString new_name = QInputDialog::getText(this, tr("Rename Profile"), tr("New name:")); + if (new_name.isEmpty()) { + return; + } + ui->mapping->setItemText(selected_index, new_name); + touch_maps[selected_index].name = new_name.toStdString(); +} + +void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is_new) { + binding_list_model->item(row_index, 0)->setText(tr("[press key]")); + + input_setter = [this, row_index, is_new](const Common::ParamPackage& params, + const bool cancel) { + auto cell = binding_list_model->item(row_index, 0); + if (cancel) { + if (is_new) { + binding_list_model->removeRow(row_index); + } else { + cell->setText( + ButtonToText(Common::ParamPackage{cell->data().toString().toStdString()})); + } + } else { + cell->setText(ButtonToText(params)); + cell->setData(QString::fromStdString(params.Serialize())); + } + }; + + device_pollers = InputCommon::Polling::GetPollers(InputCommon::Polling::DeviceType::Button); + + for (auto& poller : device_pollers) { + poller->Start(); + } + + grabKeyboard(); + grabMouse(); + qApp->setOverrideCursor(QCursor(Qt::CursorShape::ArrowCursor)); + timeout_timer->start(5000); // Cancel after 5 seconds + poll_timer->start(200); // Check for new inputs every 200ms +} + +void ConfigureTouchFromButton::NewBinding(const QPoint& pos) { + QStandardItem* button = new QStandardItem(); + button->setEditable(false); + QStandardItem* xcoord = new QStandardItem(QString::number(pos.x())); + QStandardItem* ycoord = new QStandardItem(QString::number(pos.y())); + + const int dot_id = ui->bottom_screen->AddDot(pos.x(), pos.y()); + button->setData(dot_id, DataRoleDot); + + binding_list_model->appendRow({button, xcoord, ycoord}); + ui->binding_list->setFocus(); + ui->binding_list->setCurrentIndex(button->index()); + + GetButtonInput(binding_list_model->rowCount() - 1, true); +} + +void ConfigureTouchFromButton::EditBinding(const QModelIndex& qi) { + if (qi.row() >= 0 && qi.column() == 0) { + GetButtonInput(qi.row(), false); + } +} + +void ConfigureTouchFromButton::DeleteBinding() { + const int row_index = ui->binding_list->currentIndex().row(); + if (row_index >= 0) { + ui->bottom_screen->RemoveDot( + binding_list_model->index(row_index, 0).data(DataRoleDot).toInt()); + binding_list_model->removeRow(row_index); + } +} + +void ConfigureTouchFromButton::OnBindingSelection(const QItemSelection& selected, + const QItemSelection& deselected) { + ui->button_delete_bind->setEnabled(!selected.isEmpty()); + if (!selected.isEmpty()) { + const auto dot_data = selected.indexes().first().data(DataRoleDot); + if (dot_data.isValid()) { + ui->bottom_screen->HighlightDot(dot_data.toInt()); + } + } + if (!deselected.isEmpty()) { + const auto dot_data = deselected.indexes().first().data(DataRoleDot); + if (dot_data.isValid()) { + ui->bottom_screen->HighlightDot(dot_data.toInt(), false); + } + } +} + +void ConfigureTouchFromButton::OnBindingChanged(QStandardItem* item) { + if (item->column() == 0) { + return; + } + + const bool blocked = binding_list_model->blockSignals(true); + item->setText(QString::number( + std::clamp(item->text().toInt(), 0, + static_cast((item->column() == 1 ? Layout::ScreenUndocked::Width + : Layout::ScreenUndocked::Height) - + 1)))); + binding_list_model->blockSignals(blocked); + + const auto dot_data = binding_list_model->index(item->row(), 0).data(DataRoleDot); + if (dot_data.isValid()) { + ui->bottom_screen->MoveDot(dot_data.toInt(), + binding_list_model->item(item->row(), 1)->text().toInt(), + binding_list_model->item(item->row(), 2)->text().toInt()); + } +} + +void ConfigureTouchFromButton::OnBindingDeleted(const QModelIndex& parent, int first, int last) { + for (int i = first; i <= last; ++i) { + auto ix = binding_list_model->index(i, 0); + if (!ix.isValid()) { + return; + } + const auto dot_data = ix.data(DataRoleDot); + if (dot_data.isValid()) { + ui->bottom_screen->RemoveDot(dot_data.toInt()); + } + } +} + +void ConfigureTouchFromButton::SetActiveBinding(const int dot_id) { + for (int i = 0; i < binding_list_model->rowCount(); ++i) { + if (binding_list_model->index(i, 0).data(DataRoleDot) == dot_id) { + ui->binding_list->setCurrentIndex(binding_list_model->index(i, 0)); + ui->binding_list->setFocus(); + return; + } + } +} + +void ConfigureTouchFromButton::SetCoordinates(const int dot_id, const QPoint& pos) { + for (int i = 0; i < binding_list_model->rowCount(); ++i) { + if (binding_list_model->item(i, 0)->data(DataRoleDot) == dot_id) { + binding_list_model->item(i, 1)->setText(QString::number(pos.x())); + binding_list_model->item(i, 2)->setText(QString::number(pos.y())); + return; + } + } +} + +void ConfigureTouchFromButton::SetPollingResult(const Common::ParamPackage& params, + const bool cancel) { + releaseKeyboard(); + releaseMouse(); + qApp->restoreOverrideCursor(); + timeout_timer->stop(); + poll_timer->stop(); + for (auto& poller : device_pollers) { + poller->Stop(); + } + if (input_setter) { + (*input_setter)(params, cancel); + input_setter.reset(); + } +} + +void ConfigureTouchFromButton::keyPressEvent(QKeyEvent* event) { + if (!input_setter && event->key() == Qt::Key_Delete) { + DeleteBinding(); + return; + } + + if (!input_setter) { + return QDialog::keyPressEvent(event); + } + + if (event->key() != Qt::Key_Escape) { + SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, + false); + } else { + SetPollingResult({}, true); + } +} + +void ConfigureTouchFromButton::ApplyConfiguration() { + SaveCurrentMapping(); + accept(); +} + +int ConfigureTouchFromButton::GetSelectedIndex() const { + return selected_index; +} + +std::vector ConfigureTouchFromButton::GetMaps() const { + return touch_maps; +} + +TouchScreenPreview::TouchScreenPreview(QWidget* parent) : QFrame(parent) { + setBackgroundRole(QPalette::ColorRole::Base); +} + +TouchScreenPreview::~TouchScreenPreview() = default; + +void TouchScreenPreview::SetCoordLabel(QLabel* const label) { + coord_label = label; +} + +int TouchScreenPreview::AddDot(const int device_x, const int device_y) { + QFont dot_font{QStringLiteral("monospace")}; + dot_font.setStyleHint(QFont::Monospace); + dot_font.setPointSize(20); + + QLabel* dot = new QLabel(this); + dot->setAttribute(Qt::WA_TranslucentBackground); + dot->setFont(dot_font); + dot->setText(QChar(0xD7)); // U+00D7 Multiplication Sign + dot->setAlignment(Qt::AlignmentFlag::AlignCenter); + dot->setProperty(PropId, ++max_dot_id); + dot->setProperty(PropX, device_x); + dot->setProperty(PropY, device_y); + dot->setCursor(Qt::CursorShape::PointingHandCursor); + dot->setMouseTracking(true); + dot->installEventFilter(this); + dot->show(); + PositionDot(dot, device_x, device_y); + dots.emplace_back(max_dot_id, dot); + return max_dot_id; +} + +void TouchScreenPreview::RemoveDot(const int id) { + for (auto dot_it = dots.begin(); dot_it != dots.end(); ++dot_it) { + if (dot_it->first == id) { + dot_it->second->deleteLater(); + dots.erase(dot_it); + return; + } + } +} + +void TouchScreenPreview::HighlightDot(const int id, const bool active) const { + for (const auto& dot : dots) { + if (dot.first == id) { + // use color property from the stylesheet, or fall back to the default palette + if (dot_highlight_color.isValid()) { + dot.second->setStyleSheet( + active ? QStringLiteral("color: %1").arg(dot_highlight_color.name()) + : QString{}); + } else { + dot.second->setForegroundRole(active ? QPalette::ColorRole::LinkVisited + : QPalette::ColorRole::NoRole); + } + if (active) { + dot.second->raise(); + } + return; + } + } +} + +void TouchScreenPreview::MoveDot(const int id, const int device_x, const int device_y) const { + for (const auto& dot : dots) { + if (dot.first == id) { + dot.second->setProperty(PropX, device_x); + dot.second->setProperty(PropY, device_y); + PositionDot(dot.second, device_x, device_y); + return; + } + } +} + +void TouchScreenPreview::resizeEvent(QResizeEvent* event) { + if (ignore_resize) { + return; + } + + const int target_width = std::min(width(), height() * 4 / 3); + const int target_height = std::min(height(), width() * 3 / 4); + if (target_width == width() && target_height == height()) { + return; + } + ignore_resize = true; + setGeometry((parentWidget()->contentsRect().width() - target_width) / 2, y(), target_width, + target_height); + ignore_resize = false; + + if (event->oldSize().width() != target_width || event->oldSize().height() != target_height) { + for (const auto& dot : dots) { + PositionDot(dot.second); + } + } +} + +void TouchScreenPreview::mouseMoveEvent(QMouseEvent* event) { + if (!coord_label) { + return; + } + const auto pos = MapToDeviceCoords(event->x(), event->y()); + if (pos) { + coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x()).arg(pos->y())); + } else { + coord_label->clear(); + } +} + +void TouchScreenPreview::leaveEvent(QEvent* event) { + if (coord_label) { + coord_label->clear(); + } +} + +void TouchScreenPreview::mousePressEvent(QMouseEvent* event) { + if (event->button() == Qt::MouseButton::LeftButton) { + const auto pos = MapToDeviceCoords(event->x(), event->y()); + if (pos) { + emit DotAdded(*pos); + } + } +} + +bool TouchScreenPreview::eventFilter(QObject* obj, QEvent* event) { + switch (event->type()) { + case QEvent::Type::MouseButtonPress: { + const auto mouse_event = static_cast(event); + if (mouse_event->button() != Qt::MouseButton::LeftButton) { + break; + } + emit DotSelected(obj->property(PropId).toInt()); + + drag_state.dot = qobject_cast(obj); + drag_state.start_pos = mouse_event->globalPos(); + return true; + } + case QEvent::Type::MouseMove: { + if (!drag_state.dot) { + break; + } + const auto mouse_event = static_cast(event); + if (!drag_state.active) { + drag_state.active = + (mouse_event->globalPos() - drag_state.start_pos).manhattanLength() >= + QApplication::startDragDistance(); + if (!drag_state.active) { + break; + } + } + auto current_pos = mapFromGlobal(mouse_event->globalPos()); + current_pos.setX(std::clamp(current_pos.x(), contentsMargins().left(), + contentsMargins().left() + contentsRect().width() - 1)); + current_pos.setY(std::clamp(current_pos.y(), contentsMargins().top(), + contentsMargins().top() + contentsRect().height() - 1)); + const auto device_coord = MapToDeviceCoords(current_pos.x(), current_pos.y()); + if (device_coord) { + drag_state.dot->setProperty(PropX, device_coord->x()); + drag_state.dot->setProperty(PropY, device_coord->y()); + PositionDot(drag_state.dot, device_coord->x(), device_coord->y()); + emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord); + if (coord_label) { + coord_label->setText( + QStringLiteral("X: %1, Y: %2").arg(device_coord->x()).arg(device_coord->y())); + } + } + return true; + } + case QEvent::Type::MouseButtonRelease: { + drag_state.dot.clear(); + drag_state.active = false; + return true; + } + default: + break; + } + return obj->eventFilter(obj, event); +} + +std::optional TouchScreenPreview::MapToDeviceCoords(const int screen_x, + const int screen_y) const { + const float t_x = 0.5f + static_cast(screen_x - contentsMargins().left()) * + (Layout::ScreenUndocked::Width - 1) / (contentsRect().width() - 1); + const float t_y = 0.5f + static_cast(screen_y - contentsMargins().top()) * + (Layout::ScreenUndocked::Height - 1) / + (contentsRect().height() - 1); + if (t_x >= 0.5f && t_x < Layout::ScreenUndocked::Width && t_y >= 0.5f && + t_y < Layout::ScreenUndocked::Height) { + + return QPoint{static_cast(t_x), static_cast(t_y)}; + } + return std::nullopt; +} + +void TouchScreenPreview::PositionDot(QLabel* const dot, const int device_x, + const int device_y) const { + dot->move(static_cast( + static_cast(device_x >= 0 ? device_x : dot->property(PropX).toInt()) * + (contentsRect().width() - 1) / (Layout::ScreenUndocked::Width - 1) + + contentsMargins().left() - static_cast(dot->width()) / 2 + 0.5f), + static_cast( + static_cast(device_y >= 0 ? device_y : dot->property(PropY).toInt()) * + (contentsRect().height() - 1) / (Layout::ScreenUndocked::Height - 1) + + contentsMargins().top() - static_cast(dot->height()) / 2 + 0.5f)); +} diff --git a/src/yuzu/configuration/configure_touch_from_button.h b/src/yuzu/configuration/configure_touch_from_button.h new file mode 100644 index 0000000000..c926db0123 --- /dev/null +++ b/src/yuzu/configuration/configure_touch_from_button.h @@ -0,0 +1,86 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include "core/frontend/framebuffer_layout.h" +#include "core/settings.h" + +class QItemSelection; +class QModelIndex; +class QStandardItemModel; +class QStandardItem; +class QTimer; + +namespace Common { +class ParamPackage; +} + +namespace InputCommon { +namespace Polling { +class DevicePoller; +} +} // namespace InputCommon + +namespace Ui { +class ConfigureTouchFromButton; +} + +class ConfigureTouchFromButton : public QDialog { + Q_OBJECT + +public: + explicit ConfigureTouchFromButton(QWidget* parent, + const std::vector& touch_maps, + int default_index = 0); + ~ConfigureTouchFromButton() override; + + int GetSelectedIndex() const; + std::vector GetMaps() const; + +public slots: + void ApplyConfiguration(); + void NewBinding(const QPoint& pos); + void SetActiveBinding(int dot_id); + void SetCoordinates(int dot_id, const QPoint& pos); + +protected: + virtual void showEvent(QShowEvent* ev) override; + virtual void keyPressEvent(QKeyEvent* event) override; + +private slots: + void NewMapping(); + void DeleteMapping(); + void RenameMapping(); + void EditBinding(const QModelIndex& qi); + void DeleteBinding(); + void OnBindingSelection(const QItemSelection& selected, const QItemSelection& deselected); + void OnBindingChanged(QStandardItem* item); + void OnBindingDeleted(const QModelIndex& parent, int first, int last); + +private: + void SetConfiguration(); + void UpdateUiDisplay(); + void ConnectEvents(); + void GetButtonInput(int row_index, bool is_new); + void SetPollingResult(const Common::ParamPackage& params, bool cancel); + void SaveCurrentMapping(); + + std::unique_ptr ui; + std::unique_ptr binding_list_model; + std::vector touch_maps; + int selected_index; + + std::unique_ptr timeout_timer; + std::unique_ptr poll_timer; + std::vector> device_pollers; + std::optional> input_setter; + + static constexpr int DataRoleDot = Qt::ItemDataRole::UserRole + 2; +}; diff --git a/src/yuzu/configuration/configure_touch_from_button.ui b/src/yuzu/configuration/configure_touch_from_button.ui new file mode 100644 index 0000000000..d0598bdbd6 --- /dev/null +++ b/src/yuzu/configuration/configure_touch_from_button.ui @@ -0,0 +1,231 @@ + + + ConfigureTouchFromButton + + + + 0 + 0 + 500 + 500 + + + + Configure Touchscreen Mappings + + + + + + + + Mapping: + + + Qt::PlainText + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + New + + + + + + + + 0 + 0 + + + + Delete + + + + + + + + 0 + 0 + + + + Rename + + + + + + + + + Qt::Horizontal + + + + + + + + + Click the bottom area to add a point, then press a button to bind. +Drag points to change position, or double-click table cells to edit values. + + + Qt::PlainText + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete Point + + + + + + + + + + 0 + 0 + + + + false + + + true + + + false + + + + + + + + 0 + 0 + + + + + 160 + 120 + + + + + 320 + 240 + + + + CrossCursor + + + true + + + true + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + + + + 0 + 0 + + + + Qt::PlainText + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + TouchScreenPreview + QFrame +
citra_qt/configuration/configure_touch_widget.h
+ 1 +
+
+ + + + buttonBox + rejected() + ConfigureTouchFromButton + reject() + + + 249 + 428 + + + 249 + 224 + + + + +
diff --git a/src/yuzu/configuration/configure_touch_widget.h b/src/yuzu/configuration/configure_touch_widget.h new file mode 100644 index 0000000000..c85960f823 --- /dev/null +++ b/src/yuzu/configuration/configure_touch_widget.h @@ -0,0 +1,61 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include + +class QLabel; + +// Widget for representing touchscreen coordinates +class TouchScreenPreview : public QFrame { + Q_OBJECT + Q_PROPERTY(QColor dotHighlightColor MEMBER dot_highlight_color) + +public: + explicit TouchScreenPreview(QWidget* parent); + ~TouchScreenPreview() override; + + void SetCoordLabel(QLabel*); + int AddDot(int device_x, int device_y); + void RemoveDot(int id); + void HighlightDot(int id, bool active = true) const; + void MoveDot(int id, int device_x, int device_y) const; + +signals: + void DotAdded(const QPoint& pos); + void DotSelected(int dot_id); + void DotMoved(int dot_id, const QPoint& pos); + +protected: + virtual void resizeEvent(QResizeEvent*) override; + virtual void mouseMoveEvent(QMouseEvent*) override; + virtual void leaveEvent(QEvent*) override; + virtual void mousePressEvent(QMouseEvent*) override; + virtual bool eventFilter(QObject*, QEvent*) override; + +private: + std::optional MapToDeviceCoords(int screen_x, int screen_y) const; + void PositionDot(QLabel* dot, int device_x = -1, int device_y = -1) const; + + bool ignore_resize = false; + QPointer coord_label; + + std::vector> dots; + int max_dot_id = 0; + QColor dot_highlight_color; + static constexpr char PropId[] = "dot_id"; + static constexpr char PropX[] = "device_x"; + static constexpr char PropY[] = "device_y"; + + struct { + bool active = false; + QPointer dot; + QPoint start_pos; + } drag_state; +}; From d176feffad824bce20b694432ade28fe8273c8e4 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sat, 29 Aug 2020 20:56:51 +0200 Subject: [PATCH 2/4] Address review comments and fix code compilation --- src/input_common/main.cpp | 8 +- src/input_common/main.h | 2 + src/input_common/touch_from_button.cpp | 7 +- src/yuzu/configuration/config.cpp | 77 +++++++----- src/yuzu/configuration/config.h | 2 + src/yuzu/configuration/configure_input.cpp | 9 +- .../configure_input_advanced.cpp | 2 + .../configuration/configure_input_advanced.h | 1 + .../configuration/configure_motion_touch.cpp | 88 ++++++++------ .../configuration/configure_motion_touch.h | 29 +++-- .../configure_touch_from_button.cpp | 114 ++++++++++-------- .../configure_touch_from_button.h | 19 ++- .../configuration/configure_touch_widget.h | 15 +-- 13 files changed, 218 insertions(+), 155 deletions(-) diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index f9d7b408f0..ea1a1cee63 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -175,9 +175,11 @@ const GCButtonFactory* InputSubsystem::GetGCButtons() const { return impl->gcbuttons.get(); } -void ReloadInputDevices() { - if (udp) - udp->ReloadUDPClient(); +void InputSubsystem::ReloadInputDevices() { + if (!impl->udp) { + return; + } + impl->udp->ReloadUDPClient(); } std::vector> InputSubsystem::GetPollers( diff --git a/src/input_common/main.h b/src/input_common/main.h index 269735c430..512215e7e6 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -118,6 +118,8 @@ public: /// Retrieves the underlying GameCube button handler. [[nodiscard]] const GCButtonFactory* GetGCButtons() const; + void ReloadInputDevices(); + /// Get all DevicePoller from all backends for a specific device type [[nodiscard]] std::vector> GetPollers( Polling::DeviceType type) const; diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp index 8e7f902535..d028dfa0d4 100644 --- a/src/input_common/touch_from_button.cpp +++ b/src/input_common/touch_from_button.cpp @@ -30,14 +30,15 @@ public: static_cast(Layout::ScreenUndocked::Width); const float y = static_cast(std::get<2>(m)) / static_cast(Layout::ScreenUndocked::Height); - return std::make_tuple(x, y, true); + return {x, y, true}; } } - return std::make_tuple(0.0f, 0.0f, false); + return {}; } private: - std::vector, int, int>> map; // button, x, y + // A vector of the mapped button, its x and its y-coordinate + std::vector, int, int>> map; }; std::unique_ptr TouchFromButtonFactory::Create( diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ead19a870a..2bc55a26af 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -420,10 +420,17 @@ void Config::ReadControlValues() { ReadKeyboardValues(); ReadMouseValues(); ReadTouchscreenValues(); + ReadMotionTouchValues(); Settings::values.vibration_enabled = ReadSetting(QStringLiteral("vibration_enabled"), true).toBool(); + Settings::values.use_docked_mode = + ReadSetting(QStringLiteral("use_docked_mode"), false).toBool(); + qt_config->endGroup(); +} + +void Config::ReadMotionTouchValues() { int num_touch_from_button_maps = qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); @@ -481,10 +488,6 @@ void Config::ReadControlValues() { .toInt()); Settings::values.udp_pad_index = static_cast(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt()); - Settings::values.use_docked_mode = - ReadSetting(QStringLiteral("use_docked_mode"), false).toBool(); - - qt_config->endGroup(); } void Config::ReadCoreValues() { @@ -977,6 +980,43 @@ void Config::SaveTouchscreenValues() { WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); } +void Config::SaveMotionTouchValues() { + WriteSetting(QStringLiteral("motion_device"), + QString::fromStdString(Settings::values.motion_device), + QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")); + WriteSetting(QStringLiteral("touch_device"), + QString::fromStdString(Settings::values.touch_device), + QStringLiteral("engine:emu_window")); + WriteSetting(QStringLiteral("use_touch_from_button"), Settings::values.use_touch_from_button, + false); + WriteSetting(QStringLiteral("touch_from_button_map"), + Settings::values.touch_from_button_map_index, 0); + WriteSetting(QStringLiteral("udp_input_address"), + QString::fromStdString(Settings::values.udp_input_address), + QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)); + WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port, + InputCommon::CemuhookUDP::DEFAULT_PORT); + WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0); + + qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); + for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { + qt_config->setArrayIndex(static_cast(p)); + WriteSetting(QStringLiteral("name"), + QString::fromStdString(Settings::values.touch_from_button_maps[p].name), + QStringLiteral("default")); + qt_config->beginWriteArray(QStringLiteral("entries")); + for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); + ++q) { + qt_config->setArrayIndex(static_cast(q)); + WriteSetting( + QStringLiteral("bind"), + QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q])); + } + qt_config->endArray(); + } + qt_config->endArray(); +} + void Config::SaveValues() { if (global) { SaveControlValues(); @@ -1019,6 +1059,7 @@ void Config::SaveControlValues() { SaveDebugValues(); SaveMouseValues(); SaveTouchscreenValues(); + SaveMotionTouchValues(); WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true); WriteSetting(QStringLiteral("motion_device"), @@ -1028,36 +1069,8 @@ void Config::SaveControlValues() { QString::fromStdString(Settings::values.touch_device), QStringLiteral("engine:emu_window")); WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false); - WriteSetting(QStringLiteral("use_touch_from_button"), Settings::values.use_touch_from_button, - false); - WriteSetting(QStringLiteral("touch_from_button_map"), - Settings::values.touch_from_button_map_index, 0); - WriteSetting(QStringLiteral("udp_input_address"), - QString::fromStdString(Settings::values.udp_input_address), - QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)); - WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port, - InputCommon::CemuhookUDP::DEFAULT_PORT); - WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0); WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false); - qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); - for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { - qt_config->setArrayIndex(static_cast(p)); - WriteSetting(QStringLiteral("name"), - QString::fromStdString(Settings::values.touch_from_button_maps[p].name), - QStringLiteral("default")); - qt_config->beginWriteArray(QStringLiteral("entries")); - for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); - ++q) { - qt_config->setArrayIndex(static_cast(q)); - WriteSetting( - QStringLiteral("bind"), - QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q])); - } - qt_config->endArray(); - } - qt_config->endArray(); - qt_config->endGroup(); } diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index aa929d1348..ca0d29c6c7 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -38,6 +38,7 @@ private: void ReadKeyboardValues(); void ReadMouseValues(); void ReadTouchscreenValues(); + void ReadMotionTouchValues(); // Read functions bases off the respective config section names. void ReadAudioValues(); @@ -64,6 +65,7 @@ private: void SaveDebugValues(); void SaveMouseValues(); void SaveTouchscreenValues(); + void SaveMotionTouchValues(); // 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 62c504286c..ae3e31762c 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -128,15 +128,14 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) { }); connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog, [this] { CallConfigureDialog(*this); }); + connect(advanced, &ConfigureInputAdvanced::CallMotionTouchConfigDialog, + [this, input_subsystem] { + CallConfigureDialog(*this, input_subsystem); + }); connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); }); - connect(ui->buttonMotionTouch, &QPushButton::clicked, [this] { - QDialog* motion_touch_dialog = new ConfigureMotionTouch(this); - return motion_touch_dialog->exec(); - }); - RetranslateUI(); LoadConfiguration(); } diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index db42b826bd..c00e3faabd 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -86,6 +86,8 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); }); connect(ui->touchscreen_advanced, &QPushButton::clicked, this, [this] { CallTouchscreenConfigDialog(); }); + connect(ui->buttonMotionTouch, &QPushButton::clicked, this, + [this] { CallMotionTouchConfigDialog(); }); LoadConfiguration(); } diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h index d8fcec52d9..50bb877680 100644 --- a/src/yuzu/configuration/configure_input_advanced.h +++ b/src/yuzu/configuration/configure_input_advanced.h @@ -28,6 +28,7 @@ signals: void CallDebugControllerDialog(); void CallMouseConfigDialog(); void CallTouchscreenConfigDialog(); + void CallMotionTouchConfigDialog(); private: void changeEvent(QEvent* event) override; diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index cb79e47cec..1a4b3c9966 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -8,7 +8,11 @@ #include #include #include +#include "common/logging/log.h" +#include "core/settings.h" #include "input_common/main.h" +#include "input_common/udp/client.h" +#include "input_common/udp/udp.h" #include "ui_configure_motion_touch.h" #include "yuzu/configuration/configure_motion_touch.h" #include "yuzu/configuration/configure_touch_from_button.h" @@ -21,8 +25,9 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, status_label = new QLabel(tr("Communicating with the server...")); cancel_button = new QPushButton(tr("Cancel")); connect(cancel_button, &QPushButton::clicked, this, [this] { - if (!completed) + if (!completed) { job->Stop(); + } accept(); }); layout->addWidget(status_label); @@ -61,36 +66,40 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, CalibrationConfigurationDialog::~CalibrationConfigurationDialog() = default; -void CalibrationConfigurationDialog::UpdateLabelText(QString text) { +void CalibrationConfigurationDialog::UpdateLabelText(const QString& text) { status_label->setText(text); } -void CalibrationConfigurationDialog::UpdateButtonText(QString text) { +void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) { cancel_button->setText(text); } -const std::array, 2> MotionProviders = { - {{"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")}, - {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}}}; +constexpr std::array, 2> MotionProviders = {{ + {"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")}, + {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}, +}}; -const std::array, 2> TouchProviders = { - {{"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")}, - {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}}}; +constexpr std::array, 2> TouchProviders = {{ + {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")}, + {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}, +}}; -ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent) - : QDialog(parent), ui(std::make_unique()) { +ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, + InputCommon::InputSubsystem* input_subsystem_) + : QDialog(parent), input_subsystem{input_subsystem_}, + ui(std::make_unique()) { ui->setupUi(this); - for (auto [provider, name] : MotionProviders) { + for (const auto [provider, name] : MotionProviders) { ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider)); } - for (auto [provider, name] : TouchProviders) { + for (const auto [provider, name] : TouchProviders) { ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider)); } ui->udp_learn_more->setOpenExternalLinks(true); ui->udp_learn_more->setText( tr("Learn More")); @@ -130,10 +139,11 @@ void ConfigureMotionTouch::SetConfiguration() { } void ConfigureMotionTouch::UpdateUiDisplay() { - std::string motion_engine = ui->motion_provider->currentData().toString().toStdString(); - std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); + const QString motion_engine = ui->motion_provider->currentData().toString(); + const QString touch_engine = ui->touch_provider->currentData().toString(); + QString cemuhook_udp = QStringLiteral("cemuhookudp"); - if (motion_engine == "motion_emu") { + if (motion_engine == QStringLiteral("motion_emu")) { ui->motion_sensitivity_label->setVisible(true); ui->motion_sensitivity->setVisible(true); } else { @@ -141,20 +151,19 @@ void ConfigureMotionTouch::UpdateUiDisplay() { ui->motion_sensitivity->setVisible(false); } - if (touch_engine == "cemuhookudp") { + if (touch_engine == cemuhook_udp) { ui->touch_calibration->setVisible(true); ui->touch_calibration_config->setVisible(true); ui->touch_calibration_label->setVisible(true); - ui->touch_calibration->setText(QStringLiteral("(%1, %2) - (%3, %4)") - .arg(QString::number(min_x), QString::number(min_y), - QString::number(max_x), QString::number(max_y))); + ui->touch_calibration->setText( + QStringLiteral("(%1, %2) - (%3, %4)").arg(min_x).arg(min_y).arg(max_x).arg(max_y)); } else { ui->touch_calibration->setVisible(false); ui->touch_calibration_config->setVisible(false); ui->touch_calibration_label->setVisible(false); } - if (motion_engine == "cemuhookudp" || touch_engine == "cemuhookudp") { + if (motion_engine == cemuhook_udp || touch_engine == cemuhook_udp) { ui->udp_config_group_box->setVisible(true); } else { ui->udp_config_group_box->setVisible(false); @@ -162,11 +171,9 @@ void ConfigureMotionTouch::UpdateUiDisplay() { } void ConfigureMotionTouch::ConnectEvents() { - connect(ui->motion_provider, - static_cast(&QComboBox::currentIndexChanged), this, + connect(ui->motion_provider, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) { UpdateUiDisplay(); }); - connect(ui->touch_provider, - static_cast(&QComboBox::currentIndexChanged), this, + connect(ui->touch_provider, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) { UpdateUiDisplay(); }); connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); connect(ui->touch_calibration_config, &QPushButton::clicked, this, @@ -174,8 +181,9 @@ void ConfigureMotionTouch::ConnectEvents() { connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, &ConfigureMotionTouch::OnConfigureTouchFromButton); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] { - if (CanCloseDialog()) + if (CanCloseDialog()) { reject(); + } }); } @@ -199,15 +207,15 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() { void ConfigureMotionTouch::OnConfigureTouchCalibration() { ui->touch_calibration_config->setEnabled(false); ui->touch_calibration_config->setText(tr("Configuring")); - CalibrationConfigurationDialog* dialog = new CalibrationConfigurationDialog( + CalibrationConfigurationDialog dialog( this, ui->udp_server->text().toStdString(), static_cast(ui->udp_port->text().toUInt()), static_cast(ui->udp_pad_index->currentIndex()), 24872); - dialog->exec(); - if (dialog->completed) { - min_x = dialog->min_x; - min_y = dialog->min_y; - max_x = dialog->max_x; - max_y = dialog->max_y; + dialog.exec(); + if (dialog.completed) { + min_x = dialog.min_x; + min_y = dialog.min_y; + max_x = dialog.max_x; + max_y = dialog.max_y; LOG_INFO(Frontend, "UDP touchpad calibration config success: min_x={}, min_y={}, max_x={}, max_y={}", min_x, min_y, max_x, max_y); @@ -220,10 +228,11 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() { } void ConfigureMotionTouch::closeEvent(QCloseEvent* event) { - if (CanCloseDialog()) + if (CanCloseDialog()) { event->accept(); - else + } else { event->ignore(); + } } void ConfigureMotionTouch::ShowUDPTestResult(bool result) { @@ -242,7 +251,7 @@ void ConfigureMotionTouch::ShowUDPTestResult(bool result) { } void ConfigureMotionTouch::OnConfigureTouchFromButton() { - ConfigureTouchFromButton dialog{this, touch_from_button_maps, + ConfigureTouchFromButton dialog{this, touch_from_button_maps, input_subsystem, ui->touch_from_button_map->currentIndex()}; if (dialog.exec() != QDialog::Accepted) { return; @@ -269,8 +278,9 @@ bool ConfigureMotionTouch::CanCloseDialog() { } void ConfigureMotionTouch::ApplyConfiguration() { - if (!CanCloseDialog()) + if (!CanCloseDialog()) { return; + } std::string motion_engine = ui->motion_provider->currentData().toString().toStdString(); std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); @@ -298,7 +308,7 @@ void ConfigureMotionTouch::ApplyConfiguration() { Settings::values.udp_input_address = ui->udp_server->text().toStdString(); Settings::values.udp_input_port = static_cast(ui->udp_port->text().toInt()); Settings::values.udp_pad_index = static_cast(ui->udp_pad_index->currentIndex()); - InputCommon::ReloadInputDevices(); + input_subsystem->ReloadInputDevices(); accept(); } diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h index 1a4f500224..2a7cdfed7f 100644 --- a/src/yuzu/configuration/configure_motion_touch.h +++ b/src/yuzu/configuration/configure_motion_touch.h @@ -7,29 +7,30 @@ #include #include #include "common/param_package.h" -#include "core/settings.h" -#include "input_common/udp/client.h" -#include "input_common/udp/udp.h" -class QVBoxLayout; class QLabel; class QPushButton; +class QVBoxLayout; namespace Ui { class ConfigureMotionTouch; } +namespace InputCommon::CemuhookUDP { +class CalibrationConfigurationJob; +} + /// A dialog for touchpad calibration configuration. class CalibrationConfigurationDialog : public QDialog { Q_OBJECT public: explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, u8 pad_index, u16 client_id); - ~CalibrationConfigurationDialog(); + ~CalibrationConfigurationDialog() override; private: - Q_INVOKABLE void UpdateLabelText(QString text); - Q_INVOKABLE void UpdateButtonText(QString text); + Q_INVOKABLE void UpdateLabelText(const QString& text); + Q_INVOKABLE void UpdateButtonText(const QString& text); QVBoxLayout* layout; QLabel* status_label; @@ -38,7 +39,10 @@ private: // Configuration results bool completed{}; - u16 min_x, min_y, max_x, max_y; + u16 min_x{}; + u16 min_y{}; + u16 max_x{}; + u16 max_y{}; friend class ConfigureMotionTouch; }; @@ -47,7 +51,7 @@ class ConfigureMotionTouch : public QDialog { Q_OBJECT public: - explicit ConfigureMotionTouch(QWidget* parent = nullptr); + explicit ConfigureMotionTouch(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_); ~ConfigureMotionTouch() override; public slots: @@ -69,9 +73,14 @@ private: std::unique_ptr ui; // Coordinate system of the CemuhookUDP touch provider - int min_x, min_y, max_x, max_y; + int min_x{}; + int min_y{}; + int max_x{}; + int max_y{}; bool udp_test_in_progress{}; + InputCommon::InputSubsystem* input_subsystem; + std::vector touch_from_button_maps; }; diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp index 0a0448cea2..0147e2ac33 100644 --- a/src/yuzu/configuration/configure_touch_from_button.cpp +++ b/src/yuzu/configuration/configure_touch_from_button.cpp @@ -10,6 +10,8 @@ #include #include #include "common/param_package.h" +#include "core/frontend/framebuffer_layout.h" +#include "core/settings.h" #include "input_common/main.h" #include "ui_configure_touch_from_button.h" #include "yuzu/configuration/configure_touch_from_button.h" @@ -68,15 +70,16 @@ static QString ButtonToText(const Common::ParamPackage& param) { ConfigureTouchFromButton::ConfigureTouchFromButton( QWidget* parent, const std::vector& touch_maps, - const int default_index) - : QDialog(parent), ui(std::make_unique()), touch_maps(touch_maps), - selected_index(default_index), timeout_timer(std::make_unique()), - poll_timer(std::make_unique()) { + InputCommon::InputSubsystem* input_subsystem_, const int default_index) + : QDialog(parent), ui(std::make_unique()), + touch_maps(touch_maps), input_subsystem{input_subsystem_}, selected_index(default_index), + timeout_timer(std::make_unique()), poll_timer(std::make_unique()) { ui->setupUi(this); - binding_list_model = std::make_unique(0, 3, this); - binding_list_model->setHorizontalHeaderLabels({tr("Button"), tr("X"), tr("Y")}); - ui->binding_list->setModel(binding_list_model.get()); + binding_list_model = new QStandardItemModel(0, 3, this); + binding_list_model->setHorizontalHeaderLabels( + {tr("Button"), tr("X", "X axis"), tr("Y", "Y axis")}); + ui->binding_list->setModel(binding_list_model); ui->bottom_screen->SetCoordLabel(ui->coord_label); SetConfiguration(); @@ -92,11 +95,12 @@ void ConfigureTouchFromButton::showEvent(QShowEvent* ev) { // width values are not valid in the constructor const int w = ui->binding_list->viewport()->contentsRect().width() / binding_list_model->columnCount(); - if (w > 0) { - ui->binding_list->setColumnWidth(0, w); - ui->binding_list->setColumnWidth(1, w); - ui->binding_list->setColumnWidth(2, w); + if (w <= 0) { + return; } + ui->binding_list->setColumnWidth(0, w); + ui->binding_list->setColumnWidth(1, w); + ui->binding_list->setColumnWidth(2, w); } void ConfigureTouchFromButton::SetConfiguration() { @@ -122,7 +126,7 @@ void ConfigureTouchFromButton::UpdateUiDisplay() { QStandardItem* ycoord = new QStandardItem(QString::number(package.Get("y", 0))); binding_list_model->appendRow({button, xcoord, ycoord}); - int dot = ui->bottom_screen->AddDot(package.Get("x", 0), package.Get("y", 0)); + const int dot = ui->bottom_screen->AddDot(package.Get("x", 0), package.Get("y", 0)); button->setData(dot, DataRoleDot); } } @@ -144,7 +148,7 @@ void ConfigureTouchFromButton::ConnectEvents() { &ConfigureTouchFromButton::EditBinding); connect(ui->binding_list->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ConfigureTouchFromButton::OnBindingSelection); - connect(binding_list_model.get(), &QStandardItemModel::itemChanged, this, + connect(binding_list_model, &QStandardItemModel::itemChanged, this, &ConfigureTouchFromButton::OnBindingChanged); connect(ui->binding_list->model(), &QStandardItemModel::rowsAboutToBeRemoved, this, &ConfigureTouchFromButton::OnBindingDeleted); @@ -231,7 +235,7 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is input_setter = [this, row_index, is_new](const Common::ParamPackage& params, const bool cancel) { - auto cell = binding_list_model->item(row_index, 0); + auto* cell = binding_list_model->item(row_index, 0); if (cancel) { if (is_new) { binding_list_model->removeRow(row_index); @@ -245,7 +249,7 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is } }; - device_pollers = InputCommon::Polling::GetPollers(InputCommon::Polling::DeviceType::Button); + device_pollers = input_subsystem->GetPollers(InputCommon::Polling::DeviceType::Button); for (auto& poller : device_pollers) { poller->Start(); @@ -259,15 +263,15 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is } void ConfigureTouchFromButton::NewBinding(const QPoint& pos) { - QStandardItem* button = new QStandardItem(); + auto* button = new QStandardItem(); button->setEditable(false); - QStandardItem* xcoord = new QStandardItem(QString::number(pos.x())); - QStandardItem* ycoord = new QStandardItem(QString::number(pos.y())); + auto* x_coord = new QStandardItem(QString::number(pos.x())); + auto* y_coord = new QStandardItem(QString::number(pos.y())); const int dot_id = ui->bottom_screen->AddDot(pos.x(), pos.y()); button->setData(dot_id, DataRoleDot); - binding_list_model->appendRow({button, xcoord, ycoord}); + binding_list_model->appendRow({button, x_coord, y_coord}); ui->binding_list->setFocus(); ui->binding_list->setCurrentIndex(button->index()); @@ -282,11 +286,11 @@ void ConfigureTouchFromButton::EditBinding(const QModelIndex& qi) { void ConfigureTouchFromButton::DeleteBinding() { const int row_index = ui->binding_list->currentIndex().row(); - if (row_index >= 0) { - ui->bottom_screen->RemoveDot( - binding_list_model->index(row_index, 0).data(DataRoleDot).toInt()); - binding_list_model->removeRow(row_index); + if (row_index < 0) { + return; } + ui->bottom_screen->RemoveDot(binding_list_model->index(row_index, 0).data(DataRoleDot).toInt()); + binding_list_model->removeRow(row_index); } void ConfigureTouchFromButton::OnBindingSelection(const QItemSelection& selected, @@ -329,7 +333,7 @@ void ConfigureTouchFromButton::OnBindingChanged(QStandardItem* item) { void ConfigureTouchFromButton::OnBindingDeleted(const QModelIndex& parent, int first, int last) { for (int i = first; i <= last; ++i) { - auto ix = binding_list_model->index(i, 0); + const auto ix = binding_list_model->index(i, 0); if (!ix.isValid()) { return; } @@ -422,7 +426,7 @@ int TouchScreenPreview::AddDot(const int device_x, const int device_y) { dot_font.setStyleHint(QFont::Monospace); dot_font.setPointSize(20); - QLabel* dot = new QLabel(this); + auto* dot = new QLabel(this); dot->setAttribute(Qt::WA_TranslucentBackground); dot->setFont(dot_font); dot->setText(QChar(0xD7)); // U+00D7 Multiplication Sign @@ -440,13 +444,14 @@ int TouchScreenPreview::AddDot(const int device_x, const int device_y) { } void TouchScreenPreview::RemoveDot(const int id) { - for (auto dot_it = dots.begin(); dot_it != dots.end(); ++dot_it) { - if (dot_it->first == id) { - dot_it->second->deleteLater(); - dots.erase(dot_it); - return; - } + const auto iter = std::find_if(dots.begin(), dots.end(), + [id](const auto& entry) { return entry.first == id; }); + if (iter == dots.cend()) { + return; } + + iter->second->deleteLater(); + dots.erase(iter); } void TouchScreenPreview::HighlightDot(const int id, const bool active) const { @@ -470,14 +475,15 @@ void TouchScreenPreview::HighlightDot(const int id, const bool active) const { } void TouchScreenPreview::MoveDot(const int id, const int device_x, const int device_y) const { - for (const auto& dot : dots) { - if (dot.first == id) { - dot.second->setProperty(PropX, device_x); - dot.second->setProperty(PropY, device_y); - PositionDot(dot.second, device_x, device_y); - return; - } + const auto iter = std::find_if(dots.begin(), dots.end(), + [id](const auto& entry) { return entry.first == id; }); + if (iter == dots.cend()) { + return; } + + iter->second->setProperty(PropX, device_x); + iter->second->setProperty(PropY, device_y); + PositionDot(iter->second, device_x, device_y); } void TouchScreenPreview::resizeEvent(QResizeEvent* event) { @@ -521,11 +527,12 @@ void TouchScreenPreview::leaveEvent(QEvent* event) { } void TouchScreenPreview::mousePressEvent(QMouseEvent* event) { - if (event->button() == Qt::MouseButton::LeftButton) { - const auto pos = MapToDeviceCoords(event->x(), event->y()); - if (pos) { - emit DotAdded(*pos); - } + if (event->button() != Qt::MouseButton::LeftButton) { + return; + } + const auto pos = MapToDeviceCoords(event->x(), event->y()); + if (pos) { + emit DotAdded(*pos); } } @@ -601,12 +608,17 @@ std::optional TouchScreenPreview::MapToDeviceCoords(const int screen_x, void TouchScreenPreview::PositionDot(QLabel* const dot, const int device_x, const int device_y) const { - dot->move(static_cast( - static_cast(device_x >= 0 ? device_x : dot->property(PropX).toInt()) * - (contentsRect().width() - 1) / (Layout::ScreenUndocked::Width - 1) + - contentsMargins().left() - static_cast(dot->width()) / 2 + 0.5f), - static_cast( - static_cast(device_y >= 0 ? device_y : dot->property(PropY).toInt()) * - (contentsRect().height() - 1) / (Layout::ScreenUndocked::Height - 1) + - contentsMargins().top() - static_cast(dot->height()) / 2 + 0.5f)); + const float device_coord_x = + static_cast(device_x >= 0 ? device_x : dot->property(PropX).toInt()); + int x_coord = static_cast( + device_coord_x * (contentsRect().width() - 1) / (Layout::ScreenUndocked::Width - 1) + + contentsMargins().left() - static_cast(dot->width()) / 2 + 0.5f); + + const float device_coord_y = + static_cast(device_y >= 0 ? device_y : dot->property(PropY).toInt()); + const int y_coord = static_cast( + device_coord_y * (contentsRect().height() - 1) / (Layout::ScreenUndocked::Height - 1) + + contentsMargins().top() - static_cast(dot->height()) / 2 + 0.5f); + + dot->move(x_coord, y_coord); } diff --git a/src/yuzu/configuration/configure_touch_from_button.h b/src/yuzu/configuration/configure_touch_from_button.h index c926db0123..0ddc54268d 100644 --- a/src/yuzu/configuration/configure_touch_from_button.h +++ b/src/yuzu/configuration/configure_touch_from_button.h @@ -9,8 +9,6 @@ #include #include #include -#include "core/frontend/framebuffer_layout.h" -#include "core/settings.h" class QItemSelection; class QModelIndex; @@ -18,6 +16,10 @@ class QStandardItemModel; class QStandardItem; class QTimer; +namespace InputCommon { +class InputSubsystem; +} + namespace Common { class ParamPackage; } @@ -32,12 +34,17 @@ namespace Ui { class ConfigureTouchFromButton; } +namespace Settings { +struct TouchFromButtonMap; +} + class ConfigureTouchFromButton : public QDialog { Q_OBJECT public: explicit ConfigureTouchFromButton(QWidget* parent, const std::vector& touch_maps, + InputCommon::InputSubsystem* input_subsystem_, int default_index = 0); ~ConfigureTouchFromButton() override; @@ -51,8 +58,8 @@ public slots: void SetCoordinates(int dot_id, const QPoint& pos); protected: - virtual void showEvent(QShowEvent* ev) override; - virtual void keyPressEvent(QKeyEvent* event) override; + void showEvent(QShowEvent* ev) override; + void keyPressEvent(QKeyEvent* event) override; private slots: void NewMapping(); @@ -73,10 +80,12 @@ private: void SaveCurrentMapping(); std::unique_ptr ui; - std::unique_ptr binding_list_model; std::vector touch_maps; + QStandardItemModel* binding_list_model; int selected_index; + InputCommon::InputSubsystem* input_subsystem; + std::unique_ptr timeout_timer; std::unique_ptr poll_timer; std::vector> device_pollers; diff --git a/src/yuzu/configuration/configure_touch_widget.h b/src/yuzu/configuration/configure_touch_widget.h index c85960f823..347b465836 100644 --- a/src/yuzu/configuration/configure_touch_widget.h +++ b/src/yuzu/configuration/configure_touch_widget.h @@ -33,11 +33,11 @@ signals: void DotMoved(int dot_id, const QPoint& pos); protected: - virtual void resizeEvent(QResizeEvent*) override; - virtual void mouseMoveEvent(QMouseEvent*) override; - virtual void leaveEvent(QEvent*) override; - virtual void mousePressEvent(QMouseEvent*) override; - virtual bool eventFilter(QObject*, QEvent*) override; + void resizeEvent(QResizeEvent*) override; + void mouseMoveEvent(QMouseEvent*) override; + void leaveEvent(QEvent*) override; + void mousePressEvent(QMouseEvent*) override; + bool eventFilter(QObject*, QEvent*) override; private: std::optional MapToDeviceCoords(int screen_x, int screen_y) const; @@ -53,9 +53,10 @@ private: static constexpr char PropX[] = "device_x"; static constexpr char PropY[] = "device_y"; - struct { + struct DragState { bool active = false; QPointer dot; QPoint start_pos; - } drag_state; + }; + DragState drag_state; }; From 0aa6ec42764756c8312da6faf5e67d85c3c28b2f Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sat, 29 Aug 2020 21:34:01 +0200 Subject: [PATCH 3/4] Reolve reorder warning --- src/yuzu/configuration/configure_motion_touch.h | 4 ++-- src/yuzu/configuration/configure_touch_from_button.ui | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h index 2a7cdfed7f..0fafb3aed7 100644 --- a/src/yuzu/configuration/configure_motion_touch.h +++ b/src/yuzu/configuration/configure_motion_touch.h @@ -70,6 +70,8 @@ private: void ConnectEvents(); bool CanCloseDialog(); + InputCommon::InputSubsystem* input_subsystem; + std::unique_ptr ui; // Coordinate system of the CemuhookUDP touch provider @@ -80,7 +82,5 @@ private: bool udp_test_in_progress{}; - InputCommon::InputSubsystem* input_subsystem; - std::vector touch_from_button_maps; }; diff --git a/src/yuzu/configuration/configure_touch_from_button.ui b/src/yuzu/configuration/configure_touch_from_button.ui index d0598bdbd6..f581e27e03 100644 --- a/src/yuzu/configuration/configure_touch_from_button.ui +++ b/src/yuzu/configuration/configure_touch_from_button.ui @@ -205,7 +205,7 @@ Drag points to change position, or double-click table cells to edit values. TouchScreenPreview QFrame -
citra_qt/configuration/configure_touch_widget.h
+
yuzu/configuration/configure_touch_widget.h
1 From d1e1ea0fef0ddfe914f14a2d547b922b71081695 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sun, 30 Aug 2020 00:07:38 +0200 Subject: [PATCH 4/4] Address second batch of reviews --- src/core/frontend/framebuffer_layout.h | 1 + src/input_common/main.h | 4 +--- src/input_common/touch_from_button.cpp | 2 +- src/input_common/touch_from_button.h | 2 -- .../configure_input_advanced.cpp | 2 +- .../configuration/configure_motion_touch.cpp | 18 +++++++++--------- .../configuration/configure_motion_touch.h | 8 ++++++-- .../configure_touch_from_button.cpp | 1 - .../configure_touch_from_button.h | 19 ++++++++----------- 9 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 91ecc30ab4..e2e3bbbb39 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -4,6 +4,7 @@ #pragma once +#include "common/common_types.h" #include "common/math_util.h" namespace Layout { diff --git a/src/input_common/main.h b/src/input_common/main.h index 512215e7e6..f3fbf696e3 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -21,9 +21,6 @@ namespace Settings::NativeButton { enum Values : int; } -/// Reloads the input devices -void ReloadInputDevices(); - namespace InputCommon { namespace Polling { @@ -118,6 +115,7 @@ public: /// Retrieves the underlying GameCube button handler. [[nodiscard]] const GCButtonFactory* GetGCButtons() const; + /// Reloads the input devices void ReloadInputDevices(); /// Get all DevicePoller from all backends for a specific device type diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp index d028dfa0d4..98da0ef1a7 100644 --- a/src/input_common/touch_from_button.cpp +++ b/src/input_common/touch_from_button.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/frontend/framebuffer_layout.h" #include "core/settings.h" #include "input_common/touch_from_button.h" @@ -43,7 +44,6 @@ private: std::unique_ptr TouchFromButtonFactory::Create( const Common::ParamPackage& params) { - return std::make_unique(); } diff --git a/src/input_common/touch_from_button.h b/src/input_common/touch_from_button.h index cfb82f108f..8b4d1aa961 100644 --- a/src/input_common/touch_from_button.h +++ b/src/input_common/touch_from_button.h @@ -5,7 +5,6 @@ #pragma once #include -#include "core/frontend/framebuffer_layout.h" #include "core/frontend/input.h" namespace InputCommon { @@ -17,7 +16,6 @@ class TouchFromButtonFactory final : public Input::Factory { public: /** * Creates a touch device from a list of button devices - * @param unused */ std::unique_ptr Create(const Common::ParamPackage& params) override; }; diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index c00e3faabd..81f9dc16c8 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -87,7 +87,7 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) connect(ui->touchscreen_advanced, &QPushButton::clicked, this, [this] { CallTouchscreenConfigDialog(); }); connect(ui->buttonMotionTouch, &QPushButton::clicked, this, - [this] { CallMotionTouchConfigDialog(); }); + &ConfigureInputAdvanced::CallMotionTouchConfigDialog); LoadConfiguration(); } diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index 1a4b3c9966..c7d0851519 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -89,10 +89,10 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, : QDialog(parent), input_subsystem{input_subsystem_}, ui(std::make_unique()) { ui->setupUi(this); - for (const auto [provider, name] : MotionProviders) { + for (const auto& [provider, name] : MotionProviders) { ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider)); } - for (const auto [provider, name] : TouchProviders) { + for (const auto& [provider, name] : TouchProviders) { ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider)); } @@ -111,10 +111,10 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, ConfigureMotionTouch::~ConfigureMotionTouch() = default; void ConfigureMotionTouch::SetConfiguration() { - Common::ParamPackage motion_param(Settings::values.motion_device); - Common::ParamPackage touch_param(Settings::values.touch_device); - std::string motion_engine = motion_param.Get("engine", "motion_emu"); - std::string touch_engine = touch_param.Get("engine", "emu_window"); + const Common::ParamPackage motion_param(Settings::values.motion_device); + const Common::ParamPackage touch_param(Settings::values.touch_device); + const std::string motion_engine = motion_param.Get("engine", "motion_emu"); + const std::string touch_engine = touch_param.Get("engine", "emu_window"); ui->motion_provider->setCurrentIndex( ui->motion_provider->findData(QString::fromStdString(motion_engine))); @@ -141,7 +141,7 @@ void ConfigureMotionTouch::SetConfiguration() { void ConfigureMotionTouch::UpdateUiDisplay() { const QString motion_engine = ui->motion_provider->currentData().toString(); const QString touch_engine = ui->touch_provider->currentData().toString(); - QString cemuhook_udp = QStringLiteral("cemuhookudp"); + const QString cemuhook_udp = QStringLiteral("cemuhookudp"); if (motion_engine == QStringLiteral("motion_emu")) { ui->motion_sensitivity_label->setVisible(true); @@ -286,8 +286,8 @@ void ConfigureMotionTouch::ApplyConfiguration() { std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); Common::ParamPackage motion_param{}, touch_param{}; - motion_param.Set("engine", motion_engine); - touch_param.Set("engine", touch_engine); + motion_param.Set("engine", std::move(motion_engine)); + touch_param.Set("engine", std::move(touch_engine)); if (motion_engine == "motion_emu") { motion_param.Set("sensitivity", static_cast(ui->motion_sensitivity->value())); diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h index 0fafb3aed7..3d4b5d6597 100644 --- a/src/yuzu/configuration/configure_motion_touch.h +++ b/src/yuzu/configuration/configure_motion_touch.h @@ -12,14 +12,18 @@ class QLabel; class QPushButton; class QVBoxLayout; -namespace Ui { -class ConfigureMotionTouch; +namespace InputCommon { +class InputSubsystem; } namespace InputCommon::CemuhookUDP { class CalibrationConfigurationJob; } +namespace Ui { +class ConfigureMotionTouch; +} + /// A dialog for touchpad calibration configuration. class CalibrationConfigurationDialog : public QDialog { Q_OBJECT diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp index 0147e2ac33..15557e4b8c 100644 --- a/src/yuzu/configuration/configure_touch_from_button.cpp +++ b/src/yuzu/configuration/configure_touch_from_button.cpp @@ -74,7 +74,6 @@ ConfigureTouchFromButton::ConfigureTouchFromButton( : QDialog(parent), ui(std::make_unique()), touch_maps(touch_maps), input_subsystem{input_subsystem_}, selected_index(default_index), timeout_timer(std::make_unique()), poll_timer(std::make_unique()) { - ui->setupUi(this); binding_list_model = new QStandardItemModel(0, 3, this); binding_list_model->setHorizontalHeaderLabels( diff --git a/src/yuzu/configuration/configure_touch_from_button.h b/src/yuzu/configuration/configure_touch_from_button.h index 0ddc54268d..d9513e3bc6 100644 --- a/src/yuzu/configuration/configure_touch_from_button.h +++ b/src/yuzu/configuration/configure_touch_from_button.h @@ -16,28 +16,26 @@ class QStandardItemModel; class QStandardItem; class QTimer; -namespace InputCommon { -class InputSubsystem; -} - namespace Common { class ParamPackage; } namespace InputCommon { -namespace Polling { -class DevicePoller; +class InputSubsystem; } -} // namespace InputCommon -namespace Ui { -class ConfigureTouchFromButton; +namespace InputCommon::Polling { +class DevicePoller; } namespace Settings { struct TouchFromButtonMap; } +namespace Ui { +class ConfigureTouchFromButton; +} + class ConfigureTouchFromButton : public QDialog { Q_OBJECT @@ -82,9 +80,8 @@ private: std::unique_ptr ui; std::vector touch_maps; QStandardItemModel* binding_list_model; - int selected_index; - InputCommon::InputSubsystem* input_subsystem; + int selected_index; std::unique_ptr timeout_timer; std::unique_ptr poll_timer;