diff --git a/src/addon.cpp b/src/addon.cpp index aa9c3917..d958f530 100644 --- a/src/addon.cpp +++ b/src/addon.cpp @@ -192,15 +192,19 @@ PERIPHERAL_ERROR GetEvents(unsigned int* event_count, PERIPHERAL_EVENT** events) if (!event_count || !events) return PERIPHERAL_ERROR_INVALID_PARAMETERS; + PERIPHERAL_ERROR result = PERIPHERAL_ERROR_FAILED; + std::vector peripheralEvents; if (CJoystickManager::Get().GetEvents(peripheralEvents)) { *event_count = peripheralEvents.size(); ADDON::PeripheralEvents::ToStructs(peripheralEvents, events); - return PERIPHERAL_NO_ERROR; + result = PERIPHERAL_NO_ERROR; } - return PERIPHERAL_ERROR_FAILED; + CJoystickManager::Get().ProcessEvents(); + + return result; } void FreeEvents(unsigned int event_count, PERIPHERAL_EVENT* events) diff --git a/src/api/Joystick.h b/src/api/Joystick.h index ed347088..4c49bbf9 100644 --- a/src/api/Joystick.h +++ b/src/api/Joystick.h @@ -86,6 +86,11 @@ namespace JOYSTICK */ virtual bool SendEvent(const ADDON::PeripheralEvent& event); + /*! + * Process events sent to the joystick + */ + virtual void ProcessEvents() { } + /*! * Tries to power off the joystick. */ diff --git a/src/api/JoystickManager.cpp b/src/api/JoystickManager.cpp index ab2e9e80..51b6314c 100644 --- a/src/api/JoystickManager.cpp +++ b/src/api/JoystickManager.cpp @@ -266,6 +266,14 @@ bool CJoystickManager::SendEvent(const ADDON::PeripheralEvent& event) return bHandled; } +void CJoystickManager::ProcessEvents() +{ + CLockObject lock(m_joystickMutex); + + for (const JoystickPtr& joystick : m_joysticks) + joystick->ProcessEvents(); +} + void CJoystickManager::TriggerScan(void) { if (m_scanner) diff --git a/src/api/JoystickManager.h b/src/api/JoystickManager.h index 69f0c626..5dfc620a 100644 --- a/src/api/JoystickManager.h +++ b/src/api/JoystickManager.h @@ -90,6 +90,11 @@ namespace JOYSTICK */ bool SendEvent(const ADDON::PeripheralEvent& event); + /*! + * \brief Process events that have arrived since the last call to ProcessEvents() + */ + void ProcessEvents(); + /*! * \brief Trigger a scan for joysticks through the callback */ diff --git a/src/api/udev/JoystickUdev.cpp b/src/api/udev/JoystickUdev.cpp index d0e62bd6..28ace248 100644 --- a/src/api/udev/JoystickUdev.cpp +++ b/src/api/udev/JoystickUdev.cpp @@ -51,7 +51,9 @@ CJoystickUdev::CJoystickUdev(udev_device* dev, const char* path) m_fd(INVALID_FD), m_bInitialized(false), m_has_set_ff(false), - m_effect(-1) + m_effect(-1), + m_motors(), + m_previousMotors() { for (unsigned int i = 0; i < MOTOR_COUNT; i++) m_motors[i] = 0; @@ -99,6 +101,75 @@ void CJoystickUdev::Deinitialize(void) CJoystick::Deinitialize(); } +void CJoystickUdev::ProcessEvents(void) +{ + uint32_t oldStrength = static_cast(m_previousMotors[MOTOR_STRONG]) + + static_cast(m_previousMotors[MOTOR_WEAK]); + uint32_t newStrength = static_cast(m_motors[MOTOR_STRONG]) + + static_cast(m_motors[MOTOR_WEAK]); + + bool bWasPlaying = (oldStrength > 0); + bool bIsPlaying = (newStrength > 0); + + if (!bWasPlaying && !bIsPlaying) + { + // Nothing to do + } + else if (!bWasPlaying && bIsPlaying) + { + UpdateMotorState(); + + // Play effect + Play(true); + } + else if (bWasPlaying && !bIsPlaying) + { + // Stop the effect + Play(false); + } + else + { + if (oldStrength != newStrength) + UpdateMotorState(); + } + + m_previousMotors = m_motors; +} + +void CJoystickUdev::Play(bool bPlayStop) +{ + struct input_event play = { { } }; + + play.type = EV_FF; + play.code = m_effect; + play.value = bPlayStop; + + if (write(m_fd, &play, sizeof(play)) < (ssize_t)sizeof(play)) + esyslog("[udev]: Failed to play rumble effect on \"%s\"", Name().c_str()); +} + +void CJoystickUdev::UpdateMotorState() +{ + struct ff_effect e = { }; + + int old_effect = m_has_set_ff ? m_effect : -1; + + e.type = FF_RUMBLE; + e.id = old_effect; + e.u.rumble.strong_magnitude = m_motors[MOTOR_STRONG]; + e.u.rumble.weak_magnitude = m_motors[MOTOR_WEAK]; + + if (ioctl(m_fd, EVIOCSFF, &e) < 0) + { + esyslog("Failed to set rumble effect on \"%s\"", Name().c_str()); + } + else + { + m_effect = e.id; + m_has_set_ff = true; + } +} + bool CJoystickUdev::ScanEvents(void) { input_event events[32]; @@ -272,65 +343,7 @@ bool CJoystickUdev::SetMotor(unsigned int motorIndex, float magnitude) uint16_t strength = std::min(0xffff, static_cast(magnitude * 0xffff)); - bool bChanged = false; - - if (strength != m_motors[motorIndex]) - bChanged = true; - - if (!bChanged) - return true; - - uint32_t oldStrength = static_cast(m_motors[MOTOR_STRONG]) + - static_cast(m_motors[MOTOR_WEAK]); - m_motors[motorIndex] = strength; - uint32_t newStrength = static_cast(m_motors[MOTOR_STRONG]) + - static_cast(m_motors[MOTOR_WEAK]); - - if (newStrength > 0) - { - // Create new or update old playing state - struct ff_effect e = { }; - - int old_effect = m_has_set_ff ? m_effect : -1; - - e.type = FF_RUMBLE; - e.id = old_effect; - e.u.rumble.strong_magnitude = m_motors[MOTOR_STRONG]; - e.u.rumble.weak_magnitude = m_motors[MOTOR_WEAK]; - - if (ioctl(m_fd, EVIOCSFF, &e) < 0) - { - esyslog("Failed to set rumble effect on \"%s\"", Name().c_str()); - return false; - } - - m_effect = e.id; - m_has_set_ff = true; - } - - bool bWasPlaying = !!oldStrength; - bool bIsPlaying = !!newStrength; - - if (bWasPlaying != bIsPlaying) - { - struct input_event play = { { } }; - - play.type = EV_FF; - play.code = m_effect; - play.value = bIsPlaying; - - // udev fails to stop playing if event is written too soon after last ioctl - if (!bIsPlaying) - usleep(2500); - - if (write(m_fd, &play, sizeof(play)) < (ssize_t)sizeof(play)) - { - esyslog("[udev]: Failed to play rumble effect on \"%s\"", Name().c_str()); - return false; - } - } - return true; } diff --git a/src/api/udev/JoystickUdev.h b/src/api/udev/JoystickUdev.h index b19fa63a..2185303a 100644 --- a/src/api/udev/JoystickUdev.h +++ b/src/api/udev/JoystickUdev.h @@ -41,6 +41,7 @@ #include "api/Joystick.h" +#include #include #include @@ -65,6 +66,7 @@ namespace JOYSTICK virtual bool Equals(const CJoystick* rhs) const override; virtual bool Initialize(void) override; virtual void Deinitialize(void) override; + virtual void ProcessEvents(void) override; protected: // implementation of CJoystick @@ -72,6 +74,9 @@ namespace JOYSTICK bool SetMotor(unsigned int motorIndex, float magnitude); private: + void UpdateMotorState(); + void Play(bool bPlayStop); + struct Axis { unsigned int axisIndex; @@ -93,6 +98,7 @@ namespace JOYSTICK // Joystick properties std::map m_button_bind; // Maps keycodes -> button std::map m_axes_bind; // Maps keycodes -> axis and axis info - uint16_t m_motors[MOTOR_COUNT]; + std::array m_motors; + std::array m_previousMotors; }; }