From 078700d0b2804355eedffff590512635d4d89563 Mon Sep 17 00:00:00 2001 From: Garrett Brown Date: Tue, 4 Jul 2017 14:52:13 -0700 Subject: [PATCH] Fix analog FF/RW in video and game --- .../joysticks/generic/FeatureHandling.cpp | 115 ++++++++++-------- .../input/joysticks/generic/FeatureHandling.h | 12 +- xbmc/input/joysticks/keymaps/KeyHandler.cpp | 98 ++++++++------- xbmc/input/joysticks/keymaps/KeyHandler.h | 3 + 4 files changed, 128 insertions(+), 100 deletions(-) diff --git a/xbmc/input/joysticks/generic/FeatureHandling.cpp b/xbmc/input/joysticks/generic/FeatureHandling.cpp index 952e1deb4c7f1..3969dd76067ed 100644 --- a/xbmc/input/joysticks/generic/FeatureHandling.cpp +++ b/xbmc/input/joysticks/generic/FeatureHandling.cpp @@ -64,10 +64,11 @@ bool CJoystickFeature::AcceptsInput(bool bActivation) CScalarFeature::CScalarFeature(const FeatureName& name, IInputHandler* handler, IButtonMap* buttonMap) : CJoystickFeature(name, handler, buttonMap), + m_inputType(INPUT_TYPE::UNKNOWN), m_bDigitalState(false), m_motionStartTimeMs(0), m_analogState(0.0f), - m_analogEvent(false), + m_bActivated(false), m_bDiscrete(true) { GAME::ControllerPtr controller = CServiceBroker::GetGameServices().GetController(handler->ControllerID()); @@ -89,6 +90,10 @@ bool CScalarFeature::OnDigitalMotion(const CDriverPrimitive& source, bool bPress bool CScalarFeature::OnAnalogMotion(const CDriverPrimitive& source, float magnitude) { + // Update activated status + if (magnitude > 0.0f) + m_bActivated = true; + // Update discrete status if (magnitude != 0.0f && magnitude != 1.0f) m_bDiscrete = false; @@ -105,48 +110,10 @@ bool CScalarFeature::OnAnalogMotion(const CDriverPrimitive& source, float magnit void CScalarFeature::ProcessMotions(void) { - if (m_bDigitalState) - { - if (m_motionStartTimeMs == 0) - { - // Button was just pressed, record start time and exit (button press - // event was already sent this frame) - m_motionStartTimeMs = XbmcThreads::SystemClockMillis(); - } - else - { - // Button has been pressed more than one event frame - const unsigned int elapsed = XbmcThreads::SystemClockMillis() - m_motionStartTimeMs; - m_handler->OnButtonHold(m_name, elapsed); - } - } - else if (m_analogEvent) - { - float magnitude = m_analogState; - - // Calculate time elapsed since motion began - const unsigned int elapsed = XbmcThreads::SystemClockMillis() - m_motionStartTimeMs; - - // If analog value is discrete, ramp up magnitude - if (m_bDiscrete) - { - if (elapsed < DISCRETE_ANALOG_RAMPUP_TIME_MS) - { - magnitude *= static_cast(elapsed) / DISCRETE_ANALOG_RAMPUP_TIME_MS; - if (magnitude < DISCRETE_ANALOG_START_VALUE) - magnitude = DISCRETE_ANALOG_START_VALUE; - } - } - - m_handler->OnButtonMotion(m_name, magnitude, elapsed); - - // Disable sending events after feature is reset - if (m_analogState == 0.0f) - { - m_analogEvent = false; - m_motionStartTimeMs = 0; - } - } + if (m_inputType == INPUT_TYPE::DIGITAL && m_bDigitalState) + ProcessDigitalMotion(); + else if (m_inputType == INPUT_TYPE::ANALOG) + ProcessAnalogMotion(); } bool CScalarFeature::OnDigitalMotion(bool bPressed) @@ -169,23 +136,63 @@ bool CScalarFeature::OnAnalogMotion(float magnitude) { const bool bActivated = (magnitude != 0.0f); - if (m_analogState != 0.0f || magnitude != 0.0f) + // Update analog state + m_analogState = magnitude; + + // Update motion time + if (!bActivated) + m_motionStartTimeMs = 0; + else if (m_motionStartTimeMs == 0) + m_motionStartTimeMs = XbmcThreads::SystemClockMillis(); + + // Log activation/deactivation + if (m_bDigitalState != bActivated) { - m_analogState = magnitude; - m_analogEvent = true; - if (m_motionStartTimeMs == 0) - m_motionStartTimeMs = XbmcThreads::SystemClockMillis(); + m_bDigitalState = bActivated; + CLog::Log(LOGDEBUG, "FEATURE [ %s ] on %s %s", m_name.c_str(), m_handler->ControllerID().c_str(), + bActivated ? "activated" : "deactivated"); + } - // Log activation/deactivation - if (m_bDigitalState != bActivated) + return true; +} + +void CScalarFeature::ProcessDigitalMotion() +{ + if (m_motionStartTimeMs == 0) + { + // Button was just pressed, record start time and exit (button press event + // was already sent this frame) + m_motionStartTimeMs = XbmcThreads::SystemClockMillis(); + } + else + { + // Button has been pressed more than one event frame + const unsigned int elapsed = XbmcThreads::SystemClockMillis() - m_motionStartTimeMs; + m_handler->OnButtonHold(m_name, elapsed); + } +} + +void CScalarFeature::ProcessAnalogMotion() +{ + float magnitude = m_analogState; + + // Calculate time elapsed since motion began + unsigned int elapsed = 0; + if (m_motionStartTimeMs > 0) + elapsed = XbmcThreads::SystemClockMillis() - m_motionStartTimeMs; + + // If analog value is discrete, ramp up magnitude + if (m_bActivated && m_bDiscrete) + { + if (elapsed < DISCRETE_ANALOG_RAMPUP_TIME_MS) { - m_bDigitalState = bActivated; - CLog::Log(LOGDEBUG, "FEATURE [ %s ] on %s %s", m_name.c_str(), m_handler->ControllerID().c_str(), - bActivated ? "activated" : "deactivated"); + magnitude *= static_cast(elapsed) / DISCRETE_ANALOG_RAMPUP_TIME_MS; + if (magnitude < DISCRETE_ANALOG_START_VALUE) + magnitude = DISCRETE_ANALOG_START_VALUE; } } - return true; + m_handler->OnButtonMotion(m_name, magnitude, elapsed); } // --- CAnalogStick ------------------------------------------------------------ diff --git a/xbmc/input/joysticks/generic/FeatureHandling.h b/xbmc/input/joysticks/generic/FeatureHandling.h index 29d84fbc4652f..0e4f33db3463c 100644 --- a/xbmc/input/joysticks/generic/FeatureHandling.h +++ b/xbmc/input/joysticks/generic/FeatureHandling.h @@ -111,12 +111,18 @@ namespace JOYSTICK bool OnDigitalMotion(bool bPressed); bool OnAnalogMotion(float magnitude); + void ProcessDigitalMotion(); + void ProcessAnalogMotion(); + + // State variables INPUT_TYPE m_inputType = INPUT_TYPE::UNKNOWN; bool m_bDigitalState; unsigned int m_motionStartTimeMs; - float m_analogState; - bool m_analogEvent; - bool m_bDiscrete; + + // Analog state variables + float m_analogState; // The current magnitude + float m_bActivated; // Set to true when first activated (magnitude > 0.0) + bool m_bDiscrete; // Set to false when a non-discrete axis is detected }; /*! diff --git a/xbmc/input/joysticks/keymaps/KeyHandler.cpp b/xbmc/input/joysticks/keymaps/KeyHandler.cpp index 81fc298360366..c3340010ed94f 100644 --- a/xbmc/input/joysticks/keymaps/KeyHandler.cpp +++ b/xbmc/input/joysticks/keymaps/KeyHandler.cpp @@ -54,6 +54,7 @@ CKeyHandler::CKeyHandler(const std::string &keyName, IActionListener *actionHand void CKeyHandler::Reset() { m_bHeld = false; + m_magnitude = 0.0f; m_holdStartTimeMs = 0; m_lastHoldTimeMs = 0; m_bActionSent = false; @@ -67,7 +68,9 @@ bool CKeyHandler::OnDigitalMotion(bool bPressed, unsigned int holdTimeMs) bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs) { - bool bHandled = false; + // Don't send deactivation event more than once + if (m_magnitude == 0.0f && magnitude == 0.0f) + return false; // Calculate press state const bool bPressed = IsPressed(magnitude); @@ -99,7 +102,7 @@ bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs) actionsWithHotkeys.emplace_back(&action); } - bHandled = HandleActions(std::move(actionsWithHotkeys), magnitude, holdTimeMs); + bool bHandled = HandleActions(std::move(actionsWithHotkeys), magnitude, holdTimeMs); // If that failed, try again with all actions if (!bHandled) @@ -113,6 +116,7 @@ bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs) } m_bHeld = bPressed; + m_magnitude = magnitude; m_lastHoldTimeMs = holdTimeMs; return bHandled; @@ -132,60 +136,68 @@ bool CKeyHandler::HandleActions(std::vector actions, float bool bHandled = false; - if (magnitude > 0.0f) - { - // Actions are sorted by holdtime, so the final action is the one with the - // greatest holdtime - const KeymapAction& finalAction = **actions.rbegin(); - const unsigned int maxHoldTimeMs = finalAction.holdTimeMs; + // Actions are sorted by holdtime, so the final action is the one with the + // greatest holdtime + const KeymapAction& finalAction = **actions.rbegin(); + const unsigned int maxHoldTimeMs = finalAction.holdTimeMs; - const bool bHasDelay = (maxHoldTimeMs != 0); - if (!bHasDelay) + const bool bHasDelay = (maxHoldTimeMs > 0); + if (!bHasDelay) + { + bHandled = HandleAction(finalAction, magnitude, holdTimeMs); + } + else + { + // If holdtime has exceeded the last action, execute it now + if (holdTimeMs >= finalAction.holdTimeMs) { + // Force holdtime to zero for the initial press + if (!m_bActionSent) + holdTimeMs = 0; + else + holdTimeMs -= finalAction.holdTimeMs; + bHandled = HandleAction(finalAction, magnitude, holdTimeMs); } else { - // If holdtime has exceeded the last action, execute it now - if (holdTimeMs >= finalAction.holdTimeMs) - { - // Force holdtime to zero for the initial press - if (!m_bActionSent) - holdTimeMs = 0; - else - holdTimeMs -= finalAction.holdTimeMs; - - bHandled = HandleAction(finalAction, magnitude, holdTimeMs); - } + // Calculate press state + const bool bPressed = IsPressed(magnitude); + const bool bJustReleased = m_bHeld && !bPressed; + + // If button was just released, send a release action + if (bJustReleased) + bHandled = HandleRelease(actions); } } - else if (actions.size() > 1) - { - // If button was help before being released, send a release action - if (m_bHeld) - { - // Holdtime is zero, so use previous holdtime from before button release - holdTimeMs = m_lastHoldTimeMs; - // Send an action on release if one occurs before the holdtime - for (auto it = actions.begin(); it != actions.end(); ) - { - const KeymapAction &action = **it; + return bHandled; +} - unsigned int thisHoldTime = (*it)->holdTimeMs; +bool CKeyHandler::HandleRelease(std::vector actions) +{ + bool bHandled = false; - ++it; - if (it == actions.end()) - break; + // Use previous holdtime from before button release + const unsigned int holdTimeMs = m_lastHoldTimeMs; - unsigned int nextHoldTime = (*it)->holdTimeMs; + // Send an action on release if one occurs before the holdtime + for (auto it = actions.begin(); it != actions.end(); ) + { + const KeymapAction &action = **it; - if (thisHoldTime <= holdTimeMs && holdTimeMs < nextHoldTime) - { - bHandled = HandleAction(action, 1.0f, 0); - break; - } - } + unsigned int thisHoldTime = (*it)->holdTimeMs; + + ++it; + if (it == actions.end()) + break; + + unsigned int nextHoldTime = (*it)->holdTimeMs; + + if (thisHoldTime <= holdTimeMs && holdTimeMs < nextHoldTime) + { + bHandled = HandleAction(action, 1.0f, 0); + break; } } diff --git a/xbmc/input/joysticks/keymaps/KeyHandler.h b/xbmc/input/joysticks/keymaps/KeyHandler.h index 9b848e5f517ea..54725de57fd87 100644 --- a/xbmc/input/joysticks/keymaps/KeyHandler.h +++ b/xbmc/input/joysticks/keymaps/KeyHandler.h @@ -56,6 +56,8 @@ namespace JOYSTICK void Reset(); bool HandleActions(std::vector actions, float magnitude, unsigned int holdTimeMs); + bool HandleRelease(std::vector actions); + bool HandleAction(const KeymapAction& action, float magnitude, unsigned int holdTimeMs); // Check criteria for sending a repeat action @@ -72,6 +74,7 @@ namespace JOYSTICK // State variables bool m_bHeld; + float m_magnitude; unsigned int m_holdStartTimeMs; unsigned int m_lastHoldTimeMs; bool m_bActionSent;