From 40571cf13c37932aedc4bd3c69c68ba4f16128a2 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 19 Nov 2022 11:16:10 +0100 Subject: [PATCH] DolphinQt: Add GBA TAS input window When emulated GBAs were added to Dolphin, it was possible to control them using the GC TAS input window. (Z was mapped to Select.) Unaware of this, I broke the functionality in b296248. To make it possible to control emulated GBAs using TAS input again, I'm adding a proper TAS input window for GBAs, with a real Select button and no analog controls. --- Source/Core/Core/HW/GBAPadEmu.cpp | 23 +++-- Source/Core/Core/HW/GBAPadEmu.h | 12 +++ Source/Core/DolphinQt/CMakeLists.txt | 2 + Source/Core/DolphinQt/DolphinQt.vcxproj | 2 + Source/Core/DolphinQt/MainWindow.cpp | 13 ++- Source/Core/DolphinQt/MainWindow.h | 2 + .../Core/DolphinQt/TAS/GBATASInputWindow.cpp | 86 +++++++++++++++++++ Source/Core/DolphinQt/TAS/GBATASInputWindow.h | 39 +++++++++ 8 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 Source/Core/DolphinQt/TAS/GBATASInputWindow.cpp create mode 100644 Source/Core/DolphinQt/TAS/GBATASInputWindow.h diff --git a/Source/Core/Core/HW/GBAPadEmu.cpp b/Source/Core/Core/HW/GBAPadEmu.cpp index c25763b6d8..274c042c2e 100644 --- a/Source/Core/Core/HW/GBAPadEmu.cpp +++ b/Source/Core/Core/HW/GBAPadEmu.cpp @@ -15,24 +15,21 @@ static const u16 dpad_bitmasks[] = {PAD_BUTTON_UP, PAD_BUTTON_DOWN, PAD_BUTTON_L static const u16 button_bitmasks[] = {PAD_BUTTON_B, PAD_BUTTON_A, PAD_TRIGGER_L, PAD_TRIGGER_R, PAD_TRIGGER_Z, PAD_BUTTON_START}; -static const char* const named_buttons[] = {"B", "A", "L", "R", _trans("SELECT"), _trans("START")}; - GBAPad::GBAPad(const unsigned int index) : m_reset_pending(false), m_index(index) { // Buttons - groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons"))); - for (const char* named_button : named_buttons) + groups.emplace_back(m_buttons = new ControllerEmu::Buttons(BUTTONS_GROUP)); + for (const char* named_button : {B_BUTTON, A_BUTTON, L_BUTTON, R_BUTTON}) { - const ControllerEmu::Translatability translate = - (named_button == std::string(_trans("SELECT")) || - named_button == std::string(_trans("START"))) ? - ControllerEmu::Translate : - ControllerEmu::DoNotTranslate; - m_buttons->AddInput(translate, named_button); + m_buttons->AddInput(ControllerEmu::DoNotTranslate, named_button); + } + for (const char* named_button : {SELECT_BUTTON, START_BUTTON}) + { + m_buttons->AddInput(ControllerEmu::Translate, named_button); } // DPad - groups.emplace_back(m_dpad = new ControllerEmu::Buttons(_trans("D-Pad"))); + groups.emplace_back(m_dpad = new ControllerEmu::Buttons(DPAD_GROUP)); for (const char* named_direction : named_directions) { m_dpad->AddInput(ControllerEmu::Translate, named_direction); @@ -63,10 +60,10 @@ GCPadStatus GBAPad::GetInput() GCPadStatus pad = {}; // Buttons - m_buttons->GetState(&pad.button, button_bitmasks); + m_buttons->GetState(&pad.button, button_bitmasks, m_input_override_function); // DPad - m_dpad->GetState(&pad.button, dpad_bitmasks); + m_dpad->GetState(&pad.button, dpad_bitmasks, m_input_override_function); // Use X button as a reset signal if (m_reset_pending) diff --git a/Source/Core/Core/HW/GBAPadEmu.h b/Source/Core/Core/HW/GBAPadEmu.h index 8dc8f24457..ca42666b48 100644 --- a/Source/Core/Core/HW/GBAPadEmu.h +++ b/Source/Core/Core/HW/GBAPadEmu.h @@ -3,6 +3,8 @@ #pragma once +#include "Common/Common.h" + #include "InputCommon/ControllerEmu/ControllerEmu.h" struct GCPadStatus; @@ -31,6 +33,16 @@ public: void LoadDefaults(const ControllerInterface& ciface) override; + static constexpr const char* BUTTONS_GROUP = _trans("Buttons"); + static constexpr const char* DPAD_GROUP = _trans("D-Pad"); + + static constexpr const char* B_BUTTON = "B"; + static constexpr const char* A_BUTTON = "A"; + static constexpr const char* L_BUTTON = "L"; + static constexpr const char* R_BUTTON = "R"; + static constexpr const char* SELECT_BUTTON = _trans("SELECT"); + static constexpr const char* START_BUTTON = _trans("START"); + private: ControllerEmu::Buttons* m_buttons; ControllerEmu::Buttons* m_dpad; diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 2455b6a03e..0307d3fc36 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -327,6 +327,8 @@ add_executable(dolphin-emu Settings/WiiPane.h TAS/GCTASInputWindow.cpp TAS/GCTASInputWindow.h + TAS/GBATASInputWindow.cpp + TAS/GBATASInputWindow.h TAS/IRWidget.cpp TAS/IRWidget.h TAS/StickWidget.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index 3c37f4ca1e..9519c30313 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -201,6 +201,7 @@ + @@ -379,6 +380,7 @@ + diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index be9f8f6db1..7e530ba237 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -109,6 +109,7 @@ #include "DolphinQt/RiivolutionBootWidget.h" #include "DolphinQt/SearchBar.h" #include "DolphinQt/Settings.h" +#include "DolphinQt/TAS/GBATASInputWindow.h" #include "DolphinQt/TAS/GCTASInputWindow.h" #include "DolphinQt/TAS/WiiTASInputWindow.h" #include "DolphinQt/ToolBar.h" @@ -303,6 +304,7 @@ MainWindow::~MainWindow() for (int i = 0; i < 4; i++) { delete m_gc_tas_input_windows[i]; + delete m_gba_tas_input_windows[i]; delete m_wii_tas_input_windows[i]; } @@ -402,6 +404,7 @@ void MainWindow::CreateComponents() for (int i = 0; i < 4; i++) { m_gc_tas_input_windows[i] = new GCTASInputWindow(nullptr, i); + m_gba_tas_input_windows[i] = new GBATASInputWindow(nullptr, i); m_wii_tas_input_windows[i] = new WiiTASInputWindow(nullptr, i); } @@ -1787,8 +1790,14 @@ void MainWindow::ShowTASInput() for (int i = 0; i < num_gc_controllers; i++) { const auto si_device = Config::Get(Config::GetInfoForSIDevice(i)); - if (si_device != SerialInterface::SIDEVICE_NONE && - si_device != SerialInterface::SIDEVICE_GC_GBA) + if (si_device == SerialInterface::SIDEVICE_GC_GBA_EMULATED) + { + m_gba_tas_input_windows[i]->show(); + m_gba_tas_input_windows[i]->raise(); + m_gba_tas_input_windows[i]->activateWindow(); + } + else if (si_device != SerialInterface::SIDEVICE_NONE && + si_device != SerialInterface::SIDEVICE_GC_GBA) { m_gc_tas_input_windows[i]->show(); m_gc_tas_input_windows[i]->raise(); diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index 60880a5275..70acfcb53a 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -26,6 +26,7 @@ class DragEnterEvent; class FIFOPlayerWindow; class FreeLookWindow; class GameList; +class GBATASInputWindow; class GCTASInputWindow; class GraphicsWindow; class HotkeyScheduler; @@ -228,6 +229,7 @@ private: NetPlaySetupDialog* m_netplay_setup_dialog; static constexpr int num_gc_controllers = 4; std::array m_gc_tas_input_windows{}; + std::array m_gba_tas_input_windows{}; static constexpr int num_wii_controllers = 4; std::array m_wii_tas_input_windows{}; diff --git a/Source/Core/DolphinQt/TAS/GBATASInputWindow.cpp b/Source/Core/DolphinQt/TAS/GBATASInputWindow.cpp new file mode 100644 index 0000000000..d963308ca1 --- /dev/null +++ b/Source/Core/DolphinQt/TAS/GBATASInputWindow.cpp @@ -0,0 +1,86 @@ +// Copyright 2022 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "DolphinQt/TAS/GBATASInputWindow.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "Common/CommonTypes.h" + +#include "Core/HW/GBAPad.h" +#include "Core/HW/GBAPadEmu.h" + +#include "DolphinQt/TAS/TASCheckBox.h" + +#include "InputCommon/ControllerEmu/ControllerEmu.h" +#include "InputCommon/InputConfig.h" + +GBATASInputWindow::GBATASInputWindow(QWidget* parent, int controller_id) + : TASInputWindow(parent), m_controller_id(controller_id) +{ + setWindowTitle(tr("GBA TAS Input %1").arg(controller_id + 1)); + + m_b_button = + CreateButton(QStringLiteral("&B"), GBAPad::BUTTONS_GROUP, GBAPad::B_BUTTON, &m_overrider); + m_a_button = + CreateButton(QStringLiteral("&A"), GBAPad::BUTTONS_GROUP, GBAPad::A_BUTTON, &m_overrider); + m_l_button = + CreateButton(QStringLiteral("&L"), GBAPad::BUTTONS_GROUP, GBAPad::L_BUTTON, &m_overrider); + m_r_button = + CreateButton(QStringLiteral("&R"), GBAPad::BUTTONS_GROUP, GBAPad::R_BUTTON, &m_overrider); + m_select_button = CreateButton(QStringLiteral("SELE&CT"), GBAPad::BUTTONS_GROUP, + GBAPad::SELECT_BUTTON, &m_overrider); + m_start_button = m_start_button = CreateButton(QStringLiteral("&START"), GBAPad::BUTTONS_GROUP, + GBAPad::START_BUTTON, &m_overrider); + + m_left_button = + CreateButton(QStringLiteral("L&eft"), GBAPad::DPAD_GROUP, DIRECTION_LEFT, &m_overrider); + m_up_button = CreateButton(QStringLiteral("&Up"), GBAPad::DPAD_GROUP, DIRECTION_UP, &m_overrider); + m_down_button = + CreateButton(QStringLiteral("&Down"), GBAPad::DPAD_GROUP, DIRECTION_DOWN, &m_overrider); + m_right_button = + CreateButton(QStringLiteral("R&ight"), GBAPad::DPAD_GROUP, DIRECTION_RIGHT, &m_overrider); + + auto* buttons_layout = new QGridLayout; + + buttons_layout->addWidget(m_left_button, 0, 0); + buttons_layout->addWidget(m_up_button, 0, 1); + buttons_layout->addWidget(m_down_button, 0, 2); + buttons_layout->addWidget(m_right_button, 0, 3); + + buttons_layout->addWidget(m_l_button, 1, 0); + buttons_layout->addWidget(m_r_button, 1, 1); + buttons_layout->addWidget(m_b_button, 1, 2); + buttons_layout->addWidget(m_a_button, 1, 3); + + buttons_layout->addWidget(m_select_button, 2, 0, 1, 2); + buttons_layout->addWidget(m_start_button, 2, 2, 1, 2); + + buttons_layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding), 0, 4); + + QGroupBox* buttons_box = new QGroupBox(tr("Buttons")); + buttons_box->setLayout(buttons_layout); + + auto* layout = new QVBoxLayout; + layout->addWidget(buttons_box); + + setLayout(layout); +} + +void GBATASInputWindow::hideEvent(QHideEvent* event) +{ + Pad::GetGBAConfig()->GetController(m_controller_id)->ClearInputOverrideFunction(); +} + +void GBATASInputWindow::showEvent(QShowEvent* event) +{ + Pad::GetGBAConfig() + ->GetController(m_controller_id) + ->SetInputOverrideFunction(m_overrider.GetInputOverrideFunction()); +} diff --git a/Source/Core/DolphinQt/TAS/GBATASInputWindow.h b/Source/Core/DolphinQt/TAS/GBATASInputWindow.h new file mode 100644 index 0000000000..6b036682a0 --- /dev/null +++ b/Source/Core/DolphinQt/TAS/GBATASInputWindow.h @@ -0,0 +1,39 @@ +// Copyright 2022 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "DolphinQt/TAS/TASInputWindow.h" + +class QGroupBox; +class QHideEvent; +class QShowEvent; +class QSpinBox; +class TASCheckBox; + +class GBATASInputWindow final : public TASInputWindow +{ + Q_OBJECT +public: + explicit GBATASInputWindow(QWidget* parent, int controller_id); + + void hideEvent(QHideEvent* event) override; + void showEvent(QShowEvent* event) override; + +private: + int m_controller_id; + + InputOverrider m_overrider; + + TASCheckBox* m_b_button; + TASCheckBox* m_a_button; + TASCheckBox* m_l_button; + TASCheckBox* m_r_button; + TASCheckBox* m_select_button; + TASCheckBox* m_start_button; + + TASCheckBox* m_left_button; + TASCheckBox* m_up_button; + TASCheckBox* m_down_button; + TASCheckBox* m_right_button; +};