diff --git a/src/core/pad.cpp b/src/core/pad.cpp index 841b08c0d..8ce4151b6 100644 --- a/src/core/pad.cpp +++ b/src/core/pad.cpp @@ -293,6 +293,14 @@ void Pad::SetMemoryCard(u32 slot, std::unique_ptr dev) m_memory_cards[slot] = std::move(dev); } +std::unique_ptr Pad::RemoveMemoryCard(u32 slot) +{ + std::unique_ptr ret = std::move(m_memory_cards[slot]); + if (ret) + ret->Reset(); + return ret; +} + u32 Pad::ReadRegister(u32 offset) { switch (offset) diff --git a/src/core/pad.h b/src/core/pad.h index dd5c18c15..88d73deca 100644 --- a/src/core/pad.h +++ b/src/core/pad.h @@ -28,6 +28,7 @@ public: MemoryCard* GetMemoryCard(u32 slot) { return m_memory_cards[slot].get(); } void SetMemoryCard(u32 slot, std::unique_ptr dev); + std::unique_ptr RemoveMemoryCard(u32 slot); Multitap* GetMultitap(u32 slot) { return &m_multitaps[slot]; }; diff --git a/src/core/system.cpp b/src/core/system.cpp index 510f3886d..12485712d 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1836,6 +1836,19 @@ void UpdateMemoryCards() } } +bool HasMemoryCard(u32 slot) +{ + return (g_pad.GetMemoryCard(slot) != nullptr); +} + +void SwapMemoryCards() +{ + std::unique_ptr first = g_pad.RemoveMemoryCard(0); + std::unique_ptr second = g_pad.RemoveMemoryCard(1); + g_pad.SetMemoryCard(0, std::move(second)); + g_pad.SetMemoryCard(1, std::move(first)); +} + void UpdateMultitaps() { switch (g_settings.multitap_mode) diff --git a/src/core/system.h b/src/core/system.h index 1dfd11036..3e60dea98 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -181,6 +181,8 @@ void UpdateControllers(); void UpdateControllerSettings(); void ResetControllers(); void UpdateMemoryCards(); +bool HasMemoryCard(u32 slot); +void SwapMemoryCards(); void UpdateMultitaps(); /// Dumps RAM to a file. diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index e02b5887f..26d2dca7a 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -1999,6 +1999,12 @@ void CommonHostInterface::RegisterGeneralHotkeys() } }); + RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("SwapMemoryCards"), + StaticString(TRANSLATABLE("Hotkeys", "Swap Memory Card Slots")), [this](bool pressed) { + if (pressed && System::IsValid()) + SwapMemoryCards(); + }); + #ifndef __ANDROID__ RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("FrameStep"), StaticString(TRANSLATABLE("Hotkeys", "Frame Step")), [this](bool pressed) { @@ -3564,6 +3570,38 @@ void CommonHostInterface::ToggleWidescreen() GTE::UpdateAspectRatio(); } +void CommonHostInterface::SwapMemoryCards() +{ + System::SwapMemoryCards(); + + if (System::HasMemoryCard(0) && System::HasMemoryCard(1)) + { + g_host_interface->AddOSDMessage( + g_host_interface->TranslateStdString("OSDMessage", "Swapped memory card ports. Both ports have a memory card."), + 10.0f); + } + else if (System::HasMemoryCard(1)) + { + g_host_interface->AddOSDMessage( + g_host_interface->TranslateStdString("OSDMessage", + "Swapped memory card ports. Port 2 has a memory card, Port 1 is empty."), + 10.0f); + } + else if (System::HasMemoryCard(0)) + { + g_host_interface->AddOSDMessage( + g_host_interface->TranslateStdString("OSDMessage", + "Swapped memory card ports. Port 1 has a memory card, Port 2 is empty."), + 10.0f); + } + else + { + g_host_interface->AddOSDMessage( + g_host_interface->TranslateStdString("OSDMessage", "Swapped memory card ports. Neither port has a memory card."), + 10.0f); + } +} + bool CommonHostInterface::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate) { diff --git a/src/frontend-common/common_host_interface.h b/src/frontend-common/common_host_interface.h index 5ee830f69..f26e3bed7 100644 --- a/src/frontend-common/common_host_interface.h +++ b/src/frontend-common/common_host_interface.h @@ -274,6 +274,9 @@ public: /// Toggle Widescreen Hack and Aspect Ratio void ToggleWidescreen(); + /// Swaps memory cards in slot 1/2. + void SwapMemoryCards(); + /// Parses a fullscreen mode into its components (width * height @ refresh hz) static bool ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate);