diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 6f3ef7a623..6de7e6dbe2 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -197,6 +197,10 @@ add_library(core HW/EXI/EXI_DeviceMic.h HW/EXI/EXI.cpp HW/EXI/EXI.h + HW/GBAPad.cpp + HW/GBAPad.h + HW/GBAPadEmu.cpp + HW/GBAPadEmu.h HW/GCKeyboard.cpp HW/GCKeyboard.h HW/GCKeyboardEmu.cpp diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 2592a6a674..c88b16fc9d 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -48,6 +48,7 @@ #include "Core/HW/CPU.h" #include "Core/HW/DSP.h" #include "Core/HW/EXI/EXI.h" +#include "Core/HW/GBAPad.h" #include "Core/HW/GCKeyboard.h" #include "Core/HW/GCPad.h" #include "Core/HW/HW.h" @@ -460,6 +461,7 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi { g_controller_interface.Initialize(wsi); Pad::Initialize(); + Pad::InitializeGBA(); Keyboard::Initialize(); init_controllers = true; } @@ -467,6 +469,7 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi { g_controller_interface.ChangeWindow(wsi.render_window); Pad::LoadConfig(); + Pad::LoadGBAConfig(); Keyboard::LoadConfig(); } @@ -517,6 +520,7 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi Keyboard::Shutdown(); Pad::Shutdown(); + Pad::ShutdownGBA(); g_controller_interface.Shutdown(); }}; diff --git a/Source/Core/Core/FreeLookManager.cpp b/Source/Core/Core/FreeLookManager.cpp index 90f2667890..39d1f47278 100644 --- a/Source/Core/Core/FreeLookManager.cpp +++ b/Source/Core/Core/FreeLookManager.cpp @@ -309,12 +309,12 @@ void Initialize() FreeLook::GetConfig().Refresh(); - s_config.LoadConfig(true); + s_config.LoadConfig(InputConfig::InputClass::GC); } void LoadInputConfig() { - s_config.LoadConfig(true); + s_config.LoadConfig(InputConfig::InputClass::GC); } bool IsInitialized() diff --git a/Source/Core/Core/HW/GBAPad.cpp b/Source/Core/Core/HW/GBAPad.cpp new file mode 100644 index 0000000000..7f25b56fd1 --- /dev/null +++ b/Source/Core/Core/HW/GBAPad.cpp @@ -0,0 +1,64 @@ +// Copyright 2021 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Core/HW/GBAPad.h" + +#include "Core/HW/GBAPadEmu.h" +#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" +#include "InputCommon/GCPadStatus.h" +#include "InputCommon/InputConfig.h" + +namespace Pad +{ +static InputConfig s_config("GBA", _trans("Pad"), "GBA"); +InputConfig* GetGBAConfig() +{ + return &s_config; +} + +void ShutdownGBA() +{ + s_config.UnregisterHotplugCallback(); + + s_config.ClearControllers(); +} + +void InitializeGBA() +{ + if (s_config.ControllersNeedToBeCreated()) + { + for (unsigned int i = 0; i < 4; ++i) + s_config.CreateController(i); + } + + s_config.RegisterHotplugCallback(); + + // Load the saved controller config + s_config.LoadConfig(InputConfig::InputClass::GBA); +} + +void LoadGBAConfig() +{ + s_config.LoadConfig(InputConfig::InputClass::GBA); +} + +bool IsGBAInitialized() +{ + return !s_config.ControllersNeedToBeCreated(); +} + +GCPadStatus GetGBAStatus(int pad_num) +{ + return static_cast(s_config.GetController(pad_num))->GetInput(); +} + +void SetGBAReset(int pad_num, bool reset) +{ + static_cast(s_config.GetController(pad_num))->SetReset(reset); +} + +ControllerEmu::ControlGroup* GetGBAGroup(int pad_num, GBAPadGroup group) +{ + return static_cast(s_config.GetController(pad_num))->GetGroup(group); +} +} // namespace Pad diff --git a/Source/Core/Core/HW/GBAPad.h b/Source/Core/Core/HW/GBAPad.h new file mode 100644 index 0000000000..76d68f26df --- /dev/null +++ b/Source/Core/Core/HW/GBAPad.h @@ -0,0 +1,28 @@ +// Copyright 2021 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +class InputConfig; +enum class GBAPadGroup; +struct GCPadStatus; + +namespace ControllerEmu +{ +class ControlGroup; +} // namespace ControllerEmu + +namespace Pad +{ +void ShutdownGBA(); +void InitializeGBA(); +void LoadGBAConfig(); +bool IsGBAInitialized(); + +InputConfig* GetGBAConfig(); + +GCPadStatus GetGBAStatus(int pad_num); +void SetGBAReset(int pad_num, bool reset); + +ControllerEmu::ControlGroup* GetGBAGroup(int pad_num, GBAPadGroup group); +} // namespace Pad diff --git a/Source/Core/Core/HW/GBAPadEmu.cpp b/Source/Core/Core/HW/GBAPadEmu.cpp new file mode 100644 index 0000000000..c25763b6d8 --- /dev/null +++ b/Source/Core/Core/HW/GBAPadEmu.cpp @@ -0,0 +1,107 @@ +// Copyright 2021 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Core/HW/GBAPadEmu.h" + +#include + +#include "InputCommon/ControllerEmu/Control/Input.h" +#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h" +#include "InputCommon/GCPadStatus.h" + +static const u16 dpad_bitmasks[] = {PAD_BUTTON_UP, PAD_BUTTON_DOWN, PAD_BUTTON_LEFT, + PAD_BUTTON_RIGHT}; + +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) + { + 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); + } + + // DPad + groups.emplace_back(m_dpad = new ControllerEmu::Buttons(_trans("D-Pad"))); + for (const char* named_direction : named_directions) + { + m_dpad->AddInput(ControllerEmu::Translate, named_direction); + } +} + +std::string GBAPad::GetName() const +{ + return fmt::format("GBA{}", m_index + 1); +} + +ControllerEmu::ControlGroup* GBAPad::GetGroup(GBAPadGroup group) const +{ + switch (group) + { + case GBAPadGroup::Buttons: + return m_buttons; + case GBAPadGroup::DPad: + return m_dpad; + default: + return nullptr; + } +} + +GCPadStatus GBAPad::GetInput() +{ + const auto lock = GetStateLock(); + GCPadStatus pad = {}; + + // Buttons + m_buttons->GetState(&pad.button, button_bitmasks); + + // DPad + m_dpad->GetState(&pad.button, dpad_bitmasks); + + // Use X button as a reset signal + if (m_reset_pending) + pad.button |= PAD_BUTTON_X; + m_reset_pending = false; + + return pad; +} + +void GBAPad::SetReset(bool reset) +{ + const auto lock = GetStateLock(); + m_reset_pending = reset; +} + +void GBAPad::LoadDefaults(const ControllerInterface& ciface) +{ + EmulatedController::LoadDefaults(ciface); + + // Buttons + m_buttons->SetControlExpression(0, "`Z`"); // B + m_buttons->SetControlExpression(1, "`X`"); // A + m_buttons->SetControlExpression(2, "`Q`"); // L + m_buttons->SetControlExpression(3, "`W`"); // R +#ifdef _WIN32 + m_buttons->SetControlExpression(4, "`BACK`"); // Select + m_buttons->SetControlExpression(5, "`RETURN`"); // Start +#else + m_buttons->SetControlExpression(4, "`Backspace`"); // Select + m_buttons->SetControlExpression(5, "`Return`"); // Start +#endif + + // D-Pad + m_dpad->SetControlExpression(0, "`T`"); // Up + m_dpad->SetControlExpression(1, "`G`"); // Down + m_dpad->SetControlExpression(2, "`F`"); // Left + m_dpad->SetControlExpression(3, "`H`"); // Right +} diff --git a/Source/Core/Core/HW/GBAPadEmu.h b/Source/Core/Core/HW/GBAPadEmu.h new file mode 100644 index 0000000000..8dc8f24457 --- /dev/null +++ b/Source/Core/Core/HW/GBAPadEmu.h @@ -0,0 +1,40 @@ +// Copyright 2021 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "InputCommon/ControllerEmu/ControllerEmu.h" + +struct GCPadStatus; + +namespace ControllerEmu +{ +class Buttons; +} // namespace ControllerEmu + +enum class GBAPadGroup +{ + DPad, + Buttons +}; + +class GBAPad : public ControllerEmu::EmulatedController +{ +public: + explicit GBAPad(unsigned int index); + GCPadStatus GetInput(); + void SetReset(bool reset); + + std::string GetName() const override; + + ControllerEmu::ControlGroup* GetGroup(GBAPadGroup group) const; + + void LoadDefaults(const ControllerInterface& ciface) override; + +private: + ControllerEmu::Buttons* m_buttons; + ControllerEmu::Buttons* m_dpad; + bool m_reset_pending; + + const unsigned int m_index; +}; diff --git a/Source/Core/Core/HW/GCKeyboard.cpp b/Source/Core/Core/HW/GCKeyboard.cpp index de03ec32b4..f99193f4d4 100644 --- a/Source/Core/Core/HW/GCKeyboard.cpp +++ b/Source/Core/Core/HW/GCKeyboard.cpp @@ -41,12 +41,12 @@ void Initialize() s_config.RegisterHotplugCallback(); // Load the saved controller config - s_config.LoadConfig(true); + s_config.LoadConfig(InputConfig::InputClass::GC); } void LoadConfig() { - s_config.LoadConfig(true); + s_config.LoadConfig(InputConfig::InputClass::GC); } ControllerEmu::ControlGroup* GetGroup(int port, KeyboardGroup group) diff --git a/Source/Core/Core/HW/GCPad.cpp b/Source/Core/Core/HW/GCPad.cpp index a34c83638d..faf50f3c02 100644 --- a/Source/Core/Core/HW/GCPad.cpp +++ b/Source/Core/Core/HW/GCPad.cpp @@ -38,12 +38,12 @@ void Initialize() s_config.RegisterHotplugCallback(); // Load the saved controller config - s_config.LoadConfig(true); + s_config.LoadConfig(InputConfig::InputClass::GC); } void LoadConfig() { - s_config.LoadConfig(true); + s_config.LoadConfig(InputConfig::InputClass::GC); } bool IsInitialized() diff --git a/Source/Core/Core/HW/Wiimote.cpp b/Source/Core/Core/HW/Wiimote.cpp index eaed4c91eb..30d522b564 100644 --- a/Source/Core/Core/HW/Wiimote.cpp +++ b/Source/Core/Core/HW/Wiimote.cpp @@ -173,7 +173,7 @@ void ResetAllWiimotes() void LoadConfig() { - s_config.LoadConfig(false); + s_config.LoadConfig(InputConfig::InputClass::Wii); s_last_connect_request_counter.fill(0); } diff --git a/Source/Core/Core/HotkeyManager.cpp b/Source/Core/Core/HotkeyManager.cpp index 77960cc381..01ddadb6be 100644 --- a/Source/Core/Core/HotkeyManager.cpp +++ b/Source/Core/Core/HotkeyManager.cpp @@ -285,7 +285,7 @@ void Initialize() void LoadConfig() { - s_config.LoadConfig(true); + s_config.LoadConfig(InputConfig::InputClass::GC); LoadLegacyConfig(s_config.GetController(0)); } diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 67c1a2eace..45cc52e6e3 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -1,4 +1,4 @@ - + @@ -264,6 +264,8 @@ + + @@ -844,6 +846,8 @@ + + diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index c4970c335d..317150812b 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -42,6 +42,7 @@ #include "Core/Core.h" #include "Core/FreeLookManager.h" #include "Core/HW/DVD/DVDInterface.h" +#include "Core/HW/GBAPad.h" #include "Core/HW/GCKeyboard.h" #include "Core/HW/GCPad.h" #include "Core/HW/ProcessorInterface.h" @@ -306,6 +307,7 @@ void MainWindow::InitControllers() g_controller_interface.Initialize(GetWindowSystemInfo(windowHandle())); Pad::Initialize(); + Pad::InitializeGBA(); Keyboard::Initialize(); Wiimote::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); FreeLook::Initialize(); @@ -320,6 +322,9 @@ void MainWindow::InitControllers() Pad::LoadConfig(); Pad::GetConfig()->SaveConfig(); + Pad::LoadGBAConfig(); + Pad::GetGBAConfig()->SaveConfig(); + Keyboard::LoadConfig(); Keyboard::GetConfig()->SaveConfig(); @@ -332,6 +337,7 @@ void MainWindow::ShutdownControllers() m_hotkey_scheduler->Stop(); Pad::Shutdown(); + Pad::ShutdownGBA(); Keyboard::Shutdown(); Wiimote::Shutdown(); HotkeyManagerEmu::Shutdown(); diff --git a/Source/Core/InputCommon/InputConfig.cpp b/Source/Core/InputCommon/InputConfig.cpp index 07249b0ed8..bace091ca5 100644 --- a/Source/Core/InputCommon/InputConfig.cpp +++ b/Source/Core/InputCommon/InputConfig.cpp @@ -26,7 +26,7 @@ InputConfig::InputConfig(const std::string& ini_name, const std::string& gui_nam InputConfig::~InputConfig() = default; -bool InputConfig::LoadConfig(bool isGC) +bool InputConfig::LoadConfig(InputClass type) { IniFile inifile; bool useProfile[MAX_BBMOTES] = {false, false, false, false, false}; @@ -43,16 +43,22 @@ bool InputConfig::LoadConfig(bool isGC) if (SConfig::GetInstance().GetGameID() != "00000000") { - std::string type; - if (isGC) + std::string type_str; + switch (type) { - type = "Pad"; - path = "Profiles/GCPad/"; - } - else - { - type = "Wiimote"; + case InputClass::GBA: + type_str = "GBA"; + path = "Profiles/GBA/"; + break; + case InputClass::Wii: + type_str = "Wiimote"; path = "Profiles/Wiimote/"; + break; + case InputClass::GC: + default: + type_str = "Pad"; + path = "Profiles/GCPad/"; + break; } IniFile game_ini = SConfig::GetInstance().LoadGameIni(); @@ -60,7 +66,7 @@ bool InputConfig::LoadConfig(bool isGC) for (int i = 0; i < 4; i++) { - const auto profile_name = fmt::format("{}Profile{}", type, num[i]); + const auto profile_name = fmt::format("{}Profile{}", type_str, num[i]); if (control_section->Exists(profile_name)) { @@ -124,7 +130,7 @@ bool InputConfig::LoadConfig(bool isGC) } #if defined(ANDROID) // Only set for wii pads - if (!isGC && use_ir_config) + if (type == InputClass::Wii && use_ir_config) { config.Set("IR/Total Yaw", ir_values[0]); config.Set("IR/Total Pitch", ir_values[1]); diff --git a/Source/Core/InputCommon/InputConfig.h b/Source/Core/InputCommon/InputConfig.h index 62eb30b4de..2c3f290576 100644 --- a/Source/Core/InputCommon/InputConfig.h +++ b/Source/Core/InputCommon/InputConfig.h @@ -24,7 +24,14 @@ public: ~InputConfig(); - bool LoadConfig(bool isGC); + enum class InputClass + { + GC, + Wii, + GBA, + }; + + bool LoadConfig(InputClass type); void SaveConfig(); template