diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 8ff38fe645..ebd6aa738f 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -63,7 +63,7 @@ add_executable(dolphin-emu Config/Mapping/MappingCommon.cpp Config/Mapping/MappingIndicator.cpp Config/Mapping/MappingNumeric.cpp - Config/Mapping/MappingRadio.cpp + Config/Mapping/MappingRadio.cpp Config/Mapping/MappingWidget.cpp Config/Mapping/MappingWindow.cpp Config/Mapping/WiimoteEmuExtension.cpp @@ -113,7 +113,7 @@ add_executable(dolphin-emu Settings/USBDeviceAddToWhitelistDialog.cpp TAS/GCTASInputWindow.cpp TAS/WiiTASInputWindow.cpp - TAS/Shared.cpp + TAS/TASInputWindow.cpp TAS/StickWidget.cpp TAS/IRWidget.cpp Updater.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index b87180eb2d..a1ddc418e9 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -110,6 +110,7 @@ + @@ -246,6 +247,7 @@ + @@ -318,9 +320,9 @@ + - @@ -377,7 +379,6 @@ - diff --git a/Source/Core/DolphinQt/TAS/GCTASInputWindow.cpp b/Source/Core/DolphinQt/TAS/GCTASInputWindow.cpp index b2a3d20fbf..eb23072faf 100644 --- a/Source/Core/DolphinQt/TAS/GCTASInputWindow.cpp +++ b/Source/Core/DolphinQt/TAS/GCTASInputWindow.cpp @@ -12,35 +12,32 @@ #include "Common/CommonTypes.h" -#include "DolphinQt/TAS/Shared.h" - #include "InputCommon/GCPadStatus.h" -GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : QDialog(parent) +GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : TASInputWindow(parent) { setWindowTitle(tr("GameCube TAS Input %1").arg(num + 1)); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - auto* main_stick_box = CreateStickInputs(this, tr("Main Stick"), m_x_main_stick_value, - m_y_main_stick_value, 255, 255, Qt::Key_F, Qt::Key_G); - auto* c_stick_box = CreateStickInputs(this, tr("C Stick"), m_x_c_stick_value, m_y_c_stick_value, - 255, 255, Qt::Key_H, Qt::Key_J); + m_main_stick_box = CreateStickInputs(tr("Main Stick"), m_x_main_stick_value, m_y_main_stick_value, + 255, 255, Qt::Key_F, Qt::Key_G); + m_c_stick_box = CreateStickInputs(tr("C Stick"), m_x_c_stick_value, m_y_c_stick_value, 255, 255, + Qt::Key_H, Qt::Key_J); auto* top_layout = new QHBoxLayout; - top_layout->addWidget(main_stick_box); - top_layout->addWidget(c_stick_box); + top_layout->addWidget(m_main_stick_box); + top_layout->addWidget(m_c_stick_box); - auto* triggers_box = new QGroupBox(tr("Triggers")); + m_triggers_box = new QGroupBox(tr("Triggers")); - auto* l_trigger_layout = CreateSliderValuePairLayout(this, tr("Left"), m_l_trigger_value, 255, - Qt::Key_N, triggers_box); - auto* r_trigger_layout = CreateSliderValuePairLayout(this, tr("Right"), m_r_trigger_value, 255, - Qt::Key_M, triggers_box); + auto* l_trigger_layout = + CreateSliderValuePairLayout(tr("Left"), m_l_trigger_value, 255, Qt::Key_N, m_triggers_box); + auto* r_trigger_layout = + CreateSliderValuePairLayout(tr("Right"), m_r_trigger_value, 255, Qt::Key_M, m_triggers_box); auto* triggers_layout = new QVBoxLayout; triggers_layout->addLayout(l_trigger_layout); triggers_layout->addLayout(r_trigger_layout); - triggers_box->setLayout(triggers_layout); + m_triggers_box->setLayout(triggers_layout); m_a_button = new QCheckBox(QStringLiteral("&A")); m_b_button = new QCheckBox(QStringLiteral("&B")); @@ -76,42 +73,35 @@ GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : QDialog(parent) buttons_layout->addLayout(buttons_layout1); buttons_layout->addLayout(buttons_layout2); - auto* buttons_box = new QGroupBox(tr("Buttons")); - buttons_box->setLayout(buttons_layout); + m_buttons_box = new QGroupBox(tr("Buttons")); + m_buttons_box->setLayout(buttons_layout); auto* layout = new QVBoxLayout; layout->addLayout(top_layout); - layout->addWidget(triggers_box); - layout->addWidget(buttons_box); + layout->addWidget(m_triggers_box); + layout->addWidget(m_buttons_box); + layout->addWidget(m_use_controller); setLayout(layout); } -static void SetButton(QCheckBox* button, GCPadStatus* pad, u16 mask) -{ - if (button->isChecked()) - pad->button |= mask; - else - pad->button &= ~mask; -} - void GCTASInputWindow::GetValues(GCPadStatus* pad) { if (!isVisible()) return; - SetButton(m_a_button, pad, PAD_BUTTON_A); - SetButton(m_b_button, pad, PAD_BUTTON_B); - SetButton(m_x_button, pad, PAD_BUTTON_X); - SetButton(m_y_button, pad, PAD_BUTTON_Y); - SetButton(m_z_button, pad, PAD_TRIGGER_Z); - SetButton(m_l_button, pad, PAD_TRIGGER_L); - SetButton(m_r_button, pad, PAD_TRIGGER_R); - SetButton(m_left_button, pad, PAD_BUTTON_LEFT); - SetButton(m_up_button, pad, PAD_BUTTON_UP); - SetButton(m_down_button, pad, PAD_BUTTON_DOWN); - SetButton(m_right_button, pad, PAD_BUTTON_RIGHT); - SetButton(m_start_button, pad, PAD_BUTTON_START); + GetButton(m_a_button, pad->button, PAD_BUTTON_A); + GetButton(m_b_button, pad->button, PAD_BUTTON_B); + GetButton(m_x_button, pad->button, PAD_BUTTON_X); + GetButton(m_y_button, pad->button, PAD_BUTTON_Y); + GetButton(m_z_button, pad->button, PAD_TRIGGER_Z); + GetButton(m_l_button, pad->button, PAD_TRIGGER_L); + GetButton(m_r_button, pad->button, PAD_TRIGGER_R); + GetButton(m_left_button, pad->button, PAD_BUTTON_LEFT); + GetButton(m_up_button, pad->button, PAD_BUTTON_UP); + GetButton(m_down_button, pad->button, PAD_BUTTON_DOWN); + GetButton(m_right_button, pad->button, PAD_BUTTON_RIGHT); + GetButton(m_start_button, pad->button, PAD_BUTTON_START); if (m_a_button->isChecked()) pad->analogA = 0xFF; @@ -123,11 +113,12 @@ void GCTASInputWindow::GetValues(GCPadStatus* pad) else pad->analogB = 0x00; - pad->triggerLeft = m_l_trigger_value->value(); - pad->triggerRight = m_r_trigger_value->value(); + GetSpinBoxU8(m_l_trigger_value, pad->triggerLeft); + GetSpinBoxU8(m_r_trigger_value, pad->triggerRight); - pad->stickX = m_x_main_stick_value->value(); - pad->stickY = m_y_main_stick_value->value(); - pad->substickX = m_x_c_stick_value->value(); - pad->substickY = m_y_c_stick_value->value(); + GetSpinBoxU8(m_x_main_stick_value, pad->stickX); + GetSpinBoxU8(m_y_main_stick_value, pad->stickY); + + GetSpinBoxU8(m_x_c_stick_value, pad->substickX); + GetSpinBoxU8(m_y_c_stick_value, pad->substickY); } diff --git a/Source/Core/DolphinQt/TAS/GCTASInputWindow.h b/Source/Core/DolphinQt/TAS/GCTASInputWindow.h index 1269145352..a75a4a76d9 100644 --- a/Source/Core/DolphinQt/TAS/GCTASInputWindow.h +++ b/Source/Core/DolphinQt/TAS/GCTASInputWindow.h @@ -4,15 +4,14 @@ #pragma once -#include - -#include "Common/CommonTypes.h" +#include "DolphinQt/TAS/TASInputWindow.h" class QCheckBox; +class QGroupBox; class QSpinBox; struct GCPadStatus; -class GCTASInputWindow : public QDialog +class GCTASInputWindow : public TASInputWindow { Q_OBJECT public: @@ -38,4 +37,8 @@ private: QSpinBox* m_y_main_stick_value; QSpinBox* m_x_c_stick_value; QSpinBox* m_y_c_stick_value; + QGroupBox* m_main_stick_box; + QGroupBox* m_c_stick_box; + QGroupBox* m_triggers_box; + QGroupBox* m_buttons_box; }; diff --git a/Source/Core/DolphinQt/TAS/Shared.cpp b/Source/Core/DolphinQt/TAS/Shared.cpp deleted file mode 100644 index 91679f121f..0000000000 --- a/Source/Core/DolphinQt/TAS/Shared.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2018 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "DolphinQt/TAS/Shared.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "Common/CommonTypes.h" - -#include "DolphinQt/QtUtils/AspectRatioWidget.h" -#include "DolphinQt/TAS/StickWidget.h" - -#include "InputCommon/GCPadStatus.h" - -QGroupBox* CreateStickInputs(QDialog* window, QString name, QSpinBox*& x_value, QSpinBox*& y_value, - u16 max_x, u16 max_y, Qt::Key x_shortcut_key, Qt::Key y_shortcut_key) -{ - const QKeySequence x_shortcut_key_sequence = QKeySequence(Qt::ALT + x_shortcut_key); - const QKeySequence y_shortcut_key_sequence = QKeySequence(Qt::ALT + y_shortcut_key); - - auto* box = - new QGroupBox(QStringLiteral("%1 (%2/%3)") - .arg(name, x_shortcut_key_sequence.toString(QKeySequence::NativeText), - y_shortcut_key_sequence.toString(QKeySequence::NativeText))); - - auto* x_layout = new QHBoxLayout; - x_value = - CreateSliderValuePair(window, x_layout, max_x, x_shortcut_key_sequence, Qt::Horizontal, box); - - auto* y_layout = new QVBoxLayout; - y_value = - CreateSliderValuePair(window, y_layout, max_y, y_shortcut_key_sequence, Qt::Vertical, box); - y_value->setMaximumWidth(60); - - auto* visual = new StickWidget(window, max_x, max_y); - window->connect(x_value, static_cast(&QSpinBox::valueChanged), visual, - &StickWidget::SetX); - window->connect(y_value, static_cast(&QSpinBox::valueChanged), visual, - &StickWidget::SetY); - window->connect(visual, &StickWidget::ChangedX, x_value, &QSpinBox::setValue); - window->connect(visual, &StickWidget::ChangedY, y_value, &QSpinBox::setValue); - - x_value->setValue(static_cast(std::round(max_x / 2.))); - y_value->setValue(static_cast(std::round(max_y / 2.))); - - auto* visual_ar = new AspectRatioWidget(visual, max_x, max_y); - - auto* visual_layout = new QHBoxLayout; - visual_layout->addWidget(visual_ar); - visual_layout->addLayout(y_layout); - - auto* layout = new QVBoxLayout; - layout->addLayout(x_layout); - layout->addLayout(visual_layout); - box->setLayout(layout); - - return box; -} - -QBoxLayout* CreateSliderValuePairLayout(QDialog* window, QString name, QSpinBox*& value, u16 max, - Qt::Key shortcut_key, QWidget* shortcut_widget, bool invert) -{ - const QKeySequence shortcut_key_sequence = QKeySequence(Qt::ALT + shortcut_key); - - auto* label = new QLabel(QStringLiteral("%1 (%2)").arg( - name, shortcut_key_sequence.toString(QKeySequence::NativeText))); - - QBoxLayout* layout = new QHBoxLayout; - layout->addWidget(label); - - value = CreateSliderValuePair(window, layout, max, shortcut_key_sequence, Qt::Horizontal, - shortcut_widget, invert); - - return layout; -} - -// The shortcut_widget argument needs to specify the container widget that will be hidden/shown. -// This is done to avoid ambigous shortcuts -QSpinBox* CreateSliderValuePair(QDialog* window, QBoxLayout* layout, u16 max, - QKeySequence shortcut_key_sequence, Qt::Orientation orientation, - QWidget* shortcut_widget, bool invert) -{ - auto* value = new QSpinBox(); - value->setRange(0, 99999); - window->connect(value, static_cast(&QSpinBox::valueChanged), - [value, max](int i) { - if (i > max) - value->setValue(max); - }); - auto* slider = new QSlider(orientation); - slider->setRange(0, max); - slider->setFocusPolicy(Qt::ClickFocus); - slider->setInvertedAppearance(invert); - - window->connect(slider, &QSlider::valueChanged, value, &QSpinBox::setValue); - window->connect(value, static_cast(&QSpinBox::valueChanged), slider, - &QSlider::setValue); - - auto* shortcut = new QShortcut(shortcut_key_sequence, shortcut_widget); - window->connect(shortcut, &QShortcut::activated, [value] { - value->setFocus(); - value->selectAll(); - }); - - layout->addWidget(slider); - layout->addWidget(value); - if (orientation == Qt::Vertical) - layout->setAlignment(slider, Qt::AlignRight); - - return value; -} diff --git a/Source/Core/DolphinQt/TAS/Shared.h b/Source/Core/DolphinQt/TAS/Shared.h deleted file mode 100644 index ae0f3abad4..0000000000 --- a/Source/Core/DolphinQt/TAS/Shared.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2018 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "Common/CommonTypes.h" - -struct GCPadStatus; -class QDialog; -class QString; -class QSpinBox; -class QCheckBox; -class QBoxLayout; -class QGroupBox; - -QGroupBox* CreateStickInputs(QDialog* window, QString name, QSpinBox*& x_value, QSpinBox*& y_value, - u16 max_x, u16 max_y, Qt::Key x_shortcut_key, Qt::Key y_shortcut_key); -QBoxLayout* CreateSliderValuePairLayout(QDialog* window, QString name, QSpinBox*& value, u16 max, - Qt::Key shortcut_key, QWidget* shortcut_widget, - bool invert = false); -QSpinBox* CreateSliderValuePair(QDialog* window, QBoxLayout* layout, u16 max, - QKeySequence shortcut_key_sequence, Qt::Orientation orientation, - QWidget* shortcut_widget, bool invert = false); diff --git a/Source/Core/DolphinQt/TAS/TASInputWindow.cpp b/Source/Core/DolphinQt/TAS/TASInputWindow.cpp new file mode 100644 index 0000000000..e87f358889 --- /dev/null +++ b/Source/Core/DolphinQt/TAS/TASInputWindow.cpp @@ -0,0 +1,192 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/CommonTypes.h" + +#include "DolphinQt/QtUtils/AspectRatioWidget.h" +#include "DolphinQt/QtUtils/QueueOnObject.h" +#include "DolphinQt/TAS/StickWidget.h" +#include "DolphinQt/TAS/TASInputWindow.h" + +#include "InputCommon/GCPadStatus.h" + +TASInputWindow::TASInputWindow(QWidget* parent) : QDialog(parent) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + m_use_controller = new QCheckBox(QStringLiteral("Enable Controller Inpu&t")); + m_use_controller->setToolTip(tr("Warning: Analog inputs may reset to controller values at " + "random. In some cases this can be fixed by adding a deadzone.")); +} + +QGroupBox* TASInputWindow::CreateStickInputs(QString name, QSpinBox*& x_value, QSpinBox*& y_value, + u16 max_x, u16 max_y, Qt::Key x_shortcut_key, + Qt::Key y_shortcut_key) +{ + const QKeySequence x_shortcut_key_sequence = QKeySequence(Qt::ALT + x_shortcut_key); + const QKeySequence y_shortcut_key_sequence = QKeySequence(Qt::ALT + y_shortcut_key); + + auto* box = + new QGroupBox(QStringLiteral("%1 (%2/%3)") + .arg(name, x_shortcut_key_sequence.toString(QKeySequence::NativeText), + y_shortcut_key_sequence.toString(QKeySequence::NativeText))); + + auto* x_layout = new QHBoxLayout; + x_value = CreateSliderValuePair(x_layout, max_x, x_shortcut_key_sequence, Qt::Horizontal, box); + + auto* y_layout = new QVBoxLayout; + y_value = CreateSliderValuePair(y_layout, max_y, y_shortcut_key_sequence, Qt::Vertical, box); + y_value->setMaximumWidth(60); + + auto* visual = new StickWidget(this, max_x, max_y); + connect(x_value, static_cast(&QSpinBox::valueChanged), visual, + &StickWidget::SetX); + connect(y_value, static_cast(&QSpinBox::valueChanged), visual, + &StickWidget::SetY); + connect(visual, &StickWidget::ChangedX, x_value, &QSpinBox::setValue); + connect(visual, &StickWidget::ChangedY, y_value, &QSpinBox::setValue); + + x_value->setValue(static_cast(std::round(max_x / 2.))); + y_value->setValue(static_cast(std::round(max_y / 2.))); + + auto* visual_ar = new AspectRatioWidget(visual, max_x, max_y); + + auto* visual_layout = new QHBoxLayout; + visual_layout->addWidget(visual_ar); + visual_layout->addLayout(y_layout); + + auto* layout = new QVBoxLayout; + layout->addLayout(x_layout); + layout->addLayout(visual_layout); + box->setLayout(layout); + + return box; +} + +QBoxLayout* TASInputWindow::CreateSliderValuePairLayout(QString name, QSpinBox*& value, u16 max, + Qt::Key shortcut_key, + QWidget* shortcut_widget, bool invert) +{ + const QKeySequence shortcut_key_sequence = QKeySequence(Qt::ALT + shortcut_key); + + auto* label = new QLabel(QStringLiteral("%1 (%2)").arg( + name, shortcut_key_sequence.toString(QKeySequence::NativeText))); + + QBoxLayout* layout = new QHBoxLayout; + layout->addWidget(label); + + value = CreateSliderValuePair(layout, max, shortcut_key_sequence, Qt::Horizontal, shortcut_widget, + invert); + + return layout; +} + +// The shortcut_widget argument needs to specify the container widget that will be hidden/shown. +// This is done to avoid ambigous shortcuts +QSpinBox* TASInputWindow::CreateSliderValuePair(QBoxLayout* layout, u16 max, + QKeySequence shortcut_key_sequence, + Qt::Orientation orientation, + QWidget* shortcut_widget, bool invert) +{ + auto* value = new QSpinBox(); + value->setRange(0, 99999); + connect(value, static_cast(&QSpinBox::valueChanged), + [value, max](int i) { + if (i > max) + value->setValue(max); + }); + auto* slider = new QSlider(orientation); + slider->setRange(0, max); + slider->setFocusPolicy(Qt::ClickFocus); + slider->setInvertedAppearance(invert); + + connect(slider, &QSlider::valueChanged, value, &QSpinBox::setValue); + connect(value, static_cast(&QSpinBox::valueChanged), slider, + &QSlider::setValue); + + auto* shortcut = new QShortcut(shortcut_key_sequence, shortcut_widget); + connect(shortcut, &QShortcut::activated, [value] { + value->setFocus(); + value->selectAll(); + }); + + layout->addWidget(slider); + layout->addWidget(value); + if (orientation == Qt::Vertical) + layout->setAlignment(slider, Qt::AlignRight); + + return value; +} + +template +void TASInputWindow::GetButton(QCheckBox* checkbox, UX& buttons, UX mask) +{ + const bool pressed = (buttons & mask) != 0; + if (m_use_controller->isChecked()) + { + if (pressed) + { + m_checkbox_set_by_controller[checkbox] = true; + QueueOnObject(checkbox, [checkbox] { checkbox->setChecked(true); }); + } + else if (m_checkbox_set_by_controller.count(checkbox) && m_checkbox_set_by_controller[checkbox]) + { + m_checkbox_set_by_controller[checkbox] = false; + QueueOnObject(checkbox, [checkbox] { checkbox->setChecked(false); }); + } + } + + if (checkbox->isChecked()) + buttons |= mask; + else + buttons &= ~mask; +} +template void TASInputWindow::GetButton(QCheckBox* button, u8& pad, u8 mask); +template void TASInputWindow::GetButton(QCheckBox* button, u16& pad, u16 mask); + +void TASInputWindow::GetSpinBoxU8(QSpinBox* spin, u8& controller_value) +{ + if (m_use_controller->isChecked()) + { + if (!m_spinbox_most_recent_values_u8.count(spin) || + m_spinbox_most_recent_values_u8[spin] != controller_value) + QueueOnObject(spin, [spin, controller_value] { spin->setValue(controller_value); }); + + m_spinbox_most_recent_values_u8[spin] = controller_value; + } + else + { + m_spinbox_most_recent_values_u8.clear(); + } + + controller_value = spin->value(); +} + +void TASInputWindow::GetSpinBoxU16(QSpinBox* spin, u16& controller_value) +{ + if (m_use_controller->isChecked()) + { + if (!m_spinbox_most_recent_values_u16.count(spin) || + m_spinbox_most_recent_values_u16[spin] != controller_value) + QueueOnObject(spin, [spin, controller_value] { spin->setValue(controller_value); }); + + m_spinbox_most_recent_values_u16[spin] = controller_value; + } + else + { + m_spinbox_most_recent_values_u16.clear(); + } + + controller_value = spin->value(); +} diff --git a/Source/Core/DolphinQt/TAS/TASInputWindow.h b/Source/Core/DolphinQt/TAS/TASInputWindow.h new file mode 100644 index 0000000000..66d6239abf --- /dev/null +++ b/Source/Core/DolphinQt/TAS/TASInputWindow.h @@ -0,0 +1,44 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "Common/CommonTypes.h" + +struct GCPadStatus; +class QBoxLayout; +class QCheckBox; +class QDialog; +class QGroupBox; +class QSpinBox; +class QString; + +class TASInputWindow : public QDialog +{ + Q_OBJECT +public: + explicit TASInputWindow(QWidget* parent); + +protected: + QGroupBox* CreateStickInputs(QString name, QSpinBox*& x_value, QSpinBox*& y_value, u16 max_x, + u16 max_y, Qt::Key x_shortcut_key, Qt::Key y_shortcut_key); + QBoxLayout* CreateSliderValuePairLayout(QString name, QSpinBox*& value, u16 max, + Qt::Key shortcut_key, QWidget* shortcut_widget, + bool invert = false); + QSpinBox* CreateSliderValuePair(QBoxLayout* layout, u16 max, QKeySequence shortcut_key_sequence, + Qt::Orientation orientation, QWidget* shortcut_widget, + bool invert = false); + template + void GetButton(QCheckBox* button, UX& pad, UX mask); + void GetSpinBoxU8(QSpinBox* spin, u8& controller_value); + void GetSpinBoxU16(QSpinBox* spin, u16& controller_value); + QCheckBox* m_use_controller; + +private: + std::map m_checkbox_set_by_controller; + std::map m_spinbox_most_recent_values_u8; + std::map m_spinbox_most_recent_values_u16; +}; diff --git a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp index df9ad7b270..03a09f83a9 100644 --- a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp +++ b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "DolphinQt/TAS/WiiTASInputWindow.h" - #include #include @@ -23,15 +21,14 @@ #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "DolphinQt/QtUtils/AspectRatioWidget.h" +#include "DolphinQt/QtUtils/QueueOnObject.h" #include "DolphinQt/TAS/IRWidget.h" -#include "DolphinQt/TAS/Shared.h" +#include "DolphinQt/TAS/WiiTASInputWindow.h" #include "InputCommon/InputConfig.h" -WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent), m_num(num) +WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(parent), m_num(num) { - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - const QKeySequence ir_x_shortcut_key_sequence = QKeySequence(Qt::ALT + Qt::Key_F); const QKeySequence ir_y_shortcut_key_sequence = QKeySequence(Qt::ALT + Qt::Key_G); @@ -41,12 +38,12 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent) ir_y_shortcut_key_sequence.toString(QKeySequence::NativeText))); auto* x_layout = new QHBoxLayout; - m_ir_x_value = CreateSliderValuePair(this, x_layout, ir_max_x, ir_x_shortcut_key_sequence, + m_ir_x_value = CreateSliderValuePair(x_layout, ir_max_x, ir_x_shortcut_key_sequence, Qt::Horizontal, m_ir_box, true); auto* y_layout = new QVBoxLayout; - m_ir_y_value = CreateSliderValuePair(this, y_layout, ir_max_y, ir_y_shortcut_key_sequence, - Qt::Vertical, m_ir_box, true); + m_ir_y_value = CreateSliderValuePair(y_layout, ir_max_y, ir_y_shortcut_key_sequence, Qt::Vertical, + m_ir_box, true); m_ir_y_value->setMaximumWidth(60); auto* visual = new IRWidget(this); @@ -71,15 +68,15 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent) ir_layout->addLayout(visual_layout); m_ir_box->setLayout(ir_layout); - m_nunchuk_stick_box = CreateStickInputs(this, tr("Nunchuk Stick"), m_nunchuk_stick_x_value, + m_nunchuk_stick_box = CreateStickInputs(tr("Nunchuk Stick"), m_nunchuk_stick_x_value, m_nunchuk_stick_y_value, 255, 255, Qt::Key_X, Qt::Key_Y); m_classic_left_stick_box = - CreateStickInputs(this, tr("Left Stick"), m_classic_left_stick_x_value, + CreateStickInputs(tr("Left Stick"), m_classic_left_stick_x_value, m_classic_left_stick_y_value, 63, 63, Qt::Key_F, Qt::Key_G); m_classic_right_stick_box = - CreateStickInputs(this, tr("Right Stick"), m_classic_right_stick_x_value, + CreateStickInputs(tr("Right Stick"), m_classic_right_stick_x_value, m_classic_right_stick_y_value, 31, 31, Qt::Key_Q, Qt::Key_W); // Need to enforce the same minimum width because otherwise the different lengths in the labels @@ -97,17 +94,21 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent) auto* remote_orientation_x_layout = // i18n: Refers to a 3D axis (used when mapping motion controls) - CreateSliderValuePairLayout(this, tr("X"), m_remote_orientation_x_value, 1023, Qt::Key_Q, + CreateSliderValuePairLayout(tr("X"), m_remote_orientation_x_value, 1023, Qt::Key_Q, m_remote_orientation_box); auto* remote_orientation_y_layout = // i18n: Refers to a 3D axis (used when mapping motion controls) - CreateSliderValuePairLayout(this, tr("Y"), m_remote_orientation_y_value, 1023, Qt::Key_W, + CreateSliderValuePairLayout(tr("Y"), m_remote_orientation_y_value, 1023, Qt::Key_W, m_remote_orientation_box); auto* remote_orientation_z_layout = // i18n: Refers to a 3D axis (used when mapping motion controls) - CreateSliderValuePairLayout(this, tr("Z"), m_remote_orientation_z_value, 1023, Qt::Key_E, + CreateSliderValuePairLayout(tr("Z"), m_remote_orientation_z_value, 1023, Qt::Key_E, m_remote_orientation_box); + m_remote_orientation_x_value->setValue(512); + m_remote_orientation_y_value->setValue(512); + m_remote_orientation_z_value->setValue(616); + auto* remote_orientation_layout = new QVBoxLayout; remote_orientation_layout->addLayout(remote_orientation_x_layout); remote_orientation_layout->addLayout(remote_orientation_y_layout); @@ -118,17 +119,21 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent) auto* nunchuk_orientation_x_layout = // i18n: Refers to a 3D axis (used when mapping motion controls) - CreateSliderValuePairLayout(this, tr("X"), m_nunchuk_orientation_x_value, 1023, Qt::Key_I, + CreateSliderValuePairLayout(tr("X"), m_nunchuk_orientation_x_value, 1023, Qt::Key_I, m_nunchuk_orientation_box); auto* nunchuk_orientation_y_layout = // i18n: Refers to a 3D axis (used when mapping motion controls) - CreateSliderValuePairLayout(this, tr("Y"), m_nunchuk_orientation_y_value, 1023, Qt::Key_O, + CreateSliderValuePairLayout(tr("Y"), m_nunchuk_orientation_y_value, 1023, Qt::Key_O, m_nunchuk_orientation_box); auto* nunchuk_orientation_z_layout = // i18n: Refers to a 3D axis (used when mapping motion controls) - CreateSliderValuePairLayout(this, tr("Z"), m_nunchuk_orientation_z_value, 1023, Qt::Key_P, + CreateSliderValuePairLayout(tr("Z"), m_nunchuk_orientation_z_value, 1023, Qt::Key_P, m_nunchuk_orientation_box); + m_nunchuk_orientation_x_value->setValue(512); + m_nunchuk_orientation_y_value->setValue(512); + m_nunchuk_orientation_z_value->setValue(512); + auto* nunchuk_orientation_layout = new QVBoxLayout; nunchuk_orientation_layout->addLayout(nunchuk_orientation_x_layout); nunchuk_orientation_layout->addLayout(nunchuk_orientation_y_layout); @@ -136,9 +141,9 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent) m_nunchuk_orientation_box->setLayout(nunchuk_orientation_layout); m_triggers_box = new QGroupBox(tr("Triggers")); - auto* l_trigger_layout = CreateSliderValuePairLayout(this, tr("Left"), m_left_trigger_value, 31, - Qt::Key_N, m_triggers_box); - auto* r_trigger_layout = CreateSliderValuePairLayout(this, tr("Right"), m_right_trigger_value, 31, + auto* l_trigger_layout = + CreateSliderValuePairLayout(tr("Left"), m_left_trigger_value, 31, Qt::Key_N, m_triggers_box); + auto* r_trigger_layout = CreateSliderValuePairLayout(tr("Right"), m_right_trigger_value, 31, Qt::Key_M, m_triggers_box); auto* triggers_layout = new QVBoxLayout; @@ -241,6 +246,7 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent) layout->addWidget(m_remote_buttons_box); layout->addWidget(m_nunchuk_buttons_box); layout->addWidget(m_classic_buttons_box); + layout->addWidget(m_use_controller); layout->setAlignment(m_nunchuk_buttons_box, Qt::AlignLeft); setLayout(layout); @@ -312,15 +318,6 @@ void WiiTASInputWindow::UpdateExt(u8 ext) } } -template -static void SetButton(QCheckBox* check_box, UX* buttons, UX mask) -{ - if (check_box->isChecked()) - *buttons |= mask; - else - *buttons &= ~mask; -} - void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rptf, int ext, wiimote_key key) { @@ -336,18 +333,18 @@ void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rp if (m_remote_buttons_box->isVisible() && buttons_data) { - u16* buttons = &(reinterpret_cast(buttons_data))->hex; - SetButton(m_a_button, buttons, WiimoteEmu::Wiimote::BUTTON_A); - SetButton(m_b_button, buttons, WiimoteEmu::Wiimote::BUTTON_B); - SetButton(m_1_button, buttons, WiimoteEmu::Wiimote::BUTTON_ONE); - SetButton(m_2_button, buttons, WiimoteEmu::Wiimote::BUTTON_TWO); - SetButton(m_plus_button, buttons, WiimoteEmu::Wiimote::BUTTON_PLUS); - SetButton(m_minus_button, buttons, WiimoteEmu::Wiimote::BUTTON_MINUS); - SetButton(m_home_button, buttons, WiimoteEmu::Wiimote::BUTTON_HOME); - SetButton(m_left_button, buttons, WiimoteEmu::Wiimote::PAD_LEFT); - SetButton(m_up_button, buttons, WiimoteEmu::Wiimote::PAD_UP); - SetButton(m_down_button, buttons, WiimoteEmu::Wiimote::PAD_DOWN); - SetButton(m_right_button, buttons, WiimoteEmu::Wiimote::PAD_RIGHT); + u16& buttons = (reinterpret_cast(buttons_data))->hex; + GetButton(m_a_button, buttons, WiimoteEmu::Wiimote::BUTTON_A); + GetButton(m_b_button, buttons, WiimoteEmu::Wiimote::BUTTON_B); + GetButton(m_1_button, buttons, WiimoteEmu::Wiimote::BUTTON_ONE); + GetButton(m_2_button, buttons, WiimoteEmu::Wiimote::BUTTON_TWO); + GetButton(m_plus_button, buttons, WiimoteEmu::Wiimote::BUTTON_PLUS); + GetButton(m_minus_button, buttons, WiimoteEmu::Wiimote::BUTTON_MINUS); + GetButton(m_home_button, buttons, WiimoteEmu::Wiimote::BUTTON_HOME); + GetButton(m_left_button, buttons, WiimoteEmu::Wiimote::PAD_LEFT); + GetButton(m_up_button, buttons, WiimoteEmu::Wiimote::PAD_UP); + GetButton(m_down_button, buttons, WiimoteEmu::Wiimote::PAD_DOWN); + GetButton(m_right_button, buttons, WiimoteEmu::Wiimote::PAD_RIGHT); } if (m_remote_orientation_box->isVisible() && accel_data && buttons_data) @@ -355,16 +352,24 @@ void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rp wm_accel& accel = *reinterpret_cast(accel_data); wm_buttons& buttons = *reinterpret_cast(buttons_data); - accel.x = m_remote_orientation_x_value->value() >> 2; - accel.y = m_remote_orientation_y_value->value() >> 2; - accel.z = m_remote_orientation_z_value->value() >> 2; + u16 accel_x = (accel.x << 2) & (buttons.acc_x_lsb & 0b11); + u16 accel_y = (accel.y << 2) & ((buttons.acc_y_lsb & 0b1) << 1); + u16 accel_z = (accel.z << 2) & ((buttons.acc_z_lsb & 0b1) << 1); - buttons.acc_x_lsb = m_remote_orientation_x_value->value() & 0x3; - buttons.acc_y_lsb = m_remote_orientation_y_value->value() >> 1 & 0x1; - buttons.acc_z_lsb = m_remote_orientation_z_value->value() >> 1 & 0x1; + GetSpinBoxU16(m_remote_orientation_x_value, accel_x); + GetSpinBoxU16(m_remote_orientation_y_value, accel_y); + GetSpinBoxU16(m_remote_orientation_z_value, accel_z); + + accel.x = accel_x >> 2; + accel.y = accel_y >> 2; + accel.z = accel_z >> 2; + + buttons.acc_x_lsb = accel_x & 0b11; + buttons.acc_y_lsb = (accel_y >> 1) & 0b1; + buttons.acc_z_lsb = (accel_z >> 1) & 0b1; } - if (m_ir_box->isVisible() && ir_data) + if (m_ir_box->isVisible() && ir_data && !m_use_controller->isChecked()) { u16 y = m_ir_y_value->value(); std::array x; @@ -429,19 +434,30 @@ void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rp if (ext_data && m_nunchuk_stick_box->isVisible()) { wm_nc& nunchuk = *reinterpret_cast(ext_data); - nunchuk.jx = m_nunchuk_stick_x_value->value(); - nunchuk.jy = m_nunchuk_stick_y_value->value(); - nunchuk.ax = m_nunchuk_orientation_x_value->value() >> 2; - nunchuk.bt.acc_x_lsb = m_nunchuk_orientation_x_value->value() & 0x3; - nunchuk.ay = m_nunchuk_orientation_y_value->value() >> 2; - nunchuk.bt.acc_y_lsb = m_nunchuk_orientation_y_value->value() & 0x3; - nunchuk.az = m_nunchuk_orientation_z_value->value() >> 2; - nunchuk.bt.acc_z_lsb = m_nunchuk_orientation_z_value->value() & 0x3; + GetSpinBoxU8(m_nunchuk_stick_x_value, nunchuk.jx); + GetSpinBoxU8(m_nunchuk_stick_y_value, nunchuk.jy); - SetButton(m_c_button, &nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_C); - SetButton(m_z_button, &nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_Z); - nunchuk.bt.hex ^= 0x3; + u16 accel_x = nunchuk.ax << 2 & (nunchuk.bt.acc_x_lsb & 0b11); + u16 accel_y = nunchuk.ay << 2 & (nunchuk.bt.acc_y_lsb & 0b11); + u16 accel_z = nunchuk.az << 2 & (nunchuk.bt.acc_z_lsb & 0b11); + + GetSpinBoxU16(m_nunchuk_orientation_x_value, accel_x); + GetSpinBoxU16(m_nunchuk_orientation_y_value, accel_y); + GetSpinBoxU16(m_nunchuk_orientation_z_value, accel_z); + + nunchuk.ax = accel_x >> 2; + nunchuk.ay = accel_y >> 2; + nunchuk.az = accel_z >> 2; + + nunchuk.bt.acc_x_lsb = accel_x & 0b11; + nunchuk.bt.acc_y_lsb = accel_y & 0b11; + nunchuk.bt.acc_z_lsb = accel_z & 0b11; + + nunchuk.bt.hex ^= 0b11; + GetButton(m_c_button, nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_C); + GetButton(m_z_button, nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_Z); + nunchuk.bt.hex ^= 0b11; WiimoteEncrypt(&key, reinterpret_cast(&nunchuk), 0, sizeof(wm_nc)); } @@ -450,36 +466,51 @@ void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rp { wm_classic_extension& cc = *reinterpret_cast(ext_data); WiimoteDecrypt(&key, reinterpret_cast(&cc), 0, sizeof(wm_classic_extension)); - cc.bt.hex = 0; - SetButton(m_classic_a_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_A); - SetButton(m_classic_b_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_B); - SetButton(m_classic_x_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_X); - SetButton(m_classic_y_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_Y); - SetButton(m_classic_plus_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_PLUS); - SetButton(m_classic_minus_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_MINUS); - SetButton(m_classic_l_button, &cc.bt.hex, WiimoteEmu::Classic::TRIGGER_L); - SetButton(m_classic_r_button, &cc.bt.hex, WiimoteEmu::Classic::TRIGGER_R); - SetButton(m_classic_zl_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZL); - SetButton(m_classic_zr_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZR); - SetButton(m_classic_left_button, &cc.bt.hex, WiimoteEmu::Classic::PAD_LEFT); - SetButton(m_classic_up_button, &cc.bt.hex, WiimoteEmu::Classic::PAD_UP); - SetButton(m_classic_down_button, &cc.bt.hex, WiimoteEmu::Classic::PAD_DOWN); - SetButton(m_classic_right_button, &cc.bt.hex, WiimoteEmu::Classic::PAD_RIGHT); + cc.bt.hex ^= 0xFFFF; + GetButton(m_classic_a_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_A); + GetButton(m_classic_b_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_B); + GetButton(m_classic_x_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_X); + GetButton(m_classic_y_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_Y); + GetButton(m_classic_plus_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_PLUS); + GetButton(m_classic_minus_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_MINUS); + GetButton(m_classic_l_button, cc.bt.hex, WiimoteEmu::Classic::TRIGGER_L); + GetButton(m_classic_r_button, cc.bt.hex, WiimoteEmu::Classic::TRIGGER_R); + GetButton(m_classic_zl_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZL); + GetButton(m_classic_zr_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZR); + GetButton(m_classic_home_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_HOME); + GetButton(m_classic_left_button, cc.bt.hex, WiimoteEmu::Classic::PAD_LEFT); + GetButton(m_classic_up_button, cc.bt.hex, WiimoteEmu::Classic::PAD_UP); + GetButton(m_classic_down_button, cc.bt.hex, WiimoteEmu::Classic::PAD_DOWN); + GetButton(m_classic_right_button, cc.bt.hex, WiimoteEmu::Classic::PAD_RIGHT); cc.bt.hex ^= 0xFFFF; - u16 rx = m_classic_right_stick_x_value->value(); - cc.rx1 = rx & 0x1; - cc.rx2 = (rx >> 1) & 0x3; - cc.rx3 = (rx >> 3) & 0x3; - cc.ry = m_classic_right_stick_y_value->value(); + u8 rx = (cc.rx1 & 0b1) & ((cc.rx2 & 0b11) << 1) & ((cc.rx3 & 0b11) << 3); + GetSpinBoxU8(m_classic_right_stick_x_value, rx); + cc.rx1 = rx & 0b1; + cc.rx2 = (rx >> 1) & 0b11; + cc.rx3 = (rx >> 3) & 0b11; - cc.regular_data.lx = m_classic_left_stick_x_value->value(); - cc.regular_data.ly = m_classic_left_stick_y_value->value(); + u8 ry = cc.ry; + GetSpinBoxU8(m_classic_right_stick_y_value, ry); + cc.ry = ry; - cc.rt = m_right_trigger_value->value(); - cc.lt1 = m_left_trigger_value->value() & 0x7; - cc.lt2 = (m_left_trigger_value->value() >> 3) & 0x3; + u8 lx = cc.regular_data.lx; + GetSpinBoxU8(m_classic_left_stick_x_value, lx); + cc.regular_data.lx = lx; + + u8 ly = cc.regular_data.ly; + GetSpinBoxU8(m_classic_left_stick_y_value, ly); + cc.regular_data.ly = ly; + + u8 rt = cc.rt; + GetSpinBoxU8(m_right_trigger_value, rt); + cc.rt = rt; + + u8 lt = (cc.lt1 & 0b111) & (cc.lt2 >> 3); + GetSpinBoxU8(m_left_trigger_value, lt); + cc.lt1 = lt & 0b111; + cc.lt2 = (lt >> 3) & 0b11; WiimoteEncrypt(&key, reinterpret_cast(&cc), 0, sizeof(wm_classic_extension)); } diff --git a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h index 2c1a206266..a8decedbf6 100644 --- a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h +++ b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h @@ -4,9 +4,7 @@ #pragma once -#include - -#include "Common/CommonTypes.h" +#include "DolphinQt/TAS/TASInputWindow.h" namespace WiimoteEmu { @@ -17,7 +15,7 @@ class QGroupBox; class QSpinBox; struct wiimote_key; -class WiiTASInputWindow : public QDialog +class WiiTASInputWindow : public TASInputWindow { Q_OBJECT public: