Skip to content

Commit

Permalink
Fix analog FF/RW in video and game
Browse files Browse the repository at this point in the history
  • Loading branch information
garbear committed Jul 5, 2017
1 parent 04cf835 commit 078700d
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 100 deletions.
115 changes: 61 additions & 54 deletions xbmc/input/joysticks/generic/FeatureHandling.cpp
Expand Up @@ -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());
Expand All @@ -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;
Expand All @@ -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<float>(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)
Expand All @@ -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<float>(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 ------------------------------------------------------------
Expand Down
12 changes: 9 additions & 3 deletions xbmc/input/joysticks/generic/FeatureHandling.h
Expand Up @@ -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
};

/*!
Expand Down
98 changes: 55 additions & 43 deletions xbmc/input/joysticks/keymaps/KeyHandler.cpp
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand All @@ -113,6 +116,7 @@ bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs)
}

m_bHeld = bPressed;
m_magnitude = magnitude;
m_lastHoldTimeMs = holdTimeMs;

return bHandled;
Expand All @@ -132,60 +136,68 @@ bool CKeyHandler::HandleActions(std::vector<const KeymapAction*> 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<const KeymapAction*> 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;
}
}

Expand Down
3 changes: 3 additions & 0 deletions xbmc/input/joysticks/keymaps/KeyHandler.h
Expand Up @@ -56,6 +56,8 @@ namespace JOYSTICK
void Reset();

bool HandleActions(std::vector<const KeymapAction*> actions, float magnitude, unsigned int holdTimeMs);
bool HandleRelease(std::vector<const KeymapAction*> actions);

bool HandleAction(const KeymapAction& action, float magnitude, unsigned int holdTimeMs);

// Check criteria for sending a repeat action
Expand All @@ -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;
Expand Down

0 comments on commit 078700d

Please sign in to comment.