2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2002-04-16 17:31:00 +00:00
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
Class: InputFilter
|
|
|
|
|
|
|
|
|
|
Desc: See header.
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
2002-04-16 17:31:00 +00:00
|
|
|
Chris Danford
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "InputFilter.h"
|
2002-05-01 19:14:55 +00:00
|
|
|
#include "RageLog.h"
|
2002-04-16 17:31:00 +00:00
|
|
|
#include "RageInput.h"
|
2003-07-26 21:58:48 +00:00
|
|
|
#include "RageThreads.h"
|
2002-06-14 22:25:22 +00:00
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
InputFilter* INPUTFILTER = NULL; // global and accessable from anywhere in our program
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2003-11-25 21:46:30 +00:00
|
|
|
static const float TIME_BEFORE_SLOW_REPEATS = 0.25f;
|
|
|
|
|
static const float TIME_BEFORE_FAST_REPEATS = 1.5f;
|
|
|
|
|
|
|
|
|
|
static const float SLOW_REPEATS_PER_SEC = 8;
|
|
|
|
|
static const float FAST_REPEATS_PER_SEC = 8;
|
|
|
|
|
|
|
|
|
|
static float g_fTimeBeforeSlow, g_fTimeBeforeFast, g_fTimeBetweenSlow, g_fTimeBetweenFast;
|
2003-07-26 21:58:48 +00:00
|
|
|
|
|
|
|
|
|
2002-09-08 06:10:23 +00:00
|
|
|
InputFilter::InputFilter()
|
2003-06-22 04:38:05 +00:00
|
|
|
{
|
2003-07-26 21:58:48 +00:00
|
|
|
queuemutex = new RageMutex;
|
2003-09-03 21:49:11 +00:00
|
|
|
memset( m_BeingHeld, 0, sizeof(m_BeingHeld) );
|
|
|
|
|
memset( m_BeingForced, 0, sizeof(m_BeingForced) );
|
|
|
|
|
memset( m_fSecsHeld, 0, sizeof(m_fSecsHeld) );
|
|
|
|
|
for( int d=0; d<NUM_INPUT_DEVICES; d++ ) // foreach InputDevice
|
2003-10-07 05:59:58 +00:00
|
|
|
for( int b=0; b < NUM_DEVICE_BUTTONS[d]; b++ ) // foreach button
|
2003-09-03 21:49:11 +00:00
|
|
|
m_fSecsToForce[d][b] = -1;
|
|
|
|
|
|
2003-07-26 22:29:34 +00:00
|
|
|
Reset();
|
2003-11-25 21:46:30 +00:00
|
|
|
ResetRepeatRate();
|
2003-07-26 21:58:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InputFilter::~InputFilter()
|
|
|
|
|
{
|
|
|
|
|
delete queuemutex;
|
2003-06-22 04:38:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InputFilter::Reset()
|
2002-09-08 06:10:23 +00:00
|
|
|
{
|
|
|
|
|
for( int i=0; i<NUM_INPUT_DEVICES; i++ )
|
2003-06-25 06:33:18 +00:00
|
|
|
ResetDevice( InputDevice(i) );
|
2002-09-08 06:10:23 +00:00
|
|
|
}
|
|
|
|
|
|
2003-11-25 21:46:30 +00:00
|
|
|
void InputFilter::SetRepeatRate( float fSlowDelay, float fSlowRate, float fFastDelay, float fFastRate )
|
|
|
|
|
{
|
|
|
|
|
g_fTimeBeforeSlow = fSlowDelay;
|
|
|
|
|
g_fTimeBeforeFast = fFastDelay;
|
|
|
|
|
g_fTimeBetweenSlow = 1/fSlowRate;
|
|
|
|
|
g_fTimeBetweenFast = 1/fFastRate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InputFilter::ResetRepeatRate()
|
|
|
|
|
{
|
|
|
|
|
SetRepeatRate( TIME_BEFORE_SLOW_REPEATS, SLOW_REPEATS_PER_SEC, TIME_BEFORE_FAST_REPEATS, FAST_REPEATS_PER_SEC );
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-16 01:35:48 +00:00
|
|
|
void InputFilter::ButtonPressed( DeviceInput di, bool Down )
|
2002-09-08 06:10:23 +00:00
|
|
|
{
|
2003-09-03 21:49:11 +00:00
|
|
|
LockMut(*queuemutex);
|
|
|
|
|
|
2003-02-16 01:35:48 +00:00
|
|
|
if(m_BeingHeld[di.device][di.button] == Down)
|
|
|
|
|
return;
|
2002-09-08 06:10:23 +00:00
|
|
|
|
2003-09-03 21:49:11 +00:00
|
|
|
const bool WasBeingPressed = IsBeingPressed( di );
|
|
|
|
|
|
2003-02-16 01:35:48 +00:00
|
|
|
m_BeingHeld[di.device][di.button] = Down;
|
|
|
|
|
m_fSecsHeld[di.device][di.button] = 0;
|
2003-10-02 02:03:29 +00:00
|
|
|
#if 0
|
|
|
|
|
if( 1 ) // PREFSMAN->m_bJoytechInput && di.IsJoystick() )
|
|
|
|
|
{
|
|
|
|
|
/* If this is a release of the right button, force it down for a little while, so
|
|
|
|
|
* the axis motion has a chance to come in before we register the right arrow release. */
|
|
|
|
|
const int RightButton = 'd';//JOY_13;
|
|
|
|
|
// const int LeftButton = 'a';//JOY_15;
|
|
|
|
|
if( !Down && di.button == RightButton )
|
|
|
|
|
{
|
|
|
|
|
LOG->Trace("temp force d");
|
|
|
|
|
ForceKey( DeviceInput(di.device, RightButton), 1 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2003-09-03 21:49:11 +00:00
|
|
|
if( WasBeingPressed != IsBeingPressed(di) )
|
|
|
|
|
{
|
|
|
|
|
InputEventType iet = IsBeingPressed(di)? IET_FIRST_PRESS:IET_RELEASE;
|
|
|
|
|
queue.push_back( InputEvent(di,iet) );
|
|
|
|
|
}
|
2003-10-02 02:03:29 +00:00
|
|
|
#if 0
|
|
|
|
|
if( 1 ) // PREFSMAN->m_bJoytechInput && di.IsJoystick() )
|
|
|
|
|
{
|
|
|
|
|
const int RightButton = 'd';//JOY_13;
|
|
|
|
|
const int LeftButton = 'a';//JOY_15;
|
|
|
|
|
bool NeedToForceBothButtons =
|
|
|
|
|
IsBeingPressed( DeviceInput(di.device, 'e'/*JOY_RIGHT*/) ) &&
|
|
|
|
|
!IsBeingPressed( DeviceInput(di.device, RightButton) );
|
|
|
|
|
LOG->Trace("--- %i", NeedToForceBothButtons );
|
|
|
|
|
if( NeedToForceBothButtons )
|
|
|
|
|
{
|
|
|
|
|
ForceKey( DeviceInput(di.device, RightButton), 0 );
|
|
|
|
|
ForceKey( DeviceInput(di.device, LeftButton), 0 );
|
|
|
|
|
} else {
|
|
|
|
|
StopForcingKey( DeviceInput(di.device, RightButton) );
|
|
|
|
|
StopForcingKey( DeviceInput(di.device, LeftButton) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2003-09-03 21:49:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Force a key down. Duration is the amount of time to force the key, or 0 to force
|
|
|
|
|
* it until we explicitly call StopForcingKey. */
|
|
|
|
|
void InputFilter::ForceKey( DeviceInput di, float duration )
|
|
|
|
|
{
|
|
|
|
|
LockMut(*queuemutex);
|
|
|
|
|
|
|
|
|
|
if( m_BeingForced[di.device][di.button] )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const bool WasBeingPressed = IsBeingPressed( di );
|
|
|
|
|
|
|
|
|
|
m_BeingForced[di.device][di.button] = true;
|
|
|
|
|
m_fSecsToForce[di.device][di.button] = duration;
|
|
|
|
|
m_fSecsHeld[di.device][di.button] = 0;
|
|
|
|
|
|
|
|
|
|
/* Send an IET_FIRST_PRESS event if the key wasn't already down. */
|
|
|
|
|
if( WasBeingPressed != IsBeingPressed( di ) )
|
|
|
|
|
{
|
|
|
|
|
InputEventType iet = IsBeingPressed(di)? IET_FIRST_PRESS:IET_RELEASE;
|
|
|
|
|
queue.push_back( InputEvent(di,iet) );
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-07-14 06:21:12 +00:00
|
|
|
|
2003-09-03 21:49:11 +00:00
|
|
|
void InputFilter::StopForcingKey( DeviceInput di )
|
|
|
|
|
{
|
2003-07-26 21:58:48 +00:00
|
|
|
LockMut(*queuemutex);
|
2003-09-03 21:49:11 +00:00
|
|
|
|
|
|
|
|
if( !m_BeingForced[di.device][di.button] )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const bool WasBeingPressed = IsBeingPressed( di );
|
|
|
|
|
|
|
|
|
|
m_BeingForced[di.device][di.button] = false;
|
|
|
|
|
m_fSecsToForce[di.device][di.button] = 0;
|
|
|
|
|
m_fSecsHeld[di.device][di.button] = 0;
|
|
|
|
|
|
|
|
|
|
/* Send an IET_RELEASE event if the key is no longer down. */
|
|
|
|
|
if( WasBeingPressed != IsBeingPressed(di) )
|
|
|
|
|
{
|
|
|
|
|
InputEventType iet = IsBeingPressed(di)? IET_FIRST_PRESS:IET_RELEASE;
|
|
|
|
|
queue.push_back( InputEvent(di,iet) );
|
|
|
|
|
}
|
2002-10-18 19:01:32 +00:00
|
|
|
}
|
|
|
|
|
|
2003-06-21 20:58:40 +00:00
|
|
|
/* Release all buttons on the given device. */
|
|
|
|
|
void InputFilter::ResetDevice( InputDevice dev )
|
|
|
|
|
{
|
2003-10-07 05:59:58 +00:00
|
|
|
for( int button = 0; button < NUM_DEVICE_BUTTONS[dev]; ++button )
|
2003-06-21 20:58:40 +00:00
|
|
|
ButtonPressed( DeviceInput(dev, button), false );
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-16 01:35:48 +00:00
|
|
|
void InputFilter::Update(float fDeltaTime)
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2003-10-02 02:03:29 +00:00
|
|
|
// static float AutoStartTime=0;
|
|
|
|
|
// AutoStartTime -= fDeltaTime;
|
|
|
|
|
// if( AutoStartTime <= 0 )
|
|
|
|
|
// {
|
|
|
|
|
// AutoStartTime = 0.5f;
|
|
|
|
|
// ButtonPressed( DeviceInput(DEVICE_KEYBOARD, 'a'), true );
|
|
|
|
|
// ButtonPressed( DeviceInput(DEVICE_KEYBOARD, 'a'), false );
|
|
|
|
|
// }
|
2003-09-03 21:49:11 +00:00
|
|
|
RageTimer now;
|
|
|
|
|
|
2003-09-07 19:35:32 +00:00
|
|
|
// Constructing the DeviceInput inside the nested loops caues terrible
|
|
|
|
|
// performance. So, construct it once outside the loop, then change
|
|
|
|
|
// .device and .button inside the loop. I have no idea what is causing
|
|
|
|
|
// the slowness. DeviceInput is a very small and simple structure, but
|
|
|
|
|
// it's constructor was being called NUM_INPUT_DEVICES*NUM_DEVICE_BUTTONS
|
|
|
|
|
// (>2000) times per Update().
|
2003-09-28 23:23:21 +00:00
|
|
|
/* This should be fixed: DeviceInput's ctor uses an init list, so RageTimer
|
|
|
|
|
* isn't initialized each time. */
|
|
|
|
|
// DeviceInput di( (InputDevice)0,0,now);
|
2003-09-07 19:35:32 +00:00
|
|
|
|
2002-11-29 20:37:12 +00:00
|
|
|
INPUTMAN->Update( fDeltaTime );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2003-07-14 06:21:12 +00:00
|
|
|
/* Make sure that nothing gets inserted while we do this, to prevent
|
|
|
|
|
* things like "key pressed, key release, key repeat". */
|
2003-07-26 21:58:48 +00:00
|
|
|
LockMut(*queuemutex);
|
2003-07-14 06:21:12 +00:00
|
|
|
|
2003-10-07 05:59:58 +00:00
|
|
|
// Don't reconstruct "di" inside the loop. This line alone is
|
|
|
|
|
// taking 4% of the CPU on a P3-666.
|
|
|
|
|
DeviceInput di( (InputDevice)0,0,now);
|
|
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
for( int d=0; d<NUM_INPUT_DEVICES; d++ ) // foreach InputDevice
|
|
|
|
|
{
|
2003-10-07 05:59:58 +00:00
|
|
|
di.device = (InputDevice)d;
|
|
|
|
|
|
|
|
|
|
for( int b=0; b < NUM_DEVICE_BUTTONS[d]; b++ ) // foreach button
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2003-10-07 05:59:58 +00:00
|
|
|
di.button = b;
|
2003-09-03 21:49:11 +00:00
|
|
|
|
|
|
|
|
if( m_fSecsToForce[d][b] > 0 )
|
|
|
|
|
{
|
|
|
|
|
m_fSecsToForce[d][b] -= fDeltaTime;
|
|
|
|
|
if( m_fSecsToForce[d][b] <= 0 )
|
|
|
|
|
StopForcingKey( di );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !IsBeingPressed(di) )
|
2003-02-16 01:35:48 +00:00
|
|
|
continue;
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2003-02-16 01:35:48 +00:00
|
|
|
const float fOldHoldTime = m_fSecsHeld[d][b];
|
|
|
|
|
m_fSecsHeld[d][b] += fDeltaTime;
|
|
|
|
|
const float fNewHoldTime = m_fSecsHeld[d][b];
|
|
|
|
|
|
|
|
|
|
float fTimeBetweenRepeats;
|
|
|
|
|
InputEventType iet;
|
2003-11-25 21:46:30 +00:00
|
|
|
if( fOldHoldTime > g_fTimeBeforeSlow )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2003-11-25 21:46:30 +00:00
|
|
|
if( fOldHoldTime > g_fTimeBeforeFast )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2003-11-25 21:46:30 +00:00
|
|
|
fTimeBetweenRepeats = g_fTimeBetweenFast;
|
2003-02-16 01:35:48 +00:00
|
|
|
iet = IET_FAST_REPEAT;
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
2003-02-16 01:35:48 +00:00
|
|
|
else
|
|
|
|
|
{
|
2003-11-25 21:46:30 +00:00
|
|
|
fTimeBetweenRepeats = g_fTimeBetweenSlow;
|
2003-02-16 01:35:48 +00:00
|
|
|
iet = IET_SLOW_REPEAT;
|
2002-08-21 22:49:13 +00:00
|
|
|
}
|
2003-02-16 01:35:48 +00:00
|
|
|
if( int(fOldHoldTime/fTimeBetweenRepeats) != int(fNewHoldTime/fTimeBetweenRepeats) )
|
2003-07-14 06:21:12 +00:00
|
|
|
{
|
|
|
|
|
queue.push_back( InputEvent(di,iet) );
|
|
|
|
|
}
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-02-16 01:35:48 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool InputFilter::IsBeingPressed( DeviceInput di )
|
|
|
|
|
{
|
2003-09-03 21:49:11 +00:00
|
|
|
return m_BeingHeld[di.device][di.button] || m_BeingForced[di.device][di.button];
|
2003-02-16 01:35:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InputFilter::GetSecsHeld( DeviceInput di )
|
|
|
|
|
{
|
|
|
|
|
return m_fSecsHeld[di.device][di.button];
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-25 21:46:30 +00:00
|
|
|
void InputFilter::ResetKeyRepeat( DeviceInput di )
|
|
|
|
|
{
|
|
|
|
|
m_fSecsHeld[di.device][di.button] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-16 01:35:48 +00:00
|
|
|
void InputFilter::GetInputEvents( InputEventArray &array )
|
|
|
|
|
{
|
2003-07-26 21:58:48 +00:00
|
|
|
LockMut(*queuemutex);
|
2003-02-16 01:35:48 +00:00
|
|
|
array = queue;
|
|
|
|
|
queue.clear();
|
2002-07-31 19:40:40 +00:00
|
|
|
}
|