mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-02-17 01:45:41 +00:00
![Nik Henson](/assets/img/avatar_default.png)
- Fixed bug with mapping of multiple assignments. - Added new ! operator for input mappings, which lets the user specify that an input must not be active. - Added option to print info about input system (such as settings and detected keyboards, mice and joysticks) during input configuration. - Added new trigger input for lightgun games with a configurable option to automatically pull trigger when offscreen input is activated (this makes playing with the mouse easier as the gun can be reloaded with single mouse button, rather than having to press both buttons at the same time). - Added -xinput command line option that switches to using XInput API rather than DirectInput for XBox 360 controllers (this allows the XBox 360 controller's two triggers to be read independently which works better for driving games when they are mapped to accele rator and brake). - Added initial version of force feedback implementation to DirectInputSystem (this still needs work).
211 lines
6.3 KiB
C++
211 lines
6.3 KiB
C++
#include "Supermodel.h"
|
|
|
|
// All the input subclasses have been grouped together here as they are very simple classes
|
|
|
|
/*
|
|
* CSwitchInput
|
|
*/
|
|
CSwitchInput::CSwitchInput(const char *inputId, const char *inputLabel, unsigned inputGameFlags, const char *defaultMapping, UINT16 offVal, UINT16 onVal) :
|
|
CInput(inputId, inputLabel, INPUT_FLAGS_SWITCH, inputGameFlags, defaultMapping), m_offVal(offVal), m_onVal(onVal)
|
|
{
|
|
//
|
|
}
|
|
|
|
void CSwitchInput::Poll()
|
|
{
|
|
prevValue = value;
|
|
|
|
bool boolValue = !!value;
|
|
if (m_source != NULL && m_source->GetValueAsSwitch(boolValue))
|
|
value = (boolValue ? m_onVal : m_offVal);
|
|
else
|
|
value = m_offVal;
|
|
}
|
|
|
|
bool CSwitchInput::Pressed()
|
|
{
|
|
return prevValue == m_offVal && value == m_onVal;
|
|
}
|
|
|
|
bool CSwitchInput::Released()
|
|
{
|
|
return prevValue == m_onVal && value == m_offVal;
|
|
}
|
|
|
|
/*
|
|
* CAnalogInput
|
|
*/
|
|
CAnalogInput::CAnalogInput(const char *inputId, const char *inputLabel, unsigned inputGameFlags, const char *defaultMapping, UINT16 minVal, UINT16 maxVal) :
|
|
CInput(inputId, inputLabel, INPUT_FLAGS_ANALOG, inputGameFlags, defaultMapping, minVal), m_minVal(minVal), m_maxVal(maxVal)
|
|
{
|
|
//
|
|
}
|
|
|
|
void CAnalogInput::Poll()
|
|
{
|
|
prevValue = value;
|
|
|
|
if (m_source == NULL)
|
|
{
|
|
value = m_minVal;
|
|
return;
|
|
}
|
|
int intValue = value;
|
|
if (m_source->GetValueAsAnalog(intValue, m_minVal, m_minVal, m_maxVal))
|
|
value = intValue;
|
|
else
|
|
value = m_minVal;
|
|
}
|
|
|
|
bool CAnalogInput::HasValue()
|
|
{
|
|
return value > m_minVal;
|
|
}
|
|
|
|
double CAnalogInput::ValueAsFraction()
|
|
{
|
|
double frac = (double)(value - m_minVal)/(double)(m_maxVal - m_minVal);
|
|
return (frac >= 0.0 ? frac : -frac);
|
|
}
|
|
|
|
/*
|
|
* CAxisInput
|
|
*/
|
|
CAxisInput::CAxisInput(const char *inputId, const char *inputLabel, unsigned inputGameFlags, const char *defaultMapping,
|
|
CAnalogInput *negInput, CAnalogInput *posInput, UINT16 minVal, UINT16 offVal, UINT16 maxVal) :
|
|
CInput(inputId, inputLabel, INPUT_FLAGS_AXIS, inputGameFlags, defaultMapping, offVal), m_negInput(negInput), m_posInput(posInput),
|
|
m_minVal(minVal), m_offVal(offVal), m_maxVal(maxVal)
|
|
{
|
|
//
|
|
}
|
|
|
|
void CAxisInput::Poll()
|
|
{
|
|
prevValue = value;
|
|
|
|
// Try getting value from analog inputs that represent negative and positive range of the axis first and then try the default input source
|
|
int intValue = value;
|
|
if ((m_negInput != NULL && m_negInput->HasValue()) || (m_posInput != NULL && m_posInput->HasValue()))
|
|
{
|
|
if (m_maxVal > m_minVal)
|
|
{
|
|
value = m_offVal;
|
|
if (m_posInput != NULL) value += (int)(m_posInput->ValueAsFraction() * (double)(m_maxVal - m_offVal));
|
|
if (m_negInput != NULL) value -= (int)(m_negInput->ValueAsFraction() * (double)(m_offVal - m_minVal));
|
|
}
|
|
else
|
|
{
|
|
value = m_offVal;
|
|
if (m_posInput != NULL) value += (int)(m_posInput->ValueAsFraction() * (double)(m_offVal - m_maxVal));
|
|
if (m_negInput != NULL) value -= (int)(m_negInput->ValueAsFraction() * (double)(m_minVal - m_offVal));
|
|
}
|
|
}
|
|
else if (m_source != NULL && m_source->GetValueAsAnalog(intValue, m_minVal, m_offVal, m_maxVal))
|
|
value = intValue;
|
|
else
|
|
value = m_offVal;
|
|
}
|
|
|
|
bool CAxisInput::HasValue()
|
|
{
|
|
return value != m_offVal;
|
|
}
|
|
|
|
double CAxisInput::ValueAsFraction()
|
|
{
|
|
double frac = (double)(value - m_minVal)/(double)(m_maxVal - m_minVal);
|
|
return (frac >= 0.0 ? frac : -frac);
|
|
}
|
|
|
|
/*
|
|
* CGearShift4Input
|
|
*/
|
|
CGearShift4Input::CGearShift4Input(const char *inputId, const char *inputLabel, unsigned inputGameFlags,
|
|
CSwitchInput *shift1Input, CSwitchInput *shift2Input, CSwitchInput *shift3Input, CSwitchInput *shift4Input,
|
|
CSwitchInput *shiftUpInput, CSwitchInput *shiftDownInput) :
|
|
CInput(inputId, inputLabel, INPUT_FLAGS_VIRTUAL, inputGameFlags),
|
|
m_shift1Input(shift1Input), m_shift2Input(shift2Input), m_shift3Input(shift3Input), m_shift4Input(shift4Input),
|
|
m_shiftUpInput(shiftUpInput), m_shiftDownInput(shiftDownInput)
|
|
{
|
|
//
|
|
}
|
|
|
|
void CGearShift4Input::Poll()
|
|
{
|
|
prevValue = value;
|
|
|
|
// Neutral is when all gear buttons are released so shifting here is implemented as follows:
|
|
// Gears (values 1-4) are set by pressing a button (lower gears have priority) and "stick" until a shift to another gear or until the
|
|
// button is pressed again, at which point neutral (value 0) is assumed.
|
|
if (m_shift1Input->Pressed()) value = (value == 1 ? 0 : 1);
|
|
else if (m_shift2Input->Pressed()) value = (value == 2 ? 0 : 2);
|
|
else if (m_shift3Input->Pressed()) value = (value == 3 ? 0 : 3);
|
|
else if (m_shift4Input->Pressed()) value = (value == 4 ? 0 : 4);
|
|
|
|
// Also the shift up/down controls can increase/decrease the gears too
|
|
if (m_shiftUpInput->Pressed()) value = CInputSource::Clamp(value + 1, 0, 4);
|
|
else if (m_shiftDownInput->Pressed()) value = CInputSource::Clamp(value - 1, 0, 4);
|
|
}
|
|
|
|
CTriggerInput::CTriggerInput(const char *inputId, const char *inputLabel, unsigned inputGameFlags,
|
|
CSwitchInput *triggerInput, CSwitchInput *offscreenInput, UINT16 offVal, UINT16 onVal) :
|
|
CInput(inputId, inputLabel, INPUT_FLAGS_VIRTUAL, inputGameFlags),
|
|
m_triggerInput(triggerInput), m_offscreenInput(offscreenInput), m_autoTrigger(false), m_offscreenCount(0), m_offVal(offVal), m_onVal(onVal)
|
|
{
|
|
//
|
|
}
|
|
|
|
void CTriggerInput::ReadFromINIFile(CINIFile *ini, const char *section)
|
|
{
|
|
CInput::ReadFromINIFile(ini, section);
|
|
|
|
string key("Input");
|
|
key.append(id);
|
|
unsigned int autoTrigger;
|
|
if (ini->Get(section, key, autoTrigger) == OKAY)
|
|
m_autoTrigger = !!autoTrigger;
|
|
}
|
|
|
|
void CTriggerInput::WriteToINIFile(CINIFile *ini, const char *section)
|
|
{
|
|
CInput::WriteToINIFile(ini, section);
|
|
|
|
string key("Input");
|
|
key.append(id);
|
|
ini->Set(section, key, (unsigned)m_autoTrigger);
|
|
}
|
|
|
|
void CTriggerInput::Poll()
|
|
{
|
|
prevValue = value;
|
|
|
|
// See if auto-trigger on reload is enabled
|
|
if (m_autoTrigger)
|
|
{
|
|
// If so, when offscreen activated simulate triggered being pressed a short while afterwards
|
|
if (m_offscreenCount > 0)
|
|
{
|
|
value = m_offscreenCount < 5;
|
|
offscreenValue = m_onVal;
|
|
m_offscreenCount--;
|
|
}
|
|
else
|
|
{
|
|
value = m_triggerInput->value;
|
|
if (m_offscreenInput->Pressed())
|
|
{
|
|
offscreenValue = m_onVal;
|
|
m_offscreenCount = 10;
|
|
}
|
|
else
|
|
offscreenValue = m_offVal;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Otherwise if disabled, just take raw values from inputs
|
|
value = m_triggerInput->value;
|
|
offscreenValue = m_offscreenInput->value;
|
|
}
|
|
}
|