implement generic high-level input debouncing
This commit is contained in:
@@ -4,7 +4,25 @@
|
|||||||
#include "RageInput.h"
|
#include "RageInput.h"
|
||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
#include "RageThreads.h"
|
#include "RageThreads.h"
|
||||||
|
#include "Preference.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some input devices require debouncing. Do this on both press and release. After
|
||||||
|
* reporting a change in state, don't report another for the debounce period. If a
|
||||||
|
* button is reported pressed, report it. If the button is immediately reported
|
||||||
|
* released, wait a period before reporting it; if the button is repressed during
|
||||||
|
* that time, the release is never reported.
|
||||||
|
*
|
||||||
|
* The detail is important: if a button is pressed for 1ms and released, we must
|
||||||
|
* always report it, even if the debounce period is 10ms, since it might be a coin
|
||||||
|
* counter with a very short signal. The only time we discard events is if a button
|
||||||
|
* is pressed, released and then pressed again quickly.
|
||||||
|
*
|
||||||
|
* This delay in events is ordinarily not noticable, because the we report initial
|
||||||
|
* presses and releases immediately. However, if a real press is ever delayed,
|
||||||
|
* this won't cause timing problems, because the event timestamp is preserved.
|
||||||
|
*/
|
||||||
|
static Preference<float> g_fInputDebounceTime( "InputDebounceTime", 0 );
|
||||||
|
|
||||||
InputFilter* INPUTFILTER = NULL; // global and accessable from anywhere in our program
|
InputFilter* INPUTFILTER = NULL; // global and accessable from anywhere in our program
|
||||||
|
|
||||||
@@ -49,6 +67,15 @@ void InputFilter::ResetRepeatRate()
|
|||||||
SetRepeatRate( TIME_BEFORE_SLOW_REPEATS, SLOW_REPEATS_PER_SEC, TIME_BEFORE_FAST_REPEATS, FAST_REPEATS_PER_SEC );
|
SetRepeatRate( TIME_BEFORE_SLOW_REPEATS, SLOW_REPEATS_PER_SEC, TIME_BEFORE_FAST_REPEATS, FAST_REPEATS_PER_SEC );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputFilter::ButtonState::ButtonState():
|
||||||
|
m_BeingHeldTime(RageZeroTimer),
|
||||||
|
m_LastReportTime(RageZeroTimer)
|
||||||
|
{
|
||||||
|
m_BeingHeld = false;
|
||||||
|
m_bLastReportedHeld = false;
|
||||||
|
m_fSecsHeld = m_Level = m_LastLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void InputFilter::ButtonPressed( DeviceInput di, bool Down )
|
void InputFilter::ButtonPressed( DeviceInput di, bool Down )
|
||||||
{
|
{
|
||||||
LockMut(*queuemutex);
|
LockMut(*queuemutex);
|
||||||
@@ -71,13 +98,11 @@ void InputFilter::ButtonPressed( DeviceInput di, bool Down )
|
|||||||
|
|
||||||
bs.m_Level = di.level;
|
bs.m_Level = di.level;
|
||||||
|
|
||||||
if( bs.m_BeingHeld == Down )
|
if( bs.m_BeingHeld != Down )
|
||||||
return;
|
{
|
||||||
|
bs.m_BeingHeld = Down;
|
||||||
bs.m_BeingHeld = Down;
|
bs.m_BeingHeldTime = di.ts;
|
||||||
bs.m_fSecsHeld = 0;
|
}
|
||||||
|
|
||||||
queue.push_back( InputEvent(di,Down? IET_FIRST_PRESS:IET_RELEASE) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputFilter::SetButtonComment( DeviceInput di, const CString &sComment )
|
void InputFilter::SetButtonComment( DeviceInput di, const CString &sComment )
|
||||||
@@ -129,6 +154,17 @@ void InputFilter::Update(float fDeltaTime)
|
|||||||
di.button = b;
|
di.button = b;
|
||||||
di.level = bs.m_Level;
|
di.level = bs.m_Level;
|
||||||
|
|
||||||
|
/* Generate IET_FIRST_PRESS and IET_RELEASE events. */
|
||||||
|
if( now - bs.m_LastReportTime >= g_fInputDebounceTime && bs.m_BeingHeld != bs.m_bLastReportedHeld )
|
||||||
|
{
|
||||||
|
bs.m_LastReportTime = now;
|
||||||
|
bs.m_bLastReportedHeld = bs.m_BeingHeld;
|
||||||
|
bs.m_fSecsHeld = 0;
|
||||||
|
|
||||||
|
di.ts = bs.m_BeingHeldTime;
|
||||||
|
queue.push_back( InputEvent(di,bs.m_bLastReportedHeld? IET_FIRST_PRESS:IET_RELEASE) );
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate IET_LEVEL_CHANGED events. */
|
/* Generate IET_LEVEL_CHANGED events. */
|
||||||
if( bs.m_LastLevel != bs.m_Level && bs.m_Level != -1 )
|
if( bs.m_LastLevel != bs.m_Level && bs.m_Level != -1 )
|
||||||
{
|
{
|
||||||
@@ -137,7 +173,7 @@ void InputFilter::Update(float fDeltaTime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Generate IET_FAST_REPEAT and IET_SLOW_REPEAT events. */
|
/* Generate IET_FAST_REPEAT and IET_SLOW_REPEAT events. */
|
||||||
if( !bs.m_BeingHeld )
|
if( !bs.m_bLastReportedHeld )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const float fOldHoldTime = bs.m_fSecsHeld;
|
const float fOldHoldTime = bs.m_fSecsHeld;
|
||||||
@@ -170,7 +206,7 @@ void InputFilter::Update(float fDeltaTime)
|
|||||||
|
|
||||||
bool InputFilter::IsBeingPressed( DeviceInput di )
|
bool InputFilter::IsBeingPressed( DeviceInput di )
|
||||||
{
|
{
|
||||||
return m_ButtonState[di.device][di.button].m_BeingHeld;
|
return m_ButtonState[di.device][di.button].m_bLastReportedHeld;
|
||||||
}
|
}
|
||||||
|
|
||||||
float InputFilter::GetSecsHeld( DeviceInput di )
|
float InputFilter::GetSecsHeld( DeviceInput di )
|
||||||
|
|||||||
@@ -63,11 +63,18 @@ public:
|
|||||||
private:
|
private:
|
||||||
struct ButtonState
|
struct ButtonState
|
||||||
{
|
{
|
||||||
ButtonState() { m_BeingHeld = false; m_fSecsHeld = m_Level = m_LastLevel = 0; }
|
ButtonState();
|
||||||
bool m_BeingHeld;
|
bool m_BeingHeld; // actual current state
|
||||||
|
bool m_bLastReportedHeld; // last state reported by Update()
|
||||||
CString m_sComment;
|
CString m_sComment;
|
||||||
float m_fSecsHeld;
|
float m_fSecsHeld;
|
||||||
float m_Level, m_LastLevel;
|
float m_Level, m_LastLevel;
|
||||||
|
|
||||||
|
// Timestamp of the last real event that came in: the time m_BeingHeld changed.
|
||||||
|
RageTimer m_BeingHeldTime;
|
||||||
|
|
||||||
|
// The time that we actually reported the last event (used for debouncing).
|
||||||
|
RageTimer m_LastReportTime;
|
||||||
};
|
};
|
||||||
ButtonState m_ButtonState[NUM_INPUT_DEVICES][MAX_DEVICE_BUTTONS];
|
ButtonState m_ButtonState[NUM_INPUT_DEVICES][MAX_DEVICE_BUTTONS];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user