From fb037aac2b03b0f735192eaac1b5ac0581aeca54 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 17 Apr 2026 16:29:35 -0500 Subject: [PATCH] Consolidate duplicated code. --- .../ControllerInterface/SDL/SDLGamepad.cpp | 116 +++++++-------- .../ControllerInterface/evdev/evdev.cpp | 132 ++++++++---------- 2 files changed, 109 insertions(+), 139 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp index cabe154688..c760ae8f0a 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp @@ -273,12 +273,56 @@ SDL_JoystickID Gamepad::GetSDLInstanceID() const return SDL_GetJoystickID(m_joystick); } -class SpringEffect final : public Core::SpringEffect +class ScopedHapticEffect { public: - explicit SpringEffect(SDL_Haptic* haptic) : m_haptic{haptic} {} + explicit ScopedHapticEffect(SDL_Haptic* haptic) : m_haptic{haptic} {} - ~SpringEffect() override { SetForce(0.0, 0.0); } +protected: + ~ScopedHapticEffect() { UpdateEffect(nullptr); } + + void UpdateEffect(const SDL_HapticEffect* effect) + { + if (effect == nullptr) + { + if (m_effect_id != -1) + { + SDL_DestroyHapticEffect(m_haptic, std::exchange(m_effect_id, -1)); + } + + return; + } + + if (m_effect_id == -1) + { + // Create and start a new effect. + m_effect_id = SDL_CreateHapticEffect(m_haptic, effect); + if (m_effect_id == -1) + { + ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_CreateHapticEffect: {}", SDL_GetError()); + return; + } + + if (!SDL_RunHapticEffect(m_haptic, m_effect_id, 1)) + ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_RunHapticEffect: {}", SDL_GetError()); + } + else + { + // Update an already running effect. + if (!SDL_UpdateHapticEffect(m_haptic, m_effect_id, effect)) + ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_UpdateHapticEffect: {}", SDL_GetError()); + } + } + +private: + SDL_Haptic* const m_haptic; + int m_effect_id = -1; +}; + +class SpringEffect final : ScopedHapticEffect, public Core::SpringEffect +{ +public: + using ScopedHapticEffect::ScopedHapticEffect; void SetForce(double gain, double center_position) override { @@ -286,11 +330,7 @@ public: if (gain == 0.0) { - if (m_effect_id != -1) - { - SDL_DestroyHapticEffect(m_haptic, std::exchange(m_effect_id, -1)); - } - + UpdateEffect(nullptr); return; } @@ -319,38 +359,14 @@ public: condition.center[0] = ControllerEmu::MapFloat(center_position, 0); - if (m_effect_id == -1) - { - // Create and start a new effect. - m_effect_id = SDL_CreateHapticEffect(m_haptic, &effect); - if (m_effect_id == -1) - { - ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_CreateHapticEffect: {}", SDL_GetError()); - return; - } - - if (!SDL_RunHapticEffect(m_haptic, m_effect_id, 1)) - ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_RunHapticEffect: {}", SDL_GetError()); - } - else - { - // Update an already running effect. - if (!SDL_UpdateHapticEffect(m_haptic, m_effect_id, &effect)) - ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_UpdateHapticEffect: {}", SDL_GetError()); - } + UpdateEffect(&effect); } - -private: - SDL_Haptic* const m_haptic; - int m_effect_id = -1; }; -class FrictionEffect final : public Core::FrictionEffect +class FrictionEffect final : ScopedHapticEffect, public Core::FrictionEffect { public: - explicit FrictionEffect(SDL_Haptic* haptic) : m_haptic{haptic} {} - - ~FrictionEffect() override { SetForce(0.0); } + using ScopedHapticEffect::ScopedHapticEffect; void SetForce(double gain) override { @@ -358,11 +374,7 @@ public: if (gain == 0.0) { - if (m_effect_id != -1) - { - SDL_DestroyHapticEffect(m_haptic, std::exchange(m_effect_id, -1)); - } - + UpdateEffect(nullptr); return; } @@ -389,30 +401,8 @@ public: condition.right_coeff[0] = coeff; condition.left_coeff[0] = coeff; - if (m_effect_id == -1) - { - // Create and start a new effect. - m_effect_id = SDL_CreateHapticEffect(m_haptic, &effect); - if (m_effect_id == -1) - { - ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_CreateHapticEffect: {}", SDL_GetError()); - return; - } - - if (!SDL_RunHapticEffect(m_haptic, m_effect_id, 1)) - ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_RunHapticEffect: {}", SDL_GetError()); - } - else - { - // Update an already running effect. - if (!SDL_UpdateHapticEffect(m_haptic, m_effect_id, &effect)) - ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL_UpdateHapticEffect: {}", SDL_GetError()); - } + UpdateEffect(&effect); } - -private: - SDL_Haptic* const m_haptic; - int m_effect_id = -1; }; std::unique_ptr Gamepad::CreateSpringEffect() diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp index f3347645c5..9227ed05ee 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp @@ -729,18 +729,17 @@ bool evdevDevice::IsValid() const return true; } -class SpringEffect final : public Core::SpringEffect +class ScopedForceFeedbackEffect { public: - explicit SpringEffect(int ffb_fd) : m_ffb_fd{ffb_fd} {} + explicit ScopedForceFeedbackEffect(int ffb_fd) : m_ffb_fd{ffb_fd} {} - ~SpringEffect() override { SetForce(0.0, 0.0); } +protected: + ~ScopedForceFeedbackEffect() { UpdateEffect(nullptr); } - void SetForce(double gain, double center_position) override + void UpdateEffect(ff_effect* effect) { - INFO_LOG_FMT(CONTROLLERINTERFACE, "SpringEffect: {:.2} {:.2}", gain, center_position); - - if (gain == 0.0) + if (effect == nullptr) { if (m_effect_id != -1) { @@ -756,10 +755,50 @@ public: return; } - ff_effect effect{ - .type = FF_SPRING, - .id = m_effect_id, - }; + effect->id = m_effect_id; + + if (ioctl(m_ffb_fd, EVIOCSFF, effect) < 0) + { + ERROR_LOG_FMT(COMMON, "EVIOCSFF: {}", Common::LastStrerrorString()); + return; + } + + if (m_effect_id == -1) + { + m_effect_id = effect->id; + + const input_event play{ + .type = EV_FF, + .code = u16(m_effect_id), + .value = std::numeric_limits::max(), + }; + + if (write(m_ffb_fd, &play, sizeof(play)) < 0) + ERROR_LOG_FMT(COMMON, "EV_FF: {}", Common::LastStrerrorString()); + } + } + +private: + const int m_ffb_fd; + s16 m_effect_id = -1; +}; + +class SpringEffect final : ScopedForceFeedbackEffect, public Core::SpringEffect +{ +public: + using ScopedForceFeedbackEffect::ScopedForceFeedbackEffect; + + void SetForce(double gain, double center_position) override + { + INFO_LOG_FMT(CONTROLLERINTERFACE, "SpringEffect: {:.2} {:.2}", gain, center_position); + + if (gain == 0.0) + { + UpdateEffect(nullptr); + return; + } + + ff_effect effect{.type = FF_SPRING}; // // "Values above 32767 ms (0x7fff) should not be used and have unspecified results." @@ -778,38 +817,14 @@ public: condition[0].center = ControllerEmu::MapFloat(center_position, 0); - if (ioctl(m_ffb_fd, EVIOCSFF, &effect) < 0) - { - ERROR_LOG_FMT(COMMON, "EVIOCSFF FF_SPRING: {}", Common::LastStrerrorString()); - return; - } - - if (m_effect_id == -1) - { - m_effect_id = effect.id; - - const input_event play{ - .type = EV_FF, - .code = u16(m_effect_id), - .value = std::numeric_limits::max(), - }; - - if (write(m_ffb_fd, &play, sizeof(play)) < 0) - ERROR_LOG_FMT(COMMON, "EV_FF: {}", Common::LastStrerrorString()); - } + UpdateEffect(&effect); } - -private: - const int m_ffb_fd; - s16 m_effect_id = -1; }; -class FrictionEffect final : public Core::FrictionEffect +class FrictionEffect final : ScopedForceFeedbackEffect, public Core::FrictionEffect { public: - explicit FrictionEffect(int ffb_fd) : m_ffb_fd{ffb_fd} {} - - ~FrictionEffect() override { SetForce(0.0); } + using ScopedForceFeedbackEffect::ScopedForceFeedbackEffect; void SetForce(double gain) override { @@ -817,24 +832,11 @@ public: if (gain == 0.0) { - if (m_effect_id != -1) - { - if (ioctl(m_ffb_fd, EVIOCRMFF, m_effect_id) < 0) - ERROR_LOG_FMT(COMMON, "EVIOCRMFF: {}", Common::LastStrerrorString()); - - // TODO: Is it correct to not remove this effect on destruction. - // Is it enough to close the parent fd ? - - m_effect_id = -1; - } - + UpdateEffect(nullptr); return; } - ff_effect effect{ - .type = FF_FRICTION, - .id = m_effect_id, - }; + ff_effect effect{.type = FF_FRICTION}; // // "Values above 32767 ms (0x7fff) should not be used and have unspecified results." @@ -851,30 +853,8 @@ public: condition[0].right_coeff = coeff; condition[0].left_coeff = coeff; - if (ioctl(m_ffb_fd, EVIOCSFF, &effect) < 0) - { - ERROR_LOG_FMT(COMMON, "EVIOCSFF FF_SPRING: {}", Common::LastStrerrorString()); - return; - } - - if (m_effect_id == -1) - { - m_effect_id = effect.id; - - const input_event play{ - .type = EV_FF, - .code = u16(m_effect_id), - .value = std::numeric_limits::max(), - }; - - if (write(m_ffb_fd, &play, sizeof(play)) < 0) - ERROR_LOG_FMT(COMMON, "EV_FF: {}", Common::LastStrerrorString()); - } + UpdateEffect(&effect); } - -private: - const int m_ffb_fd; - s16 m_effect_id = -1; }; std::unique_ptr evdevDevice::CreateSpringEffect()