diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index 8d3d4f99aa..13736a9f88 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -146,19 +146,6 @@ void ConvertAnalogStick(float x, float y, float *outX, float *outY) { *outY = Clamp(y / norm * mappedNorm, -1.0f, 1.0f); } -void ControlMapper::SetCallbacks( - std::function onVKey, - std::function onVKeyAnalog, - std::function updatePSPButtons, - std::function setPSPAnalog, - std::function setRawAnalog) { - onVKey_ = onVKey; - onVKeyAnalog_ = onVKeyAnalog; - updatePSPButtons_ = updatePSPButtons; - setPSPAnalog_ = setPSPAnalog; - setRawAnalog_ = setRawAnalog; -} - void ControlMapper::SetPSPAxis(int device, int stick, char axis, float value) { const int axisId = axis == 'X' ? 0 : 1; if (stick != 0 && stick != 1) { @@ -171,12 +158,10 @@ void ControlMapper::SetPSPAxis(int device, int stick, char axis, float value) { position[axisId] = value; - float x = position[0]; - float y = position[1]; + const float x = position[0]; + const float y = position[1]; - if (setRawAnalog_) { - setRawAnalog_(stick, x, y); - } + listener_->SetRawAnalog(stick, x, y); // NOTE: We need to use single-axis checks, since the other axis might be from another device, // so we'll add a little leeway. @@ -208,7 +193,7 @@ void ControlMapper::UpdateAnalogOutput(int stick) { } converted_[stick][0] = x; converted_[stick][1] = y; - setPSPAnalog_(iInternalScreenRotationCached_, stick, x, y); + listener_->SetPSPAnalog(iInternalScreenRotationCached_, stick, x, y); } void ControlMapper::ForceReleaseVKey(int vkey) { @@ -416,7 +401,7 @@ bool ControlMapper::UpdatePSPState(const InputMapping &changedMapping, double no } // We only request changing the buttons where the mapped input was involved. - updatePSPButtons_(buttonMask & changedButtonMask, (~buttonMask) & changedButtonMask); + listener_->UpdatePSPButtons(buttonMask & changedButtonMask, (~buttonMask) & changedButtonMask); bool keyInputUsed = changedButtonMask != 0; bool updateAnalogSticks = false; @@ -579,16 +564,16 @@ void ControlMapper::ToggleSwapAxes() { swapAxes_ = !swapAxes_; - updatePSPButtons_(0, CTRL_LEFT | CTRL_RIGHT | CTRL_UP | CTRL_DOWN); + listener_->UpdatePSPButtons(0, CTRL_LEFT | CTRL_RIGHT | CTRL_UP | CTRL_DOWN); for (VirtKey vkey = VIRTKEY_FIRST; vkey < VIRTKEY_LAST; vkey = (VirtKey)(vkey + 1)) { if (IsSwappableVKey(vkey)) { if (virtKeyOn_[vkey - VIRTKEY_FIRST]) { - onVKey_(vkey, false); + listener_->OnVKey(vkey, false); virtKeyOn_[vkey - VIRTKEY_FIRST] = false; } if (virtKeys_[vkey - VIRTKEY_FIRST] > 0.0f) { - onVKeyAnalog_(vkey, 0.0f); + listener_->OnVKeyAnalog(vkey, 0.0f); virtKeys_[vkey - VIRTKEY_FIRST] = 0.0f; } } @@ -657,12 +642,12 @@ void ControlMapper::Update(const DisplayLayoutConfig &config, double now) { float x = std::min(1.0f, std::max(-1.0f, 1.42f * (float)cos(now * -g_Config.fAnalogAutoRotSpeed))); float y = std::min(1.0f, std::max(-1.0f, 1.42f * (float)sin(now * -g_Config.fAnalogAutoRotSpeed))); - setPSPAnalog_(iInternalScreenRotationCached_, 0, x, y); + listener_->SetPSPAnalog(iInternalScreenRotationCached_, 0, x, y); } else if (autoRotatingAnalogCCW_) { float x = std::min(1.0f, std::max(-1.0f, 1.42f * (float)cos(now * g_Config.fAnalogAutoRotSpeed))); float y = std::min(1.0f, std::max(-1.0f, 1.42f * (float)sin(now * g_Config.fAnalogAutoRotSpeed))); - setPSPAnalog_(iInternalScreenRotationCached_, 0, x, y); + listener_->SetPSPAnalog(iInternalScreenRotationCached_, 0, x, y); } } @@ -683,9 +668,9 @@ void ControlMapper::PSPKey(int deviceId, int pspKeyCode, KeyInputFlags flags) { } else { // INFO_LOG(Log::System, "pspKey %d %d", pspKeyCode, flags); if (flags & KeyInputFlags::DOWN) - updatePSPButtons_(pspKeyCode, 0); + listener_->UpdatePSPButtons(pspKeyCode, 0); if (flags & KeyInputFlags::UP) - updatePSPButtons_(0, pspKeyCode); + listener_->UpdatePSPButtons(0, pspKeyCode); } } @@ -706,8 +691,7 @@ void ControlMapper::onVKeyAnalog(int deviceId, VirtKey vkey, float value) { case VIRTKEY_AXIS_RIGHT_Y_MIN: stick = CTRL_STICK_RIGHT; axis = 'Y'; sign = -1.0f; break; case VIRTKEY_AXIS_RIGHT_Y_MAX: stick = CTRL_STICK_RIGHT; axis = 'Y'; break; default: - if (onVKeyAnalog_) - onVKeyAnalog_(vkey, value); + listener_->OnVKeyAnalog(vkey, value); return; } if (oppositeVKey != 0) { @@ -728,7 +712,7 @@ void ControlMapper::onVKey(VirtKey vkey, bool down) { autoRotatingAnalogCCW_ = false; } else { autoRotatingAnalogCW_ = false; - setPSPAnalog_(iInternalScreenRotationCached_, 0, 0.0f, 0.0f); + listener_->SetPSPAnalog(iInternalScreenRotationCached_, 0, 0.0f, 0.0f); } break; case VIRTKEY_ANALOG_ROTATE_CCW: @@ -737,12 +721,11 @@ void ControlMapper::onVKey(VirtKey vkey, bool down) { autoRotatingAnalogCCW_ = true; } else { autoRotatingAnalogCCW_ = false; - setPSPAnalog_(iInternalScreenRotationCached_, 0, 0.0f, 0.0f); + listener_->SetPSPAnalog(iInternalScreenRotationCached_, 0, 0.0f, 0.0f); } break; default: - if (onVKey_) - onVKey_(vkey, down); + listener_->OnVKey(vkey, down); break; } } diff --git a/Core/ControlMapper.h b/Core/ControlMapper.h index b3772e07af..e0550f5085 100644 --- a/Core/ControlMapper.h +++ b/Core/ControlMapper.h @@ -8,6 +8,18 @@ #include struct DisplayLayoutConfig; + +// Pure interface. +class ControlListener { +public: + virtual ~ControlListener() = default; + virtual void OnVKey(VirtKey vkey, bool down) {} + virtual void OnVKeyAnalog(VirtKey vkey, float value) {} + virtual void UpdatePSPButtons(uint32_t buttonMask, uint32_t changedMask) {} + virtual void SetPSPAnalog(int rotation, int stick, float x, float y) {} + virtual void SetRawAnalog(int stick, float x, float y) {} +}; + // Utilities for mapping input events to PSP inputs and virtual keys. // Main use is of course from EmuScreen.cpp, but also useful from control settings etc. class ControlMapper { @@ -21,12 +33,9 @@ public: // Required callbacks. // TODO: These are so many now that a virtual interface might be more appropriate.. - void SetCallbacks( - std::function onVKey, - std::function onVKeyAnalog, - std::function updatePSPButtons, - std::function setPSPAnalog, - std::function setRawAnalog); + void SetListener(ControlListener *listener) { + listener_ = listener; + } // Inject raw PSP key input directly, such as from touch screen controls. // Combined with the mapped input. Unlike __Ctrl APIs, this supports @@ -96,11 +105,7 @@ private: std::map curInput_; // Callbacks - std::function onVKey_; - std::function onVKeyAnalog_; - std::function updatePSPButtons_; - std::function setPSPAnalog_; - std::function setRawAnalog_; + ControlListener *listener_ = nullptr; }; void ConvertAnalogStick(float x, float y, float *outX, float *outY); diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index c45806a0b9..e0155fd3e4 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -480,18 +480,21 @@ void KeyMappingNewMouseKeyDialog::axis(const AxisInput &axis) { } AnalogCalibrationScreen::AnalogCalibrationScreen(const Path &gamePath) : UITwoPaneBaseDialogScreen(gamePath, TwoPaneFlags::SettingsCanScroll) { - mapper_.SetCallbacks( - [](int vkey, bool down) {}, - [](int vkey, float analogValue) {}, - [&](uint32_t bitsToSet, uint32_t bitsToClear) {}, - [&](int iInternalRotation, int stick, float x, float y) { - analogX_[stick] = x; - analogY_[stick] = y; - }, - [&](int stick, float x, float y) { - rawX_[stick] = x; - rawY_[stick] = y; - }); + mapper_.SetListener(this); +} + +AnalogCalibrationScreen::~AnalogCalibrationScreen() { + mapper_.SetListener(nullptr); +} + +void AnalogCalibrationScreen::SetPSPAnalog(int rotation, int stick, float x, float y) { + analogX_[stick] = x; + analogY_[stick] = y; +} + +void AnalogCalibrationScreen::SetRawAnalog(int stick, float x, float y) { + rawX_[stick] = x; + rawY_[stick] = y; } void AnalogCalibrationScreen::update() { diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h index bd792b1112..366cae25ab 100644 --- a/UI/ControlMappingScreen.h +++ b/UI/ControlMappingScreen.h @@ -125,9 +125,10 @@ private: class JoystickHistoryView; -class AnalogCalibrationScreen : public UITwoPaneBaseDialogScreen { +class AnalogCalibrationScreen : public UITwoPaneBaseDialogScreen, protected ControlListener { public: AnalogCalibrationScreen(const Path &gamePath); + ~AnalogCalibrationScreen(); bool key(const KeyInput &key) override; void axis(const AxisInput &axis) override; @@ -140,6 +141,9 @@ protected: void CreateSettingsViews(UI::ViewGroup *parent) override; void CreateContentViews(UI::ViewGroup *parent) override; + void SetPSPAnalog(int rotation, int stick, float x, float y) override; + void SetRawAnalog(int stick, float x, float y) override; + std::string_view GetTitle() const override; private: void OnResetToDefaults(UI::EventParams &e); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index d8570f13c8..e16bcc11f8 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -126,7 +126,11 @@ static void AssertCancelCallback(const char *message, void *userdata) { } // Handles control rotation due to internal screen rotation. -static void SetPSPAnalog(int iInternalScreenRotation, int stick, float x, float y) { +void EmuScreen::UpdatePSPButtons(uint32_t bitsToSet, uint32_t bitsToClear) { + __CtrlUpdateButtons(bitsToSet, bitsToClear); +} + +void EmuScreen::SetPSPAnalog(int iInternalScreenRotation, int stick, float x, float y) { switch (iInternalScreenRotation) { case ROTATION_LOCKED_HORIZONTAL: // Standard rotation. No change. @@ -158,14 +162,7 @@ static void SetPSPAnalog(int iInternalScreenRotation, int stick, float x, float EmuScreen::EmuScreen(const Path &filename) : gamePath_(filename) { saveStateSlot_ = SaveState::GetCurrentSlot(); - controlMapper_.SetCallbacks( - std::bind(&EmuScreen::onVKey, this, _1, _2), - std::bind(&EmuScreen::onVKeyAnalog, this, _1, _2), - [](uint32_t bitsToSet, uint32_t bitsToClear) { - __CtrlUpdateButtons(bitsToSet, bitsToClear); - }, - &SetPSPAnalog, - nullptr); + controlMapper_.SetListener(this); _dbg_assert_(coreState == CORE_POWERDOWN); @@ -449,6 +446,8 @@ void EmuScreen::bootComplete() { } EmuScreen::~EmuScreen() { + controlMapper_.SetListener(nullptr); + if (imguiInited_) { ImGui_ImplThin3d_Shutdown(); ImGui::DestroyContext(ctx_); @@ -739,7 +738,7 @@ static void ShowFpsLimitNotice() { g_OSD.SetFlags("altspeed", OSDMessageFlags::Transparent); } -void EmuScreen::onVKey(VirtKey virtualKeyCode, bool down) { +void EmuScreen::OnVKey(VirtKey virtualKeyCode, bool down) { auto sc = GetI18NCategory(I18NCat::SCREEN); auto mc = GetI18NCategory(I18NCat::MAPPABLECONTROLS); @@ -1081,7 +1080,7 @@ void EmuScreen::ProcessVKey(VirtKey virtKey) { } } -void EmuScreen::onVKeyAnalog(VirtKey virtualKeyCode, float value) { +void EmuScreen::OnVKeyAnalog(VirtKey virtualKeyCode, float value) { if (virtualKeyCode != VIRTKEY_SPEED_ANALOG) { return; } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index a902d2ef39..e0a2c2db71 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -36,7 +36,7 @@ struct AxisInput; class AsyncImageFileView; class ChatMenu; -class EmuScreen : public UIScreen { +class EmuScreen : public UIScreen, public ControlListener { public: EmuScreen(const Path &filename); ~EmuScreen(); @@ -72,6 +72,13 @@ protected: void focusChanged(ScreenFocusChange focusChange) override; ScreenRenderFlags PreRender(ScreenRenderMode mode) override; + // ControlListener implementations + void OnVKey(VirtKey virtualKeyCode, bool down); + void OnVKeyAnalog(VirtKey virtualKeyCode, float value); + void UpdatePSPButtons(uint32_t buttonMask, uint32_t changedMask) override; + void SetPSPAnalog(int rotation, int stick, float x, float y); + void SetRawAnalog(int deviceId, float x, float y) {} + private: void CreateViews() override; ScreenRenderFlags RunEmulation(bool skipBufferEffects); @@ -87,8 +94,6 @@ private: void runImDebugger(); void renderImDebugger(); - void onVKey(VirtKey virtualKeyCode, bool down); - void onVKeyAnalog(VirtKey virtualKeyCode, float value); void AutoLoadSaveState(); bool checkPowerDown(); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index a754d77577..bc5ea4d61e 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -1432,7 +1432,7 @@ void MainScreen::CreateViews() { #if !defined(MOBILE_DEVICE) auto gr = GetI18NCategory(I18NCat::GRAPHICS); ImageID icon(g_Config.bFullScreen ? "I_RESTORE" : "I_FULLSCREEN"); - fullscreenButton_ = logo->Add(new Button(gr->T("FullScreen", "Full Screen"), icon, new AnchorLayoutParams(48, 48, NONE, 0, 0, NONE, Centering::None))); + fullscreenButton_ = logo->Add(new Button("", icon, new AnchorLayoutParams(48, 48, NONE, 0, 0, NONE, Centering::None))); fullscreenButton_->SetIgnoreText(true); fullscreenButton_->OnClick.Add([this](UI::EventParams &e) { if (fullscreenButton_) {