DolphinQt: Rework TAS input threading, part 2 (analog inputs)

This commit is contained in:
JosJuice 2023-03-07 19:22:09 +01:00
parent 11e4d46927
commit 0300b44d23
8 changed files with 101 additions and 56 deletions

View File

@ -343,6 +343,8 @@ add_executable(dolphin-emu
TAS/TASInputWindow.h TAS/TASInputWindow.h
TAS/TASSlider.cpp TAS/TASSlider.cpp
TAS/TASSlider.h TAS/TASSlider.h
TAS/TASSpinBox.cpp
TAS/TASSpinBox.h
TAS/WiiTASInputWindow.cpp TAS/WiiTASInputWindow.cpp
TAS/WiiTASInputWindow.h TAS/WiiTASInputWindow.h
ToolBar.cpp ToolBar.cpp

View File

@ -209,6 +209,7 @@
<ClCompile Include="TAS\TASInputWindow.cpp" /> <ClCompile Include="TAS\TASInputWindow.cpp" />
<ClCompile Include="TAS\TASControlState.cpp" /> <ClCompile Include="TAS\TASControlState.cpp" />
<ClCompile Include="TAS\TASSlider.cpp" /> <ClCompile Include="TAS\TASSlider.cpp" />
<ClCompile Include="TAS\TASSpinBox.cpp" />
<ClCompile Include="TAS\WiiTASInputWindow.cpp" /> <ClCompile Include="TAS\WiiTASInputWindow.cpp" />
<ClCompile Include="ToolBar.cpp" /> <ClCompile Include="ToolBar.cpp" />
<ClCompile Include="Translation.cpp" /> <ClCompile Include="Translation.cpp" />
@ -389,6 +390,7 @@
<QtMoc Include="TAS\StickWidget.h" /> <QtMoc Include="TAS\StickWidget.h" />
<QtMoc Include="TAS\TASCheckBox.h" /> <QtMoc Include="TAS\TASCheckBox.h" />
<QtMoc Include="TAS\TASInputWindow.h" /> <QtMoc Include="TAS\TASInputWindow.h" />
<QtMoc Include="TAS\TASSpinBox.h" />
<QtMoc Include="TAS\WiiTASInputWindow.h" /> <QtMoc Include="TAS\WiiTASInputWindow.h" />
<QtMoc Include="ToolBar.h" /> <QtMoc Include="ToolBar.h" />
<QtMoc Include="Updater.h" /> <QtMoc Include="Updater.h" />

View File

@ -23,6 +23,7 @@
#include "DolphinQt/TAS/StickWidget.h" #include "DolphinQt/TAS/StickWidget.h"
#include "DolphinQt/TAS/TASCheckBox.h" #include "DolphinQt/TAS/TASCheckBox.h"
#include "DolphinQt/TAS/TASSlider.h" #include "DolphinQt/TAS/TASSlider.h"
#include "DolphinQt/TAS/TASSpinBox.h"
#include "InputCommon/ControllerEmu/ControllerEmu.h" #include "InputCommon/ControllerEmu/ControllerEmu.h"
#include "InputCommon/ControllerEmu/StickGate.h" #include "InputCommon/ControllerEmu/StickGate.h"
@ -109,11 +110,11 @@ QGroupBox* TASInputWindow::CreateStickInputs(const QString& text, std::string_vi
const int y_default = static_cast<int>(std::round(max_y / 2.)); const int y_default = static_cast<int>(std::round(max_y / 2.));
auto* x_layout = new QHBoxLayout; auto* x_layout = new QHBoxLayout;
QSpinBox* x_value = CreateSliderValuePair(x_layout, x_default, max_x, x_shortcut_key_sequence, TASSpinBox* x_value = CreateSliderValuePair(x_layout, x_default, max_x, x_shortcut_key_sequence,
Qt::Horizontal, box); Qt::Horizontal, box);
auto* y_layout = new QVBoxLayout; auto* y_layout = new QVBoxLayout;
QSpinBox* y_value = TASSpinBox* y_value =
CreateSliderValuePair(y_layout, y_default, max_y, y_shortcut_key_sequence, Qt::Vertical, box); CreateSliderValuePair(y_layout, y_default, max_y, y_shortcut_key_sequence, Qt::Vertical, box);
y_value->setMaximumWidth(60); y_value->setMaximumWidth(60);
@ -169,14 +170,14 @@ QBoxLayout* TASInputWindow::CreateSliderValuePairLayout(
return layout; return layout;
} }
QSpinBox* TASInputWindow::CreateSliderValuePair( TASSpinBox* TASInputWindow::CreateSliderValuePair(
std::string_view group_name, std::string_view control_name, InputOverrider* overrider, std::string_view group_name, std::string_view control_name, InputOverrider* overrider,
QBoxLayout* layout, u16 zero, int default_, u16 min, u16 max, QBoxLayout* layout, u16 zero, int default_, u16 min, u16 max,
QKeySequence shortcut_key_sequence, Qt::Orientation orientation, QWidget* shortcut_widget, QKeySequence shortcut_key_sequence, Qt::Orientation orientation, QWidget* shortcut_widget,
std::optional<ControlState> scale) std::optional<ControlState> scale)
{ {
QSpinBox* value = CreateSliderValuePair(layout, default_, max, shortcut_key_sequence, orientation, TASSpinBox* value = CreateSliderValuePair(layout, default_, max, shortcut_key_sequence,
shortcut_widget); orientation, shortcut_widget);
InputOverrider::OverrideFunction func; InputOverrider::OverrideFunction func;
if (scale) if (scale)
@ -199,12 +200,12 @@ QSpinBox* TASInputWindow::CreateSliderValuePair(
// The shortcut_widget argument needs to specify the container widget that will be hidden/shown. // The shortcut_widget argument needs to specify the container widget that will be hidden/shown.
// This is done to avoid ambigous shortcuts // This is done to avoid ambigous shortcuts
QSpinBox* TASInputWindow::CreateSliderValuePair(QBoxLayout* layout, int default_, u16 max, TASSpinBox* TASInputWindow::CreateSliderValuePair(QBoxLayout* layout, int default_, u16 max,
QKeySequence shortcut_key_sequence, QKeySequence shortcut_key_sequence,
Qt::Orientation orientation, Qt::Orientation orientation,
QWidget* shortcut_widget) QWidget* shortcut_widget)
{ {
auto* value = new QSpinBox(); auto* value = new TASSpinBox();
value->setRange(0, 99999); value->setRange(0, 99999);
value->setValue(default_); value->setValue(default_);
connect(value, qOverload<int>(&QSpinBox::valueChanged), [value, max](int i) { connect(value, qOverload<int>(&QSpinBox::valueChanged), [value, max](int i) {
@ -243,51 +244,27 @@ std::optional<ControlState> TASInputWindow::GetButton(TASCheckBox* checkbox,
return checkbox->GetValue() ? 1.0 : 0.0; return checkbox->GetValue() ? 1.0 : 0.0;
} }
std::optional<ControlState> TASInputWindow::GetSpinBox(QSpinBox* spin, u16 zero, u16 min, u16 max, std::optional<ControlState> TASInputWindow::GetSpinBox(TASSpinBox* spin, u16 zero, u16 min, u16 max,
ControlState controller_state) ControlState controller_state)
{ {
const u16 controller_value = const u16 controller_value =
ControllerEmu::EmulatedController::MapFloat<u16>(controller_state, zero, 0, max); ControllerEmu::EmulatedController::MapFloat<u16>(controller_state, zero, 0, max);
if (m_use_controller->isChecked()) if (m_use_controller->isChecked())
{ spin->OnControllerValueChanged(controller_value);
if (!m_spinbox_most_recent_values.count(spin) ||
m_spinbox_most_recent_values[spin] != controller_value) return ControllerEmu::EmulatedController::MapToFloat<ControlState, u16>(spin->GetValue(), zero,
{ min, max);
QueueOnObjectBlocking(spin, [spin, controller_value] { spin->setValue(controller_value); });
} }
m_spinbox_most_recent_values[spin] = controller_value; std::optional<ControlState> TASInputWindow::GetSpinBox(TASSpinBox* spin, u16 zero,
}
else
{
m_spinbox_most_recent_values.clear();
}
return ControllerEmu::EmulatedController::MapToFloat<ControlState, u16>(spin->value(), zero, min,
max);
}
std::optional<ControlState> TASInputWindow::GetSpinBox(QSpinBox* spin, u16 zero,
ControlState controller_state, ControlState controller_state,
ControlState scale) ControlState scale)
{ {
const u16 controller_value = static_cast<u16>(std::llround(controller_state * scale + zero)); const u16 controller_value = static_cast<u16>(std::llround(controller_state * scale + zero));
if (m_use_controller->isChecked()) if (m_use_controller->isChecked())
{ spin->OnControllerValueChanged(controller_value);
if (!m_spinbox_most_recent_values.count(spin) ||
m_spinbox_most_recent_values[spin] != controller_value)
{
QueueOnObjectBlocking(spin, [spin, controller_value] { spin->setValue(controller_value); });
}
m_spinbox_most_recent_values[spin] = controller_value; return (spin->GetValue() - zero) / scale;
}
else
{
m_spinbox_most_recent_values.clear();
}
return (spin->value() - zero) / scale;
} }

View File

@ -22,6 +22,7 @@ class QGroupBox;
class QSpinBox; class QSpinBox;
class QString; class QString;
class TASCheckBox; class TASCheckBox;
class TASSpinBox;
class InputOverrider final class InputOverrider final
{ {
@ -57,12 +58,13 @@ protected:
u16 zero, int default_, u16 min, u16 max, u16 zero, int default_, u16 min, u16 max,
Qt::Key shortcut_key, QWidget* shortcut_widget, Qt::Key shortcut_key, QWidget* shortcut_widget,
std::optional<ControlState> scale = {}); std::optional<ControlState> scale = {});
QSpinBox* CreateSliderValuePair(std::string_view group_name, std::string_view control_name, TASSpinBox* CreateSliderValuePair(std::string_view group_name, std::string_view control_name,
InputOverrider* overrider, QBoxLayout* layout, u16 zero, InputOverrider* overrider, QBoxLayout* layout, u16 zero,
int default_, u16 min, u16 max, int default_, u16 min, u16 max,
QKeySequence shortcut_key_sequence, Qt::Orientation orientation, QKeySequence shortcut_key_sequence, Qt::Orientation orientation,
QWidget* shortcut_widget, std::optional<ControlState> scale = {}); QWidget* shortcut_widget,
QSpinBox* CreateSliderValuePair(QBoxLayout* layout, int default_, u16 max, std::optional<ControlState> scale = {});
TASSpinBox* CreateSliderValuePair(QBoxLayout* layout, int default_, u16 max,
QKeySequence shortcut_key_sequence, Qt::Orientation orientation, QKeySequence shortcut_key_sequence, Qt::Orientation orientation,
QWidget* shortcut_widget); QWidget* shortcut_widget);
@ -73,10 +75,8 @@ protected:
private: private:
std::optional<ControlState> GetButton(TASCheckBox* checkbox, ControlState controller_state); std::optional<ControlState> GetButton(TASCheckBox* checkbox, ControlState controller_state);
std::optional<ControlState> GetSpinBox(QSpinBox* spin, u16 zero, u16 min, u16 max, std::optional<ControlState> GetSpinBox(TASSpinBox* spin, u16 zero, u16 min, u16 max,
ControlState controller_state); ControlState controller_state);
std::optional<ControlState> GetSpinBox(QSpinBox* spin, u16 zero, ControlState controller_state, std::optional<ControlState> GetSpinBox(TASSpinBox* spin, u16 zero, ControlState controller_state,
ControlState scale); ControlState scale);
std::map<QSpinBox*, u16> m_spinbox_most_recent_values;
}; };

View File

@ -0,0 +1,33 @@
// Copyright 2019 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "DolphinQt/TAS/TASSpinBox.h"
#include "DolphinQt/QtUtils/QueueOnObject.h"
TASSpinBox::TASSpinBox(QWidget* parent) : QSpinBox(parent)
{
connect(this, QOverload<int>::of(&TASSpinBox::valueChanged), this, &TASSpinBox::OnUIValueChanged);
}
int TASSpinBox::GetValue() const
{
return m_state.GetValue();
}
void TASSpinBox::OnControllerValueChanged(int new_value)
{
if (m_state.OnControllerValueChanged(static_cast<u16>(new_value)))
QueueOnObject(this, &TASSpinBox::ApplyControllerValueChange);
}
void TASSpinBox::OnUIValueChanged(int new_value)
{
m_state.OnUIValueChanged(static_cast<u16>(new_value));
}
void TASSpinBox::ApplyControllerValueChange()
{
const QSignalBlocker blocker(this);
setValue(m_state.ApplyControllerValueChange());
}

View File

@ -0,0 +1,29 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QSpinBox>
#include "DolphinQt/TAS/TASControlState.h"
class TASInputWindow;
class TASSpinBox : public QSpinBox
{
Q_OBJECT
public:
explicit TASSpinBox(QWidget* parent = nullptr);
// Can be called from the CPU thread
int GetValue() const;
// Must be called from the CPU thread
void OnControllerValueChanged(int new_value);
private slots:
void OnUIValueChanged(int new_value);
void ApplyControllerValueChange();
private:
TASControlState m_state;
};

View File

@ -29,6 +29,7 @@
#include "DolphinQt/QtUtils/QueueOnObject.h" #include "DolphinQt/QtUtils/QueueOnObject.h"
#include "DolphinQt/TAS/IRWidget.h" #include "DolphinQt/TAS/IRWidget.h"
#include "DolphinQt/TAS/TASCheckBox.h" #include "DolphinQt/TAS/TASCheckBox.h"
#include "DolphinQt/TAS/TASSpinBox.h"
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h" #include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
#include "InputCommon/ControllerEmu/ControllerEmu.h" #include "InputCommon/ControllerEmu/ControllerEmu.h"

View File

@ -12,6 +12,7 @@ class QHideEvent;
class QShowEvent; class QShowEvent;
class QSpinBox; class QSpinBox;
class TASCheckBox; class TASCheckBox;
class TASSpinBox;
namespace WiimoteEmu namespace WiimoteEmu
{ {
@ -75,8 +76,8 @@ private:
TASCheckBox* m_classic_up_button; TASCheckBox* m_classic_up_button;
TASCheckBox* m_classic_down_button; TASCheckBox* m_classic_down_button;
TASCheckBox* m_classic_right_button; TASCheckBox* m_classic_right_button;
QSpinBox* m_ir_x_value; TASSpinBox* m_ir_x_value;
QSpinBox* m_ir_y_value; TASSpinBox* m_ir_y_value;
QGroupBox* m_remote_orientation_box; QGroupBox* m_remote_orientation_box;
QGroupBox* m_nunchuk_orientation_box; QGroupBox* m_nunchuk_orientation_box;
QGroupBox* m_ir_box; QGroupBox* m_ir_box;