Include the complete input state with each input report.

This only deals with buttons being held, so won't cause
performance issues.

This deals with a general problem of the input layer:
you can query the current state of the inputs, but inputs
are received in a queue, causing inconsistencies.

This is why pressing enter during a load, then holding Alt
after pressing it, causes the game to switch fullscreen
after the load finishes; checking for "alt-enter" should
be checking if Alt was pressed when Enter was pressed,
not whether it's pressed right now.

Similarly, CodeDetector has difficulty handling a "Right-Left"
and a "Left-Right" code simultaneously.  If both buttons
are pressed quickly, it needs to check whether Right was
pressed at the time Left was reported, not at the time
EnteredCode was called.
This commit is contained in:
Glenn Maynard
2006-09-08 04:03:14 +00:00
parent 6daf49eac6
commit be6d3d4043
4 changed files with 58 additions and 7 deletions
+49 -5
View File
@@ -42,6 +42,8 @@ namespace
{
return g_ButtonStates[di];
}
DeviceInputList g_CurrentState;
}
/*
@@ -190,6 +192,30 @@ void InputFilter::ReportButtonChange( const DeviceInput &di, InputEventType t )
InputEvent &ie = queue.back();
ie.type = t;
ie.di = di;
/*
* Include a list of all buttons that were pressed at the time of this event. We
* can create this efficiently using g_ButtonStates. Use a vector and not a
* map, for efficiency; most code will not use this information. Iterating over
* g_ButtonStates will be in DeviceInput order, so users can binary search this
* list (eg. std::lower_bound).
*/
MakeButtonStateList( ie.m_ButtonState );
g_CurrentState = ie.m_ButtonState;
}
void InputFilter::MakeButtonStateList( vector<DeviceInput> &aInputOut ) const
{
aInputOut.reserve( g_ButtonStates.size() );
for( ButtonStateMap::const_iterator it = g_ButtonStates.begin(); it != g_ButtonStates.end(); ++it )
{
const DeviceInput &di = it->first;
const ButtonState &bs = it->second;
if( !bs.m_bLastReportedHeld )
continue;
aInputOut.push_back( di );
aInputOut.back().ts = bs.m_LastInputTime;
}
}
void InputFilter::Update( float fDeltaTime )
@@ -279,16 +305,34 @@ void InputFilter::Update( float fDeltaTime )
g_ButtonStates.erase( *it );
}
bool InputFilter::IsBeingPressed( const DeviceInput &di )
template<typename T, typename IT>
const T *FindItemBinarySearch( IT begin, IT end, const T &i )
{
LockMut(*queuemutex);
return GetButtonState( di ).m_bLastReportedHeld;
IT it = lower_bound( begin, end, i );
if( it == end || *it != i )
return NULL;
return &*it;
}
float InputFilter::GetSecsHeld( const DeviceInput &di )
bool InputFilter::IsBeingPressed( const DeviceInput &di, const DeviceInputList *pButtonState )
{
LockMut(*queuemutex);
return GetButtonState( di ).m_LastInputTime.Ago();
if( pButtonState == NULL )
pButtonState = &g_CurrentState;
const DeviceInput *pDI = FindItemBinarySearch( pButtonState->begin(), pButtonState->end(), di );
return pDI != NULL;
}
float InputFilter::GetSecsHeld( const DeviceInput &di, const DeviceInputList *pButtonState )
{
LockMut(*queuemutex);
if( pButtonState == NULL )
pButtonState = &g_CurrentState;
const DeviceInput *pDI = FindItemBinarySearch( pButtonState->begin(), pButtonState->end(), di );
if( pDI == NULL )
return 0;
return pDI->ts.Ago();
}
RString InputFilter::GetButtonComment( const DeviceInput &di ) const