The volume keys wanted a partner, and the bass trim could not be one as it stood: it scaled the sample data as it loaded, so by the time anyone pressed a key the audio was already sitting in OpenAL buffers and nothing short of a restart would move it. So the trim is now a per-zone gain applied in the mix instead. Each buffer's depth - how much of the low band it occupies - is still worked out once at load from its playback rate, but the trim itself is read every frame, which is what lets Home and End move it while sounds are playing. It is the better form regardless: no rewriting of sample data, and no quantisation on top of audio that has already been through one gain stage. Home raises, End lowers, in steps of 0.05, and the setting is written to bass.cfg beside the exe exactly as the volume writes volume.cfg. Together with PageUp and PageDown that is the amplifier and the crossover the cabinets had in hardware and a desktop does not. Builds clean, runs, and neither knob fires unprompted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2682 lines
66 KiB
C++
2682 lines
66 KiB
C++
#include "mungal4.h"
|
|
#pragma hdrstop
|
|
|
|
#include "l4padrio.h"
|
|
|
|
#include "l4ctrl.h"
|
|
#include "l4keybd.h"
|
|
#include "l4app.h"
|
|
#include "l4audrnd.h" // RPAudioMasterVolumeStep, for the PgUp/PgDn keys
|
|
#include "l4audres.h" // RPBassTrimStep, for the Home/End keys
|
|
#include "l4dinput.h"
|
|
#include "..\munga\appmgr.h"
|
|
#include "dxutils.h"
|
|
|
|
// #define LOCAL_TEST
|
|
|
|
#if defined(LOCAL_TEST)
|
|
# define Test_Tell(n) Tell(n << std::flush);
|
|
#else
|
|
# define Test_Tell(n)
|
|
#endif
|
|
|
|
static const char *initFileName = "JOYSTICK.INI";
|
|
#define RIO_SPOOL_SIZE 12000
|
|
|
|
//###########################################################################
|
|
//########################### Button type table #############################
|
|
//###########################################################################
|
|
#define DARKBTN (char) 0
|
|
#define AUTOBTN (char) 1
|
|
#define MAPBTN (char) 2
|
|
|
|
#define DI_TRIGGER 0
|
|
#define DI_THUMB1 2
|
|
#define DI_THUMB2 1
|
|
#define DI_THUMB3 3
|
|
#define DI_THROTTLE 10
|
|
|
|
static char
|
|
buttonType[LBE4ControlsManager::ButtonCount] =
|
|
{
|
|
AUTOBTN, // ButtonAuxLowerLeft8=0x00
|
|
AUTOBTN, // ButtonAuxLowerLeft7
|
|
AUTOBTN, // ButtonAuxLowerLeft6,
|
|
AUTOBTN, // ButtonAuxLowerLeft5,
|
|
AUTOBTN, // ButtonAuxLowerLeft4,
|
|
AUTOBTN, // ButtonAuxLowerLeft3,
|
|
AUTOBTN, // ButtonAuxLowerLeft2,
|
|
AUTOBTN, // ButtonAuxLowerLeft1,
|
|
|
|
AUTOBTN, // ButtonAuxLowerRight8=0x08
|
|
AUTOBTN, // ButtonAuxLowerRight7,
|
|
AUTOBTN, // ButtonAuxLowerRight6,
|
|
AUTOBTN, // ButtonAuxLowerRight5,
|
|
AUTOBTN, // ButtonAuxLowerRight4,
|
|
AUTOBTN, // ButtonAuxLowerRight3,
|
|
AUTOBTN, // ButtonAuxLowerRight2,
|
|
AUTOBTN, // ButtonAuxLowerRight1,
|
|
|
|
AUTOBTN, // ButtonSecondary1=0x10
|
|
AUTOBTN, // ButtonSecondary2,
|
|
AUTOBTN, // ButtonSecondary3,
|
|
AUTOBTN, // ButtonSecondary4,
|
|
AUTOBTN, // ButtonSecondary5,
|
|
AUTOBTN, // ButtonSecondary6,
|
|
DARKBTN, //
|
|
DARKBTN, //
|
|
AUTOBTN, // ButtonSecondary7=0x18
|
|
AUTOBTN, // ButtonSecondary8,
|
|
AUTOBTN, // ButtonSecondary9,
|
|
AUTOBTN, // ButtonSecondary10,
|
|
AUTOBTN, // ButtonSecondary11,
|
|
AUTOBTN, // ButtonSecondary12,
|
|
DARKBTN, //
|
|
DARKBTN, //
|
|
|
|
AUTOBTN, // ButtonAuxUpperCenter8=0x20
|
|
AUTOBTN, // ButtonAuxUpperCenter7,
|
|
AUTOBTN, // ButtonAuxUpperCenter6,
|
|
AUTOBTN, // ButtonAuxUpperCenter5,
|
|
AUTOBTN, // ButtonAuxUpperCenter4,
|
|
AUTOBTN, // ButtonAuxUpperCenter3,
|
|
AUTOBTN, // ButtonAuxUpperCenter2,
|
|
AUTOBTN, // ButtonAuxUpperCenter1,
|
|
|
|
AUTOBTN, // ButtonAuxUpperLeft8=0x28
|
|
AUTOBTN, // ButtonAuxUpperLeft7,
|
|
AUTOBTN, // ButtonAuxUpperLeft6,
|
|
AUTOBTN, // ButtonAuxUpperLeft5,
|
|
AUTOBTN, // ButtonAuxUpperLeft4,
|
|
AUTOBTN, // ButtonAuxUpperLeft3,
|
|
AUTOBTN, // ButtonAuxUpperLeft2,
|
|
AUTOBTN, // ButtonAuxUpperLeft1,
|
|
|
|
AUTOBTN, // ButtonAuxUpperRight8=0x30
|
|
AUTOBTN, // ButtonAuxUpperRight7,
|
|
AUTOBTN, // ButtonAuxUpperRight6,
|
|
AUTOBTN, // ButtonAuxUpperRight5,
|
|
AUTOBTN, // ButtonAuxUpperRight4,
|
|
AUTOBTN, // ButtonAuxUpperRight3,
|
|
AUTOBTN, // ButtonAuxUpperRight2,
|
|
AUTOBTN, // ButtonAuxUpperRight1,
|
|
|
|
AUTOBTN, // ButtonPanic=0x38,
|
|
DARKBTN, //
|
|
DARKBTN, //
|
|
DARKBTN, //
|
|
DARKBTN, // ButtonDoor=0x3C,
|
|
DARKBTN, //
|
|
DARKBTN, //
|
|
|
|
DARKBTN, // ButtonThrottle1=0x3F,
|
|
MAPBTN, // ButtonJoystickTrigger=0x40
|
|
MAPBTN, // ButtonJoystickHatDown=0x41
|
|
MAPBTN, // ButtonJoystickHatUp=0x42
|
|
MAPBTN, // ButtonJoystickHatRight=0x43
|
|
MAPBTN, // ButtonJoystickHatLeft=0x44
|
|
MAPBTN, // ButtonJoystickPinky=0x45
|
|
MAPBTN, // ButtonJoystickThumbLow=0x46
|
|
MAPBTN // ButtonJoystickThumbHigh=0x47
|
|
};
|
|
|
|
//###########################################################################
|
|
//############################ Joystick classes #############################
|
|
//###########################################################################
|
|
Joystick::Joystick()
|
|
{
|
|
NotationFile
|
|
init(initFileName);
|
|
|
|
channel[0] = new FilterChannel(
|
|
&init,
|
|
FilterChannel::joystickXName,
|
|
10,20,30 // bogus values in case file didn't previously exist
|
|
);
|
|
Check(channel[0]);
|
|
|
|
channel[1] = new FilterChannel(
|
|
&init,
|
|
FilterChannel::joystickYName,
|
|
10,20,30 // bogus values in case file didn't previously exist
|
|
);
|
|
Check(channel[1]);
|
|
|
|
ButtonReleased = Joystick::NoButton;
|
|
ButtonPressed = Joystick::NoButton;
|
|
Check_Fpu();
|
|
}
|
|
|
|
Joystick::~Joystick()
|
|
{
|
|
Check(this);
|
|
|
|
NotationFile
|
|
init(initFileName);
|
|
|
|
//-------------------------------------------
|
|
// Save DOS timestamp
|
|
//-------------------------------------------
|
|
time_t
|
|
dos_time;
|
|
time(&dos_time);
|
|
init.SetEntry("operator", "time", ctime(&dos_time));
|
|
|
|
for(int i=0; i<2; ++i)
|
|
{
|
|
Check(channel[i]);
|
|
delete channel[i];
|
|
channel[i] = NULL;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
Joystick::BeginAlignment()
|
|
{
|
|
Check(this);
|
|
for(int i=0; i<2; ++i)
|
|
{
|
|
Check(channel[i]);
|
|
channel[i]->BeginAlignment();
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
Joystick::EndAlignment()
|
|
{
|
|
Check(this);
|
|
//------------------------------------------------------------
|
|
// If channel was never adjusted, synthesize reasonable values
|
|
//------------------------------------------------------------
|
|
NotationFile
|
|
init(initFileName);
|
|
EndAndSaveAlignment(&init);
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
Joystick::EndAndSaveAlignment(NotationFile *init_file)
|
|
{
|
|
Check(this);
|
|
Check(init_file);
|
|
for(int i=0; i<2; ++i)
|
|
{
|
|
Check(channel[i]);
|
|
channel[i]->EndAlignment(init_file);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
Joystick::Update()
|
|
{
|
|
Fail("Joystick::Update should not be called!\n");
|
|
}
|
|
|
|
void
|
|
Joystick::SetDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
for(int i=0; i<2; ++i)
|
|
{
|
|
Check(channel[i]);
|
|
channel[i]->SetDeadBand(dead_band);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
OrdinaryJoystick::OrdinaryJoystick()
|
|
{
|
|
//STUBBED: JOYSTICK RB 1/14/07
|
|
//PC_Joystick_Mask = PCJ_Standard_Mask;
|
|
//ExtendedValue.x = (Scalar) 0;
|
|
//ExtendedValue.y = (Scalar) 0;
|
|
//Check_Fpu();
|
|
}
|
|
|
|
OrdinaryJoystick::~OrdinaryJoystick()
|
|
{
|
|
Check_Fpu();
|
|
}
|
|
|
|
void OrdinaryJoystick::Update()
|
|
{
|
|
//STUBBED: JOYSTICK RB 1/14/07
|
|
//int newButtons, changedButtons;
|
|
|
|
//Check(this);
|
|
////
|
|
////---------------------------------------------------
|
|
//// Update analog values
|
|
////---------------------------------------------------
|
|
////
|
|
//PC_Joystick_Update();
|
|
//Check(channel[0]);
|
|
//Value.x = channel[0]->Update(PC_Joystick1_Raw_X);
|
|
//Check(channel[1]);
|
|
//Value.y = channel[1]->Update(PC_Joystick1_Raw_Y);
|
|
////
|
|
////---------------------------------------------------
|
|
//// Handle button changes
|
|
////---------------------------------------------------
|
|
////
|
|
//newButtons = (int) PC_Joystick_Buttons;
|
|
//changedButtons = newButtons ^ oldButtons;
|
|
|
|
//ButtonPressed = Joystick::NoButton;
|
|
//ButtonReleased = Joystick::NoButton;
|
|
|
|
//if (changedButtons)
|
|
//{
|
|
// if (changedButtons & PCJ_Standard_Button1)
|
|
// {
|
|
// if (newButtons & PCJ_Standard_Button1)
|
|
// {
|
|
// ButtonPressed |= Joystick::Trigger;
|
|
// }
|
|
// else
|
|
// {
|
|
// ButtonReleased |= Joystick::Trigger;
|
|
// }
|
|
// }
|
|
// if (changedButtons & PCJ_Standard_Button2)
|
|
// {
|
|
// if (newButtons & PCJ_Standard_Button2)
|
|
// {
|
|
// ButtonPressed |= Joystick::Thumb3;
|
|
// }
|
|
// else
|
|
// {
|
|
// ButtonReleased |= Joystick::Thumb3;
|
|
// }
|
|
// }
|
|
//}
|
|
//oldButtons = newButtons;
|
|
//Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
Joystick::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
FlightStickPro::FlightStickPro()
|
|
{
|
|
//STUBBED: JOYSTICK RB 1/14/07
|
|
//NotationFile
|
|
// init(initFileName);
|
|
|
|
//throttle = new FilterChannel(
|
|
// &init,
|
|
// FilterChannel::throttleName,
|
|
// 10,30 // bogus values in case file doesn't exist
|
|
//);
|
|
|
|
//Check(throttle);
|
|
|
|
//PC_Joystick_Mask = PCJ_FSP_Mask;
|
|
//ExtendedValue.x = (Scalar) 0;
|
|
//Check_Fpu();
|
|
}
|
|
|
|
FlightStickPro::~FlightStickPro()
|
|
{
|
|
Check(this);
|
|
|
|
NotationFile
|
|
init(initFileName);
|
|
//-------------------------------------------
|
|
// Save DOS timestamp
|
|
//-------------------------------------------
|
|
time_t
|
|
dos_time;
|
|
time(&dos_time);
|
|
init.SetEntry("operator", "time", ctime(&dos_time));
|
|
|
|
Check(throttle);
|
|
delete throttle;
|
|
throttle = NULL;
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void FlightStickPro::Update()
|
|
{
|
|
//STUBBED: JOYSTICK RB 1/14/07
|
|
//int newButtons;
|
|
|
|
//Check(this);
|
|
////
|
|
////---------------------------------------------------
|
|
//// Update analog values
|
|
////---------------------------------------------------
|
|
////
|
|
//PC_Joystick_Update();
|
|
//Check(channel[0]);
|
|
//Value.x = channel[0]->Update(PC_Joystick1_Raw_X);
|
|
//Check(channel[1]);
|
|
//Value.y = channel[1]->Update(PC_Joystick1_Raw_Y);
|
|
|
|
//// Note inverted direction (below) for throttle
|
|
|
|
//Check(throttle);
|
|
//ExtendedValue.y = 1.0 - throttle->Update(PC_Joystick2_Raw_Y);
|
|
////
|
|
////---------------------------------------------------
|
|
//// Handle button changes
|
|
////---------------------------------------------------
|
|
////
|
|
//newButtons = int (PC_Joystick_Buttons);
|
|
|
|
//ButtonPressed = Joystick::NoButton;
|
|
//ButtonReleased = Joystick::NoButton;
|
|
|
|
//if (newButtons != oldButtons)
|
|
//{
|
|
// switch(oldButtons)
|
|
// {
|
|
// case PCJ_FSP_Up: ButtonReleased = Joystick::HatUp; break;
|
|
// case PCJ_FSP_Down: ButtonReleased = Joystick::HatDown; break;
|
|
// case PCJ_FSP_Left: ButtonReleased = Joystick::HatLeft; break;
|
|
// case PCJ_FSP_Right: ButtonReleased = Joystick::HatRight; break;
|
|
// case PCJ_FSP_Trigger: ButtonReleased = Joystick::Trigger; break;
|
|
// case PCJ_FSP_LButton: ButtonReleased = Joystick::Thumb3; break;
|
|
// case PCJ_FSP_RButton: ButtonReleased = Joystick::Thumb1; break;
|
|
// case PCJ_FSP_CButton: ButtonReleased = Joystick::Thumb2; break;
|
|
// }
|
|
// switch(newButtons)
|
|
// {
|
|
// case PCJ_FSP_Up: ButtonPressed = Joystick::HatUp; break;
|
|
// case PCJ_FSP_Down: ButtonPressed = Joystick::HatDown; break;
|
|
// case PCJ_FSP_Left: ButtonPressed = Joystick::HatLeft; break;
|
|
// case PCJ_FSP_Right: ButtonPressed = Joystick::HatRight; break;
|
|
// case PCJ_FSP_Trigger: ButtonPressed = Joystick::Trigger; break;
|
|
// case PCJ_FSP_LButton: ButtonPressed = Joystick::Thumb3; break;
|
|
// case PCJ_FSP_RButton: ButtonPressed = Joystick::Thumb1; break;
|
|
// case PCJ_FSP_CButton: ButtonPressed = Joystick::Thumb2; break;
|
|
// }
|
|
// oldButtons = newButtons;
|
|
//}
|
|
//Check_Fpu();
|
|
}
|
|
|
|
void
|
|
FlightStickPro::BeginAlignment()
|
|
{
|
|
Check(this);
|
|
Check(throttle);
|
|
throttle->BeginAlignment();
|
|
|
|
Joystick::BeginAlignment();
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
FlightStickPro::EndAlignment()
|
|
{
|
|
Check(this);
|
|
|
|
NotationFile
|
|
init(initFileName);
|
|
|
|
Check(throttle);
|
|
throttle->EndAlignment(&init);
|
|
|
|
Joystick::EndAndSaveAlignment(&init);
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext)
|
|
{
|
|
ThrustMaster *joystick = (ThrustMaster*)pContext;
|
|
if (FAILED(joystick->mDI->CreateDevice(pdidInstance->guidInstance, &joystick->mJoystick, NULL)))
|
|
return DIENUM_CONTINUE;
|
|
|
|
return DIENUM_STOP;
|
|
}
|
|
|
|
BOOL CALLBACK EnumAxesCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
|
|
{
|
|
ThrustMaster *joystick = (ThrustMaster*)pvRef;
|
|
DIPROPRANGE diprg;
|
|
diprg.diph.dwSize = sizeof(DIPROPRANGE);
|
|
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
diprg.diph.dwHow = DIPH_BYID;
|
|
diprg.diph.dwObj = lpddoi->dwType;
|
|
diprg.lMax = diprg.lMax = 0;
|
|
|
|
if (lpddoi->guidType == GUID_XAxis)
|
|
{
|
|
if (SUCCEEDED(joystick->mJoystick->GetProperty(DIPROP_RANGE, &diprg.diph)))
|
|
{
|
|
joystick->xAxisMin = diprg.lMin;
|
|
joystick->xAxisMax = diprg.lMax;
|
|
}
|
|
}
|
|
else if (lpddoi->guidType == GUID_YAxis)
|
|
{
|
|
if (SUCCEEDED(joystick->mJoystick->GetProperty(DIPROP_RANGE, &diprg.diph)))
|
|
{
|
|
joystick->yAxisMin = diprg.lMin;
|
|
joystick->yAxisMax = diprg.lMax;
|
|
}
|
|
}
|
|
else if (lpddoi->guidType == GUID_ZAxis)
|
|
{
|
|
if (SUCCEEDED(joystick->mJoystick->GetProperty(DIPROP_RANGE, &diprg.diph)))
|
|
{
|
|
joystick->zAxisMin = diprg.lMin;
|
|
joystick->zAxisMax = diprg.lMax;
|
|
}
|
|
}
|
|
else if (lpddoi->guidType == GUID_RxAxis)
|
|
{
|
|
}
|
|
else if (lpddoi->guidType == GUID_RyAxis)
|
|
{
|
|
}
|
|
else if (lpddoi->guidType == GUID_RzAxis)
|
|
{
|
|
if (SUCCEEDED(joystick->mJoystick->GetProperty(DIPROP_RANGE, &diprg.diph)))
|
|
{
|
|
joystick->rzAxisMin = diprg.lMin;
|
|
joystick->rzAxisMax = diprg.lMax;
|
|
}
|
|
}
|
|
else if (lpddoi->guidType == GUID_Slider)
|
|
{
|
|
if (SUCCEEDED(joystick->mJoystick->GetProperty(DIPROP_RANGE, &diprg.diph)))
|
|
{
|
|
joystick->zAxisMin = diprg.lMin;
|
|
joystick->zAxisMax = diprg.lMax;
|
|
}
|
|
}
|
|
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
ThrustMaster::ThrustMaster(HINSTANCE hInstance, HWND hWnd)
|
|
{
|
|
//STUBBED: JOYSTICK RB 1/14/07
|
|
ExtendedValue.x = (Scalar) 0;
|
|
ExtendedValue.y = (Scalar) 0;
|
|
hatMax = 0;
|
|
prevHatState = 0;
|
|
|
|
mDI = NULL;
|
|
mJoystick = NULL;
|
|
|
|
if (SUCCEEDED(DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&mDI, NULL)))
|
|
{
|
|
mDI->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, this, DIEDFL_ATTACHEDONLY);
|
|
if (mJoystick)
|
|
if (SUCCEEDED(mJoystick->SetDataFormat(&c_dfDIJoystick2)))
|
|
if (SUCCEEDED(mJoystick->SetCooperativeLevel(hWnd, DISCL_EXCLUSIVE | DISCL_BACKGROUND)))
|
|
if (SUCCEEDED(mJoystick->EnumObjects(EnumAxesCallback, this, DIDFT_AXIS)))
|
|
return;
|
|
}
|
|
|
|
if (mDI)
|
|
{
|
|
mDI->Release();
|
|
mDI = NULL;
|
|
}
|
|
if (mJoystick)
|
|
{
|
|
mJoystick->Release();
|
|
mJoystick = NULL;
|
|
}
|
|
}
|
|
|
|
ThrustMaster::~ThrustMaster()
|
|
{
|
|
Check_Fpu();
|
|
}
|
|
|
|
bool ThrustMaster::Poll()
|
|
{
|
|
HRESULT hr;
|
|
if (mJoystick)
|
|
{
|
|
V( mJoystick->Poll() );
|
|
if (FAILED(hr))
|
|
{
|
|
V( mJoystick->Acquire() );
|
|
while (hr == DIERR_INPUTLOST)
|
|
V( mJoystick->Acquire() );
|
|
return false;
|
|
}
|
|
|
|
V( mJoystick->GetDeviceState(sizeof(DIJOYSTATE2), &mJoystate) );
|
|
if (FAILED(hr))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ThrustMaster::Update()
|
|
{
|
|
if (!Poll())
|
|
return;
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Update analog values
|
|
//---------------------------------------------------
|
|
//
|
|
Value.x = ((Scalar)(mJoystate.lX - xAxisMin) / (Scalar)(xAxisMax - xAxisMin)) * 2.0f - 1.0f;
|
|
Value.y = ((Scalar)(mJoystate.lY - yAxisMin) / (Scalar)(yAxisMax - yAxisMin)) * 2.0f - 1.0f;
|
|
LONG z = (mJoystate.lZ == 0 ? mJoystate.rglSlider[0] : mJoystate.lZ);
|
|
ExtendedValue.y = 1.0f - (Scalar)(z - zAxisMin) / (Scalar)(zAxisMax - zAxisMin);
|
|
// full left rotation = 0, center rotation = 1/2 range, full right = full range
|
|
LONG rot = (Scalar)(mJoystate.lRz - rzAxisMin);
|
|
Scalar half = (Scalar)(rzAxisMax - rzAxisMin) / 2.0f;
|
|
Rotation.x = (Scalar)0;
|
|
Rotation.y = (Scalar)0;
|
|
if (rot <= half)
|
|
Rotation.x = ((half - rot) / half) * 470.0;
|
|
else
|
|
Rotation.y = ((rot - half) / half) * 470.0;
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Handle button changes
|
|
//---------------------------------------------------
|
|
//
|
|
ButtonPressed = Joystick::NoButton;
|
|
ButtonReleased = Joystick::NoButton;
|
|
|
|
int newButtons = 0;
|
|
if (mJoystate.rgbButtons[DI_TRIGGER])
|
|
newButtons |= Joystick::Trigger;
|
|
if (mJoystate.rgbButtons[DI_THUMB1])
|
|
newButtons |= Joystick::Thumb1;
|
|
if (mJoystate.rgbButtons[DI_THUMB2])
|
|
newButtons |= Joystick::Thumb2;
|
|
if (mJoystate.rgbButtons[DI_THUMB3])
|
|
newButtons |= Joystick::Thumb3;
|
|
if (mJoystate.rgbButtons[DI_THROTTLE])
|
|
newButtons |= Joystick::Throttle;
|
|
if (mJoystate.rgdwPOV[0] == 0)
|
|
newButtons |= Joystick::HatUp;
|
|
if (mJoystate.rgdwPOV[0] == 9000)
|
|
newButtons |= Joystick::HatRight;
|
|
if (mJoystate.rgdwPOV[0] == 18000)
|
|
newButtons |= Joystick::HatDown;
|
|
if (mJoystate.rgdwPOV[0] == 27000)
|
|
newButtons |= Joystick::HatLeft;
|
|
|
|
ButtonPressed = (oldButtons ^ newButtons) & newButtons;
|
|
ButtonReleased = (oldButtons ^ newButtons) & oldButtons;
|
|
oldButtons = newButtons;
|
|
}
|
|
|
|
|
|
//#########################################################################
|
|
//########################## LBE4ControlsManager ##########################
|
|
//#########################################################################
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Class derivation
|
|
//---------------------------------------------------------------------------
|
|
Derivation* LBE4ControlsManager::GetClassDerivations()
|
|
{
|
|
static Derivation classDerivations(ControlsManager::GetClassDerivations(), "L4ControlsManager");
|
|
return &classDerivations;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Message support
|
|
//---------------------------------------------------------------------------
|
|
//const Receiver::HandlerEntry
|
|
// LBE4ControlsManager::MessageHandlerEntries[]=
|
|
//{
|
|
// MESSAGE_ENTRY(LBE4ControlsManager,BeginCalibration),
|
|
// MESSAGE_ENTRY(LBE4ControlsManager,EndCalibration)
|
|
//};
|
|
//
|
|
//Receiver::MessageHandlerSet
|
|
// LBE4ControlsManager::MessageHandlers(
|
|
// ELEMENTS(LBE4ControlsManager::MessageHandlerEntries),
|
|
// LBE4ControlsManager::MessageHandlerEntries,
|
|
// ControlsManager::MessageHandlers
|
|
// );
|
|
//---------------------------------------------------------------------------
|
|
// Shared data
|
|
//---------------------------------------------------------------------------
|
|
LBE4ControlsManager::SharedData
|
|
LBE4ControlsManager::DefaultData(
|
|
LBE4ControlsManager::GetClassDerivations(),
|
|
LBE4ControlsManager::GetMessageHandlers()
|
|
);
|
|
//
|
|
//############################################################################
|
|
// LBE4ControlsManager
|
|
//
|
|
// Creator method
|
|
//----------------------------------------------------------------------------
|
|
// Enter: virtualDataPtr
|
|
//############################################################################
|
|
//
|
|
LBE4ControlsManager::LBE4ControlsManager():
|
|
ControlsManager(L4ControlsManagerClassID, DefaultData)
|
|
{
|
|
Check_Pointer(this);
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// configure
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
flags.mouseExists = 0;
|
|
flags.keyboardExists = 0;
|
|
flags.joystickExists = 0;
|
|
flags.RIOExists = 0;
|
|
|
|
virtualJoystickX = 0;
|
|
virtualJoystickY = 0;
|
|
|
|
lastJoystickUpdate = 0.0f;
|
|
joystickType = LBE4ControlsManager::none;
|
|
|
|
mousePointer = NULL;
|
|
joystickPointer = NULL;
|
|
rioPointer = NULL;
|
|
lastRioRequest = 0L;
|
|
primaryControlType = LBE4ControlsManager::None;
|
|
|
|
char *controlString = getenv("L4CONTROLS");
|
|
|
|
if (controlString != NULL)
|
|
{
|
|
//
|
|
//-------------------------------------------------
|
|
// parse environment variable, build configuration
|
|
//-------------------------------------------------
|
|
//
|
|
char
|
|
temp[128];
|
|
char
|
|
*dest;
|
|
char
|
|
c;
|
|
int
|
|
noMore(0);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Get the next token
|
|
// Can't use strtok(), because RIO::RIO uses it,
|
|
// and it's not re-entrant.
|
|
//
|
|
|
|
dest = temp;
|
|
if (noMore)
|
|
{
|
|
*dest = '\0';
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
switch(c=*controlString++)
|
|
{
|
|
case '\0':
|
|
case '\n':
|
|
noMore = 1;
|
|
// deliberately falls through into next case
|
|
|
|
case ',':
|
|
case ';':
|
|
c = '\0';
|
|
// deliberately falls through into default case
|
|
|
|
default:
|
|
*dest++=c;
|
|
break;
|
|
}
|
|
}
|
|
while (c != '\0');
|
|
}
|
|
|
|
//Win32 Serial support: ADB 06/30/07
|
|
if(strncmp(temp, "RIO", 3) == 0)
|
|
{
|
|
if(strncmp(temp, "RIO:COM", 7) == 0)
|
|
{
|
|
int l = strlen(temp+4) + 5;
|
|
char* comm = new char[l];
|
|
strcpy(comm, "\\\\.\\");
|
|
strcpy(comm+4, temp+4);
|
|
rioPointer = new RIO(comm);//temp + 4);
|
|
Check(rioPointer);
|
|
Register_Object(rioPointer);
|
|
flags.RIOExists = 1;
|
|
primaryControlType = LBE4ControlsManager::PrimaryRIO;
|
|
delete comm;
|
|
}
|
|
else
|
|
{
|
|
rioPointer = new RIO("COM1");
|
|
Check(rioPointer);
|
|
Register_Object(rioPointer);
|
|
flags.RIOExists = 1;
|
|
primaryControlType = LBE4ControlsManager::PrimaryRIO;
|
|
}
|
|
}
|
|
else if (strcmpi(temp, "KEYBOARD") == 0)
|
|
{
|
|
flags.keyboardExists = 1;
|
|
}
|
|
else if (strcmpi(temp, "MOUSE") == 0)
|
|
{
|
|
if (!flags.mouseExists)
|
|
{
|
|
flags.mouseExists = 1;
|
|
mousePointer = new Mouse;
|
|
Check(mousePointer);
|
|
Register_Object(mousePointer);
|
|
if (mousePointer->Errors)
|
|
{
|
|
Unregister_Object(mousePointer);
|
|
delete mousePointer;
|
|
mousePointer = NULL;
|
|
flags.mouseExists = 0;
|
|
} else
|
|
{
|
|
primaryControlType = LBE4ControlsManager::PrimaryThrustMaster;
|
|
}
|
|
}
|
|
}
|
|
else if (strcmpi(temp, "JOYSTICK") == 0)
|
|
{
|
|
flags.joystickExists = 1;
|
|
joystickType = LBE4ControlsManager::ordinary;
|
|
joystickPointer = new OrdinaryJoystick();
|
|
Register_Object(joystickPointer);
|
|
primaryControlType = LBE4ControlsManager::PrimaryGenericJoystick;
|
|
}
|
|
else if (strcmpi(temp, "FLIGHTSTICKPRO") == 0)
|
|
{
|
|
flags.joystickExists = 1;
|
|
joystickType = LBE4ControlsManager::flightstickPro;
|
|
joystickPointer = new FlightStickPro();
|
|
Register_Object(joystickPointer);
|
|
primaryControlType = LBE4ControlsManager::PrimaryFlightStickPro;
|
|
}
|
|
else if (strcmpi(temp, "THRUSTMASTER") == 0)
|
|
{
|
|
flags.joystickExists = 1;
|
|
joystickType = LBE4ControlsManager::thrustMaster;
|
|
joystickPointer = new ThrustMaster(ApplicationManager::GetCurrentManager()->GetHInstance(), ApplicationManager::GetCurrentManager()->GetHWnd());
|
|
Register_Object(joystickPointer);
|
|
primaryControlType = LBE4ControlsManager::PrimaryThrustMaster;
|
|
}
|
|
else if (strcmpi(temp, "DIJOYSTICK") == 0)
|
|
{
|
|
joystickPointer = new DIJoystick(ApplicationManager::GetCurrentManager()->GetHInstance(), ApplicationManager::GetCurrentManager()->GetHWnd());
|
|
if (((DIJoystick*)joystickPointer)->IsValid())
|
|
{
|
|
flags.joystickExists = 1;
|
|
joystickType = LBE4ControlsManager::directInputJoystick;
|
|
Register_Object(joystickPointer);
|
|
primaryControlType = LBE4ControlsManager::PrimaryThrustMaster;
|
|
}
|
|
else
|
|
{
|
|
delete joystickPointer;
|
|
joystickPointer = NULL;
|
|
}
|
|
}
|
|
else if (strcmpi(temp, "PAD") == 0)
|
|
{
|
|
//------------------------------------------------------
|
|
// Cockpit-less play: PadRIO speaks the RIO control
|
|
// surface from an XInput pad + the PC keyboard, so the
|
|
// full RIO mapper/lamp/button path runs unchanged.
|
|
//------------------------------------------------------
|
|
rioPointer = new PadRIO();
|
|
Check(rioPointer);
|
|
Register_Object(rioPointer);
|
|
flags.RIOExists = 1;
|
|
primaryControlType = LBE4ControlsManager::PrimaryRIO;
|
|
}
|
|
}
|
|
while (temp[0] != '\0');
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// Clear all lamps (and reset analog I/O)
|
|
//--------------------------------------------------
|
|
if (rioPointer != NULL)
|
|
{
|
|
Check(rioPointer);
|
|
rioPointer->GeneralReset();
|
|
}
|
|
//--------------------------------------------------
|
|
// Get mode mask for updating
|
|
//--------------------------------------------------
|
|
Check(application);
|
|
Check(application->GetModeManager());
|
|
ModeMask
|
|
mode_mask = application->GetModeManager()->GetModeMask();
|
|
//--------------------------------------------------
|
|
// Initialize scalar group
|
|
//--------------------------------------------------
|
|
{
|
|
int
|
|
i;
|
|
ControlsScalar
|
|
initial_scalar = 0.0;
|
|
|
|
for(i=0; i<ScalarCount; ++i)
|
|
{
|
|
scalarGroup[i].ForceUpdate(&initial_scalar, mode_mask);
|
|
}
|
|
}
|
|
//--------------------------------------------------
|
|
// Initialize joystick group
|
|
//--------------------------------------------------
|
|
{
|
|
int
|
|
i;
|
|
ControlsJoystick
|
|
initial_stick;
|
|
|
|
initial_stick.x = 0.0;
|
|
initial_stick.y = 0.0;
|
|
|
|
for(i=0; i<JoystickCount; ++i)
|
|
{
|
|
joystickGroup[i].ForceUpdate(&initial_stick, mode_mask);
|
|
}
|
|
}
|
|
//--------------------------------------------------
|
|
// Initialize keyboard group
|
|
//--------------------------------------------------
|
|
{
|
|
int
|
|
i;
|
|
ControlsKey
|
|
initial_key = 0;
|
|
|
|
for(i=0; i<KeyboardCount; ++i)
|
|
{
|
|
keyboardGroup[i].ForceUpdate(&initial_key, mode_mask);
|
|
}
|
|
}
|
|
//--------------------------------------------------
|
|
// Initialize button control groups
|
|
//--------------------------------------------------
|
|
{
|
|
int
|
|
i;
|
|
ControlsButton
|
|
initial_button_value = 0;
|
|
|
|
for(i=0; i<ButtonCount; ++i)
|
|
{
|
|
buttonGroup[i].ForceUpdate(&initial_button_value, mode_mask);
|
|
buttonActivateModeMask[i] = mode_mask;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// Initialize control mode
|
|
//--------------------------------------------------
|
|
l4ControlsMode = normalMode;
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i<maxStringIDs; ++i)
|
|
{
|
|
temporaryStringID[i] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
// stringManager.Add("A90", KeyboardPilot, this, BeginCalibrationMessageID, 0);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Initialize the RIO stream spoofing stuff
|
|
//-----------------------------------------
|
|
//
|
|
rioStream = NULL;
|
|
streamStart = Now();
|
|
playbackMode = False;
|
|
streamEnabled = False;
|
|
|
|
previousJoystickX = (Scalar) 0;
|
|
previousJoystickY = (Scalar) 0;
|
|
previousThrottle = (Scalar) 0;
|
|
previousPedalLeft = (Scalar) 0;
|
|
previousPedalRight = (Scalar) 0;
|
|
//
|
|
//-------------------------------------
|
|
// See if we need to load in a RIO file
|
|
//-------------------------------------
|
|
//
|
|
CString
|
|
playback = L4Application::GetRIOPlaybackFileName();
|
|
if (playback && strlen(playback))
|
|
{
|
|
if (!flags.RIOExists)
|
|
{
|
|
DEBUG_STREAM << "RIO must be enabled by setenv!\n" << std::flush;
|
|
PostQuitMessage(1);
|
|
}
|
|
LoadPlayback(playback);
|
|
playbackMode = True;
|
|
}
|
|
|
|
CString
|
|
record = L4Application::GetRIORecordingFileName();
|
|
if (record && strlen(record))
|
|
{
|
|
if (!flags.RIOExists)
|
|
{
|
|
DEBUG_STREAM << "RIO must be enabled by setenv!\n" << std::flush;
|
|
PostQuitMessage(1);
|
|
}
|
|
|
|
RIOStreamEvent
|
|
*events = new RIOStreamEvent[RIO_SPOOL_SIZE];
|
|
Register_Pointer(events);
|
|
|
|
Verify(rioStream == NULL);
|
|
rioStream =
|
|
new MemoryStream(events, RIO_SPOOL_SIZE * sizeof(RIOStreamEvent));
|
|
Register_Object(rioStream);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//############################################################################
|
|
// ~LBE4ControlsManager
|
|
//
|
|
// Destructor method
|
|
//############################################################################
|
|
//
|
|
LBE4ControlsManager::~LBE4ControlsManager()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//----------------------------------------
|
|
// If we are recording, save the recording
|
|
//----------------------------------------
|
|
//
|
|
if (IsRecording())
|
|
{
|
|
CString
|
|
record = L4Application::GetRIORecordingFileName();
|
|
SaveRecording(record);
|
|
}
|
|
|
|
if (rioStream)
|
|
{
|
|
Check(rioStream);
|
|
rioStream->Rewind();
|
|
RIOStreamEvent
|
|
*start = (RIOStreamEvent*)rioStream->GetPointer();
|
|
|
|
Unregister_Object(rioStream);
|
|
delete rioStream;
|
|
|
|
Unregister_Pointer(start);
|
|
delete[] start;
|
|
|
|
rioStream = NULL;
|
|
streamEnabled = False;
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// Delete mouse
|
|
//--------------------------------------------------
|
|
if (mousePointer != NULL)
|
|
{
|
|
Check(mousePointer);
|
|
Unregister_Object(mousePointer);
|
|
delete mousePointer;
|
|
mousePointer = NULL;
|
|
}
|
|
//--------------------------------------------------
|
|
// Delete joystick
|
|
//--------------------------------------------------
|
|
if (joystickPointer != NULL)
|
|
{
|
|
Check(joystickPointer);
|
|
Unregister_Object(joystickPointer);
|
|
delete joystickPointer;
|
|
joystickPointer = NULL;
|
|
}
|
|
//--------------------------------------------------
|
|
// Delete string manager temporary groups
|
|
//--------------------------------------------------
|
|
ExitControlsMode();
|
|
//--------------------------------------------------
|
|
// Delete RIO AFTER buttons!
|
|
// ...the 'autoManager' button class sends
|
|
// lamp commands when deleted.
|
|
//--------------------------------------------------
|
|
if (rioPointer != NULL)
|
|
{
|
|
Check(rioPointer);
|
|
Unregister_Object(rioPointer);
|
|
delete rioPointer;
|
|
rioPointer = NULL;
|
|
}
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// LocalShutdown
|
|
//#############################################################################
|
|
//
|
|
void
|
|
LBE4ControlsManager::LocalShutdown()
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
if (rioPointer != NULL)
|
|
{
|
|
Check(rioPointer);
|
|
Unregister_Object(rioPointer);
|
|
delete rioPointer;
|
|
|
|
rioPointer = NULL;
|
|
}
|
|
|
|
ControlsManager::LocalShutdown();
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//############################################################################
|
|
// Remove
|
|
//
|
|
// Remove all controlsInstance records bearing the given ID
|
|
//############################################################################
|
|
//
|
|
void
|
|
LBE4ControlsManager::Remove(ModeMask mode_mask)
|
|
{
|
|
int i;
|
|
|
|
Check(this);
|
|
for(i=0; i<ScalarCount; ++i)
|
|
{
|
|
Check(&scalarGroup[i]);
|
|
scalarGroup[i].Remove(mode_mask);
|
|
}
|
|
|
|
for(i=0; i<JoystickCount; ++i)
|
|
{
|
|
Check(&joystickGroup[i]);
|
|
joystickGroup[i].Remove(mode_mask);
|
|
}
|
|
|
|
for(i=0; i<KeyboardCount; ++i)
|
|
{
|
|
Check(&keyboardGroup[i]);
|
|
keyboardGroup[i].Remove(mode_mask);
|
|
}
|
|
|
|
for(i=0; i<ButtonCount; ++i)
|
|
{
|
|
Check(&buttonGroup[i]);
|
|
buttonGroup[i].Remove(mode_mask);
|
|
}
|
|
|
|
Check(&mouseGroup[0]);
|
|
mouseGroup[0].Remove(mode_mask);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//############################################################################
|
|
// SetLamp
|
|
//
|
|
// Sets a specific lamp to the designated state
|
|
//############################################################################
|
|
//
|
|
|
|
void
|
|
LBE4ControlsManager::SetLamp(
|
|
int lamp_number,
|
|
int state
|
|
)
|
|
{
|
|
if (rioPointer != NULL)
|
|
{
|
|
Check(rioPointer);
|
|
Verify(lamp_number >= 0);
|
|
Verify(lamp_number < LBE4ControlsManager::LampCount);
|
|
|
|
rioPointer->SetLamp(lamp_number, (RIO::LampState) state);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//############################################################################
|
|
// Execute
|
|
//
|
|
// Execution method
|
|
//############################################################################
|
|
//
|
|
void
|
|
LBE4ControlsManager::Execute()
|
|
{
|
|
ControlsJoystick virtual_joystick;
|
|
ControlsKey keyValue;
|
|
ControlsMouse mouseValue;
|
|
static Scalar mouseWheel = 0.0;
|
|
Logical new_RIO_values(False);
|
|
Logical mouseMoved = false;
|
|
Logical mouseWheelMoved = false;
|
|
static int oldX = 0;
|
|
static int oldY = 0;
|
|
|
|
Check(this);
|
|
//--------------------------------------------------
|
|
// Get mode mask for updating
|
|
//--------------------------------------------------
|
|
Check(application);
|
|
Check(application->GetModeManager());
|
|
ModeMask
|
|
mode_mask = application->GetModeManager()->GetModeMask();
|
|
//-------------------------------------------------------------------------
|
|
// Process operator control mode
|
|
//-------------------------------------------------------------------------
|
|
// ManageControlsMode();
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Process RIO
|
|
//-------------------------------------------------------------------------
|
|
if (flags.RIOExists)
|
|
{
|
|
Check(rioPointer);
|
|
|
|
RIO::RIOEvent rio_event;
|
|
//
|
|
//------------------------------------
|
|
// Request analog update
|
|
// (held down to 5 Hz unless reply
|
|
// is received: reply allows another
|
|
// request to be sent next invocation)
|
|
//------------------------------------
|
|
//
|
|
if (!playbackMode)
|
|
{
|
|
//Scalar
|
|
// delta_t(Now() - lastRioRequest);
|
|
//Scalar
|
|
// limit;
|
|
//static Logical
|
|
// first_time = True;
|
|
|
|
//ADB 10/01/07
|
|
static DWORD last_check = GetTickCount();
|
|
DWORD limit = 15000;
|
|
|
|
if(application->GetApplicationState() == Application::RunningMission)
|
|
{
|
|
//Posible Bug: ADB 03/30/07
|
|
//limit = 15.0; // 0.2
|
|
limit = 50;//reduced to improve responsiveness
|
|
}
|
|
//else
|
|
//{
|
|
// //limit = 15.0;
|
|
// limit = 15000;
|
|
//}
|
|
|
|
//if (first_time)
|
|
//{
|
|
// first_time = False;
|
|
//}
|
|
//else
|
|
{
|
|
DWORD this_check = GetTickCount();
|
|
//if(this_check - last_check >= 1000)
|
|
//DEBUG_STREAM << "No Request in " << (this_check - last_check) << "ms." << std::endl << std::flush;
|
|
|
|
if((this_check - last_check) >= limit)
|
|
//if (delta_t >= limit) // 5 Hz minimum rate, in case of no reply
|
|
{
|
|
//-------------------------
|
|
// Debugging aid
|
|
//-------------------------
|
|
//long time_in_ticks;
|
|
|
|
//time_in_ticks = lastRioRequest;
|
|
//if (time_in_ticks != 0L)
|
|
//{
|
|
// DEBUG_STREAM << "LBE4ControlsManager::Execute, lost RIO analog request\n";
|
|
|
|
//STUBBED: JOYSTICK RB 1/14/07
|
|
/*extern Logical
|
|
iThinkIRQIsOn;
|
|
|
|
extern int
|
|
pcspakCharactersSent;
|
|
|
|
DEBUG_STREAM <<
|
|
"iThinkIRQIsOn =" << iThinkIRQIsOn <<
|
|
", actual state =" << PCSPAKIRQState() <<
|
|
", characters sent =" << pcspakCharactersSent << "\n";*/
|
|
//}
|
|
|
|
rioPointer->RequestAnalogUpdate();
|
|
//lastRioRequest = Now();
|
|
last_check = this_check;
|
|
}
|
|
//-------------------------
|
|
// Debugging aid
|
|
//-------------------------
|
|
//else if (delta_t < 0.0)
|
|
//{
|
|
// DEBUG_STREAM <<
|
|
// "LBE4ControlsManager::Execute, delta_t went negative (" <<
|
|
// delta_t << ")\n";
|
|
|
|
// rioPointer->RequestAnalogUpdate();
|
|
// lastRioRequest = Now();
|
|
//}
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------------------
|
|
// Process events
|
|
//------------------------------------
|
|
//
|
|
while (GetNextRIOEvent(&rio_event))
|
|
{
|
|
ProcessRIOEvent(rio_event, &new_RIO_values);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Read physical joystick inputs, filter the values
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
if (flags.joystickExists)
|
|
{
|
|
Scalar delta_t = (Scalar)Now() - lastJoystickUpdate;
|
|
|
|
if (delta_t > .05)
|
|
{
|
|
Check(joystickPointer);
|
|
joystickPointer->Update();
|
|
joystickPointer->Value.x = -joystickPointer->Value.x; // HACK!!!
|
|
|
|
lastJoystickUpdate = Now();
|
|
}
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Read physical mouse inputs, generate virtual joystick values
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
if (flags.mouseExists)
|
|
{
|
|
Check(mousePointer);
|
|
//OLD WAY: mousePointer->ReadCounters(&mouseValue.x, &mouseValue.y);
|
|
//NEW WAY
|
|
/*MSG msg;
|
|
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
|
|
{
|
|
if (msg.message == WM_MOUSEMOVE)
|
|
{
|
|
mouseMoved = true;
|
|
|
|
GetMessage(&msg, NULL, 0, 0);
|
|
int x = (msg.lParam & 0xFFFF);
|
|
int y = (msg.lParam & 0xFFFF0000) >> 16;
|
|
mouseValue.x = x - oldX;
|
|
mouseValue.y = y - oldY;
|
|
oldX = x;
|
|
oldY = y;
|
|
|
|
virtualJoystickX += mouseValue.x;
|
|
virtualJoystickY += mouseValue.y;
|
|
|
|
#define MAXEXTENT 400 // This is a guess. We'll have to try it and see.
|
|
|
|
if (virtualJoystickX > MAXEXTENT) { virtualJoystickX = MAXEXTENT; }
|
|
if (virtualJoystickX < -MAXEXTENT) { virtualJoystickX = -MAXEXTENT; }
|
|
virtual_joystick.x = (Scalar) virtualJoystickX / (Scalar) MAXEXTENT;
|
|
|
|
if (virtualJoystickY > MAXEXTENT) { virtualJoystickY = MAXEXTENT; }
|
|
if (virtualJoystickY < -MAXEXTENT) { virtualJoystickY = -MAXEXTENT; }
|
|
virtual_joystick.y = (Scalar) virtualJoystickY / (Scalar) MAXEXTENT;
|
|
}*/
|
|
//else if (msg.message == 0x020A /*WM_MOUSEWHEEL*/)
|
|
/*{
|
|
#define MAXEXTENT 1200.0f // Just a guess
|
|
|
|
mouseWheelMoved = true;
|
|
GetMessage(&msg, NULL, 0, 0);
|
|
//mouseWheel = (signed int)((msg.wParam & 0xFFFF0000) >> 16) * 1.0f;
|
|
int delta = (mouseWheel * MAXEXTENT) + ((short)HIWORD(msg.wParam));
|
|
|
|
if (delta > MAXEXTENT)
|
|
delta = MAXEXTENT;
|
|
if (delta < 0.0f)
|
|
delta = 0.0f;
|
|
|
|
mouseWheel = delta / MAXEXTENT;
|
|
}
|
|
}*/
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Update the scalar mapping groups using the analog values
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
if (flags.RIOExists && new_RIO_values)
|
|
{
|
|
Check(rioPointer);
|
|
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarThrottle]);
|
|
scalarGroup[LBE4ControlsManager::ScalarThrottle].Update(
|
|
&rioPointer->Throttle, mode_mask
|
|
);
|
|
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarLeftPedal]);
|
|
scalarGroup[LBE4ControlsManager::ScalarLeftPedal].Update(
|
|
&rioPointer->LeftPedal, mode_mask
|
|
);
|
|
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarRightPedal]);
|
|
scalarGroup[LBE4ControlsManager::ScalarRightPedal].Update(
|
|
&rioPointer->RightPedal, mode_mask
|
|
);
|
|
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarJoystickX]);
|
|
scalarGroup[LBE4ControlsManager::ScalarJoystickX].Update(
|
|
&rioPointer->JoystickX, mode_mask
|
|
);
|
|
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarJoystickY]);
|
|
scalarGroup[LBE4ControlsManager::ScalarJoystickY].Update(
|
|
&rioPointer->JoystickY, mode_mask
|
|
);
|
|
}
|
|
else if (flags.joystickExists)
|
|
{
|
|
scalarGroup[LBE4ControlsManager::ScalarLeftPedal].Update(
|
|
&joystickPointer->Rotation.x, mode_mask
|
|
);
|
|
|
|
scalarGroup[LBE4ControlsManager::ScalarRightPedal].Update(
|
|
&joystickPointer->Rotation.y, mode_mask
|
|
);
|
|
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarThrottle]);
|
|
scalarGroup[LBE4ControlsManager::ScalarThrottle].Update(
|
|
&joystickPointer->ExtendedValue.y, mode_mask
|
|
);
|
|
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarJoystickX]);
|
|
scalarGroup[LBE4ControlsManager::ScalarJoystickX].Update(
|
|
&joystickPointer->Value.x, mode_mask
|
|
);
|
|
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarJoystickY]);
|
|
scalarGroup[LBE4ControlsManager::ScalarJoystickY].Update(
|
|
&joystickPointer->Value.y, mode_mask
|
|
);
|
|
}
|
|
|
|
if (flags.mouseExists)
|
|
{
|
|
if (mouseMoved)
|
|
{
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarMouseX]);
|
|
scalarGroup[LBE4ControlsManager::ScalarMouseX].Update(
|
|
&virtual_joystick.x, mode_mask
|
|
);
|
|
Check(&scalarGroup[LBE4ControlsManager::ScalarMouseY]);
|
|
scalarGroup[LBE4ControlsManager::ScalarMouseY].Update(
|
|
&virtual_joystick.y, mode_mask
|
|
);
|
|
}
|
|
else
|
|
{
|
|
Scalar clear = 0;
|
|
scalarGroup[LBE4ControlsManager::ScalarMouseX].Update(&clear, mode_mask);
|
|
scalarGroup[LBE4ControlsManager::ScalarMouseY].Update(&clear, mode_mask);
|
|
}
|
|
if (mouseWheelMoved)
|
|
{
|
|
scalarGroup[LBE4ControlsManager::ScalarThrottle].Update(
|
|
&mouseWheel, mode_mask
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Update the joystick mapping groups using the analog values
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
if (flags.RIOExists && new_RIO_values)
|
|
{
|
|
Check(rioPointer);
|
|
|
|
ControlsJoystick
|
|
stick;
|
|
|
|
stick.x = rioPointer->JoystickX;
|
|
stick.y = rioPointer->JoystickY;
|
|
|
|
Check(&joystickGroup[LBE4ControlsManager::JoystickPhysical]);
|
|
joystickGroup[LBE4ControlsManager::JoystickPhysical].Update(
|
|
&stick, mode_mask
|
|
);
|
|
}
|
|
else if (flags.joystickExists)
|
|
{
|
|
Check(&joystickGroup[LBE4ControlsManager::JoystickPhysical]);
|
|
joystickGroup[LBE4ControlsManager::JoystickPhysical].Update(
|
|
&joystickPointer->Value, mode_mask
|
|
);
|
|
}
|
|
|
|
if (flags.mouseExists && mouseMoved)
|
|
{
|
|
Check(&joystickGroup[LBE4ControlsManager::JoystickVirtual]);
|
|
/*joystickGroup[LBE4ControlsManager::JoystickVirtual].Update(
|
|
&virtual_joystick, mode_mask
|
|
);*/
|
|
joystickGroup[LBE4ControlsManager::JoystickPhysical].Update(
|
|
&virtual_joystick, mode_mask
|
|
);
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Update the PC keyboard mapping group
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Master volume, PgUp louder / PgDn quieter.
|
|
//
|
|
// The cabinets ran the game at unity and left level to an external
|
|
// amplifier and crossover; without that hardware the player has to be able
|
|
// to reach the volume while playing.
|
|
//
|
|
// POLLED, not taken off the key message below, and that is deliberate. The
|
|
// pump below only ever consumes WM_KEYUP / WM_SYSKEYUP / WM_CHAR from the
|
|
// front of the queue, and the front-end runs message loops of its own, so
|
|
// key messages are raced for and routinely lost -- measured here at roughly
|
|
// two of every six presses arriving. That is survivable for a one-shot like
|
|
// the abort chord; it is not survivable for a control you tap repeatedly to
|
|
// find a level. Reading the key state directly costs nothing and cannot be
|
|
// dropped.
|
|
//
|
|
// Page keys because they produce no typed character, so they cannot collide
|
|
// with the character-keyed commands the pump feeds, nothing else in RP binds
|
|
// them, and they exist on tenkeyless keyboards.
|
|
//
|
|
// The foreground check keeps an alt-tabbed game from eating the volume keys
|
|
// of whatever the player switched to.
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// Home/End do the same for the bass trim - the crossover's low band to
|
|
// PgUp/PgDn's amplifier.
|
|
//
|
|
{
|
|
static int volume_up_held = 0;
|
|
static int volume_down_held = 0;
|
|
static int bass_up_held = 0;
|
|
static int bass_down_held = 0;
|
|
|
|
int focused = 0;
|
|
|
|
if (HWND foreground = GetForegroundWindow())
|
|
{
|
|
DWORD foreground_process = 0;
|
|
|
|
GetWindowThreadProcessId(foreground, &foreground_process);
|
|
focused = (foreground_process == GetCurrentProcessId());
|
|
}
|
|
|
|
const int up = focused && (GetAsyncKeyState(VK_PRIOR) & 0x8000) != 0;
|
|
const int down = focused && (GetAsyncKeyState(VK_NEXT) & 0x8000) != 0;
|
|
const int bass_up = focused && (GetAsyncKeyState(VK_HOME) & 0x8000) != 0;
|
|
const int bass_down = focused && (GetAsyncKeyState(VK_END) & 0x8000) != 0;
|
|
|
|
if (up && !volume_up_held)
|
|
{
|
|
RPAudioMasterVolumeStep(+1);
|
|
}
|
|
if (down && !volume_down_held)
|
|
{
|
|
RPAudioMasterVolumeStep(-1);
|
|
}
|
|
if (bass_up && !bass_up_held)
|
|
{
|
|
RPBassTrimStep(+1);
|
|
}
|
|
if (bass_down && !bass_down_held)
|
|
{
|
|
RPBassTrimStep(-1);
|
|
}
|
|
|
|
volume_up_held = up;
|
|
volume_down_held = down;
|
|
bass_up_held = bass_up;
|
|
bass_down_held = bass_down;
|
|
}
|
|
|
|
if (flags.keyboardExists)
|
|
{
|
|
//RB 1/20/07
|
|
//keyValue = (ControlsKey) PC_Keyboard_Read();
|
|
MSG msg;
|
|
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
|
|
{
|
|
if (msg.message == WM_SYSKEYUP || msg.message == WM_KEYUP || msg.message == WM_CHAR)
|
|
{
|
|
GetMessage(&msg, NULL, 0, 0);
|
|
TranslateMessage(&msg);
|
|
keyValue = (msg.wParam & VK_MASK);
|
|
if (msg.message == WM_SYSKEYUP)
|
|
keyValue |= ALT_BIT;
|
|
keyboardGroup[KeyboardPC].ForceUpdate(&keyValue, mode_mask);
|
|
stringManager.Update(KeyboardPC, keyValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Update the button mapping groups
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
|
|
//
|
|
//--------------------------
|
|
// Joystick buttons
|
|
//--------------------------
|
|
//
|
|
if (flags.joystickExists)
|
|
{
|
|
int i;
|
|
ControlsButton b;
|
|
|
|
Check(joystickPointer);
|
|
|
|
i = joystickPointer->ButtonReleased;
|
|
if(i != Joystick::NoButton)
|
|
{
|
|
if (i & Joystick::Trigger)
|
|
{
|
|
b = - ButtonJoystickTrigger - 1;
|
|
buttonGroup[ButtonJoystickTrigger].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::Thumb1)
|
|
{
|
|
b = - ButtonJoystickPinky - 1;
|
|
buttonGroup[ButtonJoystickPinky].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::Thumb2)
|
|
{
|
|
b = - ButtonJoystickThumbLow - 1;
|
|
buttonGroup[ButtonJoystickThumbLow].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::Thumb3)
|
|
{
|
|
b = - ButtonJoystickThumbHigh - 1;
|
|
buttonGroup[ButtonJoystickThumbHigh].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::Throttle)
|
|
{
|
|
b = - ButtonThrottle1 - 1;
|
|
buttonGroup[ButtonThrottle1].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::HatUp)
|
|
{
|
|
b = - ButtonJoystickHatUp - 1;
|
|
buttonGroup[ButtonJoystickHatUp].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::HatDown)
|
|
{
|
|
b = - ButtonJoystickHatDown - 1;
|
|
buttonGroup[ButtonJoystickHatDown].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::HatLeft)
|
|
{
|
|
b = - ButtonJoystickHatLeft - 1;
|
|
buttonGroup[ButtonJoystickHatLeft].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::HatRight)
|
|
{
|
|
b = - ButtonJoystickHatRight - 1;
|
|
buttonGroup[ButtonJoystickHatRight].Update(&b, mode_mask);
|
|
}
|
|
}
|
|
|
|
i = joystickPointer->ButtonPressed;
|
|
if(i != Joystick::NoButton)
|
|
{
|
|
if (i & Joystick::Trigger)
|
|
{
|
|
b = ButtonJoystickTrigger + 1;
|
|
buttonGroup[ButtonJoystickTrigger].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::Thumb1)
|
|
{
|
|
b = ButtonJoystickPinky + 1;
|
|
buttonGroup[ButtonJoystickPinky].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::Thumb2)
|
|
{
|
|
b = ButtonJoystickThumbLow + 1;
|
|
buttonGroup[ButtonJoystickThumbLow].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::Thumb3)
|
|
{
|
|
b = ButtonJoystickThumbHigh + 1;
|
|
buttonGroup[ButtonJoystickThumbHigh].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::Throttle)
|
|
{
|
|
b = ButtonThrottle1 - 1;
|
|
buttonGroup[ButtonThrottle1].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::HatUp)
|
|
{
|
|
b = ButtonJoystickHatUp + 1;
|
|
buttonGroup[ButtonJoystickHatUp].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::HatDown)
|
|
{
|
|
b = ButtonJoystickHatDown + 1;
|
|
buttonGroup[ButtonJoystickHatDown].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::HatLeft)
|
|
{
|
|
b = ButtonJoystickHatLeft + 1;
|
|
buttonGroup[ButtonJoystickHatLeft].Update(&b, mode_mask);
|
|
}
|
|
if (i & Joystick::HatRight)
|
|
{
|
|
b = ButtonJoystickHatRight + 1;
|
|
buttonGroup[ButtonJoystickHatRight].Update(&b, mode_mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------
|
|
// Mouse buttons
|
|
//--------------------------
|
|
//
|
|
if (flags.mouseExists)
|
|
{
|
|
int i, j, k;
|
|
ControlsButton b;
|
|
|
|
k = mousePointer->ButtonCount;
|
|
|
|
for(i=0, j=LBE4ControlsManager::ButtonMouseLeft; i<k; ++i,++j)
|
|
{
|
|
if (mousePointer->ButtonPressed(i))
|
|
{
|
|
b = (ControlsButton) (j+1);
|
|
buttonGroup[j].Update(&b, mode_mask);
|
|
}
|
|
|
|
if (mousePointer->ButtonReleased(i))
|
|
{
|
|
b = (ControlsButton) (-j-1);
|
|
buttonGroup[j].Update(&b, mode_mask);
|
|
}
|
|
}
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Update the mouse mapping group
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
mouseGroup[0].Update(&mouseValue, mode_mask);
|
|
}
|
|
|
|
// Tell("LBE4ControlsManager::Execute ends\n" << std::flush);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//############################################################################
|
|
// BeginAlignJoystick
|
|
//
|
|
// Start alignment process for joystick and analog inputs
|
|
//############################################################################
|
|
//
|
|
void
|
|
LBE4ControlsManager::BeginAlignJoystick()
|
|
{
|
|
Check(this);
|
|
|
|
if (flags.joystickExists)
|
|
{
|
|
Check(joystickPointer);
|
|
joystickPointer->BeginAlignment();
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//############################################################################
|
|
// EndAlignJoystick
|
|
//
|
|
// End alignment process for joystick and analog inputs
|
|
//############################################################################
|
|
//
|
|
void
|
|
LBE4ControlsManager::EndAlignJoystick()
|
|
{
|
|
Check(this);
|
|
|
|
if (flags.RIOExists)
|
|
{
|
|
Check(rioPointer);
|
|
rioPointer->ForceCenterJoystick();
|
|
}
|
|
|
|
if (flags.joystickExists)
|
|
{
|
|
Check(joystickPointer);
|
|
joystickPointer->EndAlignment();
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
LBE4ControlsManager::CenterRIOJoystick()
|
|
{
|
|
Check(this);
|
|
|
|
if (flags.RIOExists)
|
|
{
|
|
Check(rioPointer);
|
|
rioPointer->ForceCenterJoystick();
|
|
}
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
LBE4ControlsManager::SetJoystickDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
|
|
if (flags.RIOExists)
|
|
{
|
|
Check(rioPointer);
|
|
rioPointer->SetJoystickDeadBand(dead_band);
|
|
}
|
|
|
|
if (flags.joystickExists)
|
|
{
|
|
Check(joystickPointer);
|
|
joystickPointer->SetDeadBand(dead_band);
|
|
}
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
LBE4ControlsManager::SetThrottleDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
|
|
if (flags.RIOExists)
|
|
{
|
|
Check(rioPointer);
|
|
rioPointer->SetThrottleDeadBand(dead_band);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
LBE4ControlsManager::SetPedalsDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
|
|
if (flags.RIOExists)
|
|
{
|
|
Check(rioPointer);
|
|
rioPointer->SetPedalsDeadBand(dead_band);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
const char*
|
|
LBE4ControlsManager::GetLampName(int lamp_number)
|
|
{
|
|
const char
|
|
*lamp_name[] =
|
|
{
|
|
"AuxLowerRight8",
|
|
"AuxLowerRight7",
|
|
"AuxLowerRight6",
|
|
"AuxLowerRight5",
|
|
"AuxLowerRight4",
|
|
"AuxLowerRight3",
|
|
"AuxLowerRight2",
|
|
"AuxLowerRight1",
|
|
"AuxLowerLeft8",
|
|
"AuxLowerLeft7",
|
|
"AuxLowerLeft6",
|
|
"AuxLowerLeft5",
|
|
"AuxLowerLeft4",
|
|
"AuxLowerLeft3",
|
|
"AuxLowerLeft2",
|
|
"AuxLowerLeft1",
|
|
"Secondary1", //=0x10
|
|
"Secondary2",
|
|
"Secondary3",
|
|
"Secondary4",
|
|
"Secondary5",
|
|
"Secondary6",
|
|
"TeslaRelay3",
|
|
"undefined_0x17",
|
|
"Secondary7", //=0x18
|
|
"Secondary8",
|
|
"Secondary9",
|
|
"Secondary10",
|
|
"Secondary11",
|
|
"Secondary12",
|
|
"TeslaRelay1",
|
|
"TeslaRelay2",
|
|
"AuxUpperCenter8", //=0x20
|
|
"AuxUpperCenter7",
|
|
"AuxUpperCenter6",
|
|
"AuxUpperCenter5",
|
|
"AuxUpperCenter4",
|
|
"AuxUpperCenter3",
|
|
"AuxUpperCenter2",
|
|
"AuxUpperCenter1",
|
|
"AuxUpperLeft8", //=0x28
|
|
"AuxUpperLeft7",
|
|
"AuxUpperLeft6",
|
|
"AuxUpperLeft5",
|
|
"AuxUpperLeft4",
|
|
"AuxUpperLeft3",
|
|
"AuxUpperLeft2",
|
|
"AuxUpperLeft1",
|
|
"AuxUpperRight8", //=0x30
|
|
"AuxUpperRight7",
|
|
"AuxUpperRight6",
|
|
"AuxUpperRight5",
|
|
"AuxUpperRight4",
|
|
"AuxUpperRight3",
|
|
"AuxUpperRight2",
|
|
"AuxUpperRight1",
|
|
"PanicButton", //=0x38
|
|
"IcomAmpEnableRelay",//=0x39
|
|
"IcomIncRelay", //=0x3A
|
|
"IcomPTTRelay", //=0x03B
|
|
"IcomDecRelay", //=0x3C
|
|
"undefined_0x3D", //=0x3D unimplemented convenience lamp
|
|
"FloorEntry" //=0x3E
|
|
};
|
|
|
|
if (lamp_number >= LampCount)
|
|
{
|
|
return "overrange";
|
|
}
|
|
else if (lamp_number < 0)
|
|
{
|
|
return "underrange";
|
|
}
|
|
else
|
|
{
|
|
return lamp_name[lamp_number];
|
|
}
|
|
}
|
|
|
|
|
|
#define ID_ENTRY(name,group)\
|
|
{ #name , LBE4ControlsManager::##group, LBE4ControlsManager::##name }
|
|
|
|
struct {
|
|
const char* controlName;
|
|
Enumeration
|
|
controlsGroup,
|
|
controlsElement;
|
|
}
|
|
Control_IDs[]=
|
|
{
|
|
//-----------------------------------------------
|
|
// Throttle
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ScalarThrottle,ScalarGroup),
|
|
ID_ENTRY(ButtonThrottle1,ButtonGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Pedals
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ScalarLeftPedal,ScalarGroup),
|
|
ID_ENTRY(ScalarRightPedal,ScalarGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Joystick
|
|
//-----------------------------------------------
|
|
ID_ENTRY(JoystickPhysical,JoystickGroup),
|
|
ID_ENTRY(ButtonJoystickHatUp,ButtonGroup),
|
|
ID_ENTRY(ButtonJoystickHatDown,ButtonGroup),
|
|
ID_ENTRY(ButtonJoystickHatLeft,ButtonGroup),
|
|
ID_ENTRY(ButtonJoystickHatRight,ButtonGroup),
|
|
ID_ENTRY(ButtonJoystickTrigger,ButtonGroup),
|
|
ID_ENTRY(ButtonJoystickThumbHigh,ButtonGroup),
|
|
ID_ENTRY(ButtonJoystickThumbLow,ButtonGroup),
|
|
ID_ENTRY(ButtonJoystickPinky,ButtonGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Secondary buttons
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ButtonSecondary1,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary2,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary3,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary4,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary5,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary6,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary7,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary8,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary9,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary10,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary11,ButtonGroup),
|
|
ID_ENTRY(ButtonSecondary12,ButtonGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Upper left auxiliary
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ButtonAuxUpperLeft8,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperLeft7,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperLeft6,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperLeft5,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperLeft4,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperLeft3,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperLeft2,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperLeft1,ButtonGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Center auxiliary
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ButtonAuxUpperCenter8,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperCenter7,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperCenter6,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperCenter5,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperCenter4,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperCenter3,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperCenter2,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperCenter1,ButtonGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Upper right auxiliary
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ButtonAuxUpperRight8,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperRight7,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperRight6,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperRight5,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperRight4,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperRight3,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperRight2,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxUpperRight1,ButtonGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Lower left auxiliary
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ButtonAuxLowerLeft8,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerLeft7,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerLeft6,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerLeft5,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerLeft4,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerLeft3,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerLeft2,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerLeft1,ButtonGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Lower right auxiliary
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ButtonAuxLowerRight8,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerRight7,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerRight6,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerRight5,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerRight4,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerRight3,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerRight2,ButtonGroup),
|
|
ID_ENTRY(ButtonAuxLowerRight1,ButtonGroup),
|
|
|
|
//-----------------------------------------------
|
|
// Miscellaneous buttons
|
|
//-----------------------------------------------
|
|
ID_ENTRY(ButtonPanic,ButtonGroup),
|
|
ID_ENTRY(ButtonDoor,ButtonGroup)
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
LBE4ControlsManager::SetControlMappingID(
|
|
const char *control_name,
|
|
ControlsMapping *mapping
|
|
)
|
|
{
|
|
Check_Pointer(control_name);
|
|
Check_Pointer(mapping);
|
|
|
|
int i;
|
|
for (i=0; i<ELEMENTS(Control_IDs); ++i)
|
|
{
|
|
if (!stricmp(control_name, Control_IDs[i].controlName))
|
|
{
|
|
mapping->controlsGroup = Control_IDs[i].controlsGroup;
|
|
mapping->controlsElement = Control_IDs[i].controlsElement;
|
|
break;
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
return i < ELEMENTS(Control_IDs);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Lamp *
|
|
LBE4ControlsManager::MakeLinkedLamp(
|
|
int element,
|
|
ModeMask mode_mask
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(application);
|
|
|
|
if (application->GetGaugeRenderer() == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
Check(application->GetGaugeRenderer());
|
|
|
|
//------------------------------------------
|
|
// Create the lamp
|
|
//------------------------------------------
|
|
L4LampManager
|
|
*lamp_manager = (L4LampManager *) application->
|
|
GetGaugeRenderer()->GetLampManager();
|
|
Check(lamp_manager);
|
|
|
|
Lamp
|
|
*lamp = new L4Lamp(
|
|
element,
|
|
mode_mask,
|
|
lamp_manager
|
|
);
|
|
Register_Object(lamp);
|
|
//------------------------------------------
|
|
// Add button mapping to lamp
|
|
//------------------------------------------
|
|
buttonGroup[element].Add(
|
|
mode_mask,
|
|
&((L4Lamp *)lamp)->automaticValue,
|
|
lamp
|
|
);
|
|
|
|
Check_Fpu();
|
|
return lamp;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
LBE4ControlsManager::CreateStreamedMappings(
|
|
Entity *player,
|
|
const int *control_mappings
|
|
)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(control_mappings);
|
|
|
|
int
|
|
controls_count = *control_mappings;
|
|
++control_mappings;
|
|
|
|
ControlsMapping
|
|
*mapping = (ControlsMapping*)control_mappings;
|
|
Simulation
|
|
*subsystem;
|
|
void
|
|
*attribute;
|
|
|
|
for (int i=0; i<controls_count; ++i)
|
|
{
|
|
subsystem = player->GetSimulation(mapping->subsystemID);
|
|
Verify(subsystem);
|
|
|
|
//
|
|
//---------------------------
|
|
// Handle the direct mappings
|
|
//---------------------------
|
|
//
|
|
int
|
|
element = mapping->controlsElement;
|
|
ModeMask
|
|
mode_mask = mapping->modeMask;
|
|
|
|
if (mapping->mappingType == ControlsMapping::DirectMapping)
|
|
{
|
|
attribute = subsystem->GetAttributePointer(mapping->attributeID);
|
|
switch (mapping->controlsGroup)
|
|
{
|
|
case ScalarGroup:
|
|
scalarGroup[element].Add(
|
|
mode_mask,
|
|
(ControlsScalar*)attribute,
|
|
subsystem
|
|
);
|
|
break;
|
|
case JoystickGroup:
|
|
joystickGroup[element].Add(
|
|
mode_mask,
|
|
(ControlsJoystick*)attribute,
|
|
subsystem
|
|
);
|
|
break;
|
|
case ButtonGroup:
|
|
//----------------------------------------------
|
|
// Add button
|
|
//----------------------------------------------
|
|
buttonGroup[element].Add(
|
|
mode_mask,
|
|
(ControlsButton*)attribute,
|
|
subsystem
|
|
);
|
|
//----------------------------------------------
|
|
// Create associated lamp
|
|
//----------------------------------------------
|
|
if(buttonType[element] == AUTOBTN)
|
|
{
|
|
# if DEBUG_LEVEL > 0
|
|
Lamp *
|
|
lamp =
|
|
# endif
|
|
MakeLinkedLamp(element, mode_mask);
|
|
|
|
# if DEBUG_LEVEL > 0
|
|
if (lamp != NULL)
|
|
{
|
|
Check(lamp);
|
|
}
|
|
# endif
|
|
}
|
|
break;
|
|
default:
|
|
Fail("Unknown mapping group!\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------
|
|
// Otherwise, it is an event mapping, so set that up
|
|
//--------------------------------------------------
|
|
//
|
|
else if (mapping->mappingType == ControlsMapping::EventMapping)
|
|
{
|
|
Receiver::MessageID
|
|
msg_id = mapping->messageID;
|
|
|
|
switch (mapping->controlsGroup)
|
|
{
|
|
case ScalarGroup:
|
|
scalarGroup[element].Add(mode_mask,subsystem,msg_id,subsystem);
|
|
break;
|
|
case JoystickGroup:
|
|
joystickGroup[element].Add(mode_mask,subsystem,msg_id,subsystem);
|
|
break;
|
|
case ButtonGroup:
|
|
//----------------------------------------------
|
|
// Add button
|
|
//----------------------------------------------
|
|
buttonGroup[element].Add(
|
|
mode_mask,
|
|
subsystem,
|
|
msg_id,
|
|
subsystem
|
|
);
|
|
//----------------------------------------------
|
|
// Create associated lamp
|
|
//----------------------------------------------
|
|
if(buttonType[element] == AUTOBTN)
|
|
{
|
|
# if DEBUG_LEVEL > 0
|
|
Lamp *
|
|
lamp =
|
|
# endif
|
|
MakeLinkedLamp(element, mode_mask);
|
|
|
|
# if DEBUG_LEVEL > 0
|
|
if (lamp != NULL)
|
|
{
|
|
Check(lamp);
|
|
}
|
|
# endif
|
|
}
|
|
break;
|
|
default:
|
|
Fail("Unknown mapping group!\n");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Fail("Unknown mapping type!\n");
|
|
}
|
|
mapping = (ControlsMapping*)((char*)mapping + sizeof(ControlsMapping));
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
LBE4ControlsManager::EnterControlsMode(
|
|
L4ControlsMode new_mode,
|
|
Scalar time_until_exit,
|
|
Receiver::MessageID message_on_exit
|
|
)
|
|
{
|
|
Check(this);
|
|
l4ControlsMode = new_mode;
|
|
|
|
exitModeTime = ((Scalar) Now()) + time_until_exit;
|
|
exitMessageID = message_on_exit;
|
|
|
|
SetLamp(LampPanic, RIO::flashFast+RIO::state1Off+RIO::state2Bright);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
LBE4ControlsManager::ExitControlsMode()
|
|
{
|
|
Check(this);
|
|
|
|
l4ControlsMode = normalMode;
|
|
|
|
int
|
|
i;
|
|
|
|
for(i=0; i<maxStringIDs; ++i)
|
|
{
|
|
if (temporaryStringID[i] != 0)
|
|
{
|
|
stringManager.Remove(temporaryStringID[i]);
|
|
}
|
|
}
|
|
|
|
SetLamp(LampPanic, RIO::solid+RIO::state1Off+RIO::state2Off);
|
|
Verify(heapcheck() != _HEAPCORRUPT);
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
LBE4ControlsManager::ManageControlsMode()
|
|
{
|
|
Check(this);
|
|
|
|
if (l4ControlsMode != normalMode)
|
|
{
|
|
if (Now() >= exitModeTime)
|
|
{
|
|
Receiver::Message
|
|
message(exitMessageID, sizeof(Receiver__Message));
|
|
|
|
Dispatch(&message);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
LBE4ControlsManager::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(*GetClassDerivations()));
|
|
return ControlsManager::TestInstance();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
LBE4ControlsManager::AnalogHasChanged()
|
|
{
|
|
Check(this);
|
|
|
|
Logical
|
|
result = False;
|
|
|
|
if (rioPointer != NULL)
|
|
{
|
|
Check(rioPointer);
|
|
|
|
result = (rioPointer->Throttle != previousThrottle);
|
|
result |= (rioPointer->LeftPedal != previousPedalLeft);
|
|
result |= (rioPointer->RightPedal != previousPedalRight);
|
|
result |= (rioPointer->JoystickX != previousJoystickX);
|
|
result |= (rioPointer->JoystickY != previousJoystickY);
|
|
|
|
if (result)
|
|
{
|
|
previousThrottle = rioPointer->Throttle;
|
|
previousPedalLeft = rioPointer->LeftPedal;
|
|
previousPedalRight = rioPointer->RightPedal;
|
|
previousJoystickX = rioPointer->JoystickX;
|
|
previousJoystickY = rioPointer->JoystickY;
|
|
}
|
|
}
|
|
|
|
Check_Fpu();
|
|
return result;
|
|
}
|
|
|
|
Logical
|
|
LBE4ControlsManager::GetNextRIOEvent(RIO::RIOEvent *rio_event)
|
|
{
|
|
//
|
|
//-------------------------------------------------
|
|
// If we aren't in playback mode, read the real RIO
|
|
//-------------------------------------------------
|
|
//
|
|
if (!playbackMode)
|
|
{
|
|
Logical
|
|
result = rioPointer->GetNextEvent(rio_event);
|
|
//----------------------------------------------------------------------
|
|
// If the RIO stream exists, and a rio event was added,
|
|
// store this event in the rioStream
|
|
//----------------------------------------------------------------------
|
|
if (result && streamEnabled)
|
|
{
|
|
Check(rioStream);
|
|
if (rioStream->GetBytesRemaining() >= sizeof(RIOStreamEvent))
|
|
{
|
|
Check(rioStream);
|
|
RIOStreamEvent
|
|
*event = (RIOStreamEvent*)rioStream->GetPointer();
|
|
Check_Pointer(event);
|
|
|
|
event->timeStamp.ticks = Now().ticks - streamStart.ticks;
|
|
|
|
if (rio_event->Type == RIO::AnalogEvent)
|
|
{
|
|
if (AnalogHasChanged())
|
|
{
|
|
DEBUG_STREAM << "AnalogEvent at" << event->timeStamp.ticks << "\n";
|
|
DEBUG_STREAM << "Pointer=" << std::hex << event << std::dec << "\n";
|
|
//----------------------------
|
|
// Set the event type
|
|
//----------------------------
|
|
event->eventType = analog;
|
|
//----------------------------
|
|
// Get the analog state
|
|
//----------------------------
|
|
event->data.analog.throttle = rioPointer->Throttle;
|
|
event->data.analog.pedalLeft = rioPointer->LeftPedal;
|
|
event->data.analog.pedalRight = rioPointer->RightPedal;
|
|
event->data.analog.joystickX = rioPointer->JoystickX;
|
|
event->data.analog.joystickY = rioPointer->JoystickY;
|
|
//----------------------------
|
|
// Save the event
|
|
//----------------------------
|
|
rioStream->AdvancePointer(sizeof(RIOStreamEvent));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUG_STREAM << "DigitalEvent at" << event->timeStamp.ticks << "\n";
|
|
DEBUG_STREAM << "Pointer=" << std::hex << event << std::dec << "\n";
|
|
//----------------------------
|
|
// Set the event type
|
|
//----------------------------
|
|
event->eventType = digital;
|
|
//----------------------------
|
|
// Save the event
|
|
//----------------------------
|
|
event->data.rioEvent = *rio_event;
|
|
rioStream->AdvancePointer(sizeof(RIOStreamEvent));
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Otherwise, we are in playback mode, so get the next record out of the
|
|
// memory block
|
|
//----------------------------------------------------------------------
|
|
//
|
|
else if (streamEnabled)
|
|
{
|
|
Check(rioStream);
|
|
if (rioStream->GetBytesRemaining() >= sizeof(RIOStreamEvent))
|
|
{
|
|
RIOStreamEvent
|
|
*event = (RIOStreamEvent*)rioStream->GetPointer();
|
|
|
|
Check_Pointer(event);
|
|
Time
|
|
now;
|
|
|
|
now.ticks = Now().ticks - streamStart.ticks;
|
|
|
|
if (event->timeStamp.ticks <= now.ticks)
|
|
{
|
|
DEBUG_STREAM << "Event timestamp=" << event->timeStamp.ticks << "\n";
|
|
switch(event->eventType)
|
|
{
|
|
case analog:
|
|
DEBUG_STREAM << "AnalogEvent\n";
|
|
//----------------------------
|
|
// Send event type ONLY
|
|
//----------------------------
|
|
rio_event->Type = RIO::AnalogEvent;
|
|
//----------------------------
|
|
// Restore the analog state
|
|
//----------------------------
|
|
rioPointer->Throttle = event->data.analog.throttle;
|
|
rioPointer->LeftPedal = event->data.analog.pedalLeft;
|
|
rioPointer->RightPedal = event->data.analog.pedalRight;
|
|
rioPointer->JoystickX = event->data.analog.joystickX;
|
|
rioPointer->JoystickY = event->data.analog.joystickY;
|
|
break;
|
|
|
|
case digital:
|
|
DEBUG_STREAM << "DigitalEvent\n";
|
|
//----------------------------
|
|
// Send the entire event
|
|
//----------------------------
|
|
*rio_event = event->data.rioEvent;
|
|
break;
|
|
}
|
|
rioStream->AdvancePointer(sizeof(RIOStreamEvent));
|
|
return True;
|
|
}
|
|
}
|
|
}
|
|
return False;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
LBE4ControlsManager::ProcessRIOEvent(
|
|
RIO::RIOEvent &rio_event,
|
|
Logical *new_RIO_values
|
|
)
|
|
{
|
|
//--------------------------------------------------
|
|
// Get mode mask for updating
|
|
//--------------------------------------------------
|
|
Check(application);
|
|
Check(application->GetModeManager());
|
|
ModeMask
|
|
mode_mask = application->GetModeManager()->GetModeMask();
|
|
ControlsButton temp;
|
|
|
|
switch(rio_event.Type)
|
|
{
|
|
case RIO::ButtonPressedEvent:
|
|
Verify(rio_event.Data.Unit >= 0);
|
|
Verify(rio_event.Data.Unit < ButtonCount);
|
|
temp = rio_event.Data.Unit + 1;
|
|
|
|
Check(&buttonGroup[rio_event.Data.Unit]);
|
|
buttonGroup[rio_event.Data.Unit].Update(&temp, mode_mask);
|
|
//----------------------------------------
|
|
// Save 'pressed' mode mask for 'release'
|
|
//----------------------------------------
|
|
buttonActivateModeMask[rio_event.Data.Unit] = mode_mask;
|
|
break;
|
|
|
|
case RIO::ButtonReleasedEvent:
|
|
Verify(rio_event.Data.Unit >= 0);
|
|
Verify(rio_event.Data.Unit < ButtonCount);
|
|
temp = -rio_event.Data.Unit - 1;
|
|
|
|
Check(&buttonGroup[rio_event.Data.Unit]);
|
|
//----------------------------------------
|
|
// Use 'pressed' mode mask for 'release'
|
|
//----------------------------------------
|
|
buttonGroup[rio_event.Data.Unit].Update(
|
|
&temp,
|
|
buttonActivateModeMask[rio_event.Data.Unit]
|
|
);
|
|
break;
|
|
|
|
case RIO::KeyEvent:
|
|
{
|
|
Verify(rio_event.Data.Keyboard.Unit >= 0);
|
|
Verify(rio_event.Data.Keyboard.Unit < KeyboardCount);
|
|
//--------------------------------------
|
|
// Convert key to ASCII
|
|
//--------------------------------------
|
|
ControlsKey
|
|
new_key = rio_event.Data.Keyboard.Key;
|
|
if (new_key <= 9)
|
|
{
|
|
new_key += '0';
|
|
}
|
|
else
|
|
{
|
|
new_key += 'A'-10;
|
|
}
|
|
Test_Tell(
|
|
"LBE4ControlsManager::Execute, new_key=" << (int) new_key <<
|
|
"\n"
|
|
);
|
|
|
|
Check(&keyboardGroup[rio_event.Data.Keyboard.Unit]);
|
|
keyboardGroup[rio_event.Data.Keyboard.Unit].
|
|
ForceUpdate(&new_key, mode_mask);
|
|
|
|
Check(&stringManager);
|
|
stringManager.Update(
|
|
rio_event.Data.Keyboard.Unit,
|
|
new_key
|
|
);
|
|
}
|
|
break;
|
|
|
|
case RIO::AnalogEvent:
|
|
lastRioRequest = 0L; // force another RIO update request
|
|
*new_RIO_values = True;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
LBE4ControlsManager::SaveRecording(const char* file_name)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(file_name);
|
|
Check(rioStream);
|
|
|
|
FileStream
|
|
output(file_name, True);
|
|
size_t
|
|
length = rioStream->GetBytesUsed();
|
|
if (length)
|
|
{
|
|
rioStream->Rewind();
|
|
|
|
output << length;
|
|
output << *rioStream;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
LBE4ControlsManager::LoadPlayback(const char* file_name)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(file_name);
|
|
|
|
FileStream
|
|
input(file_name);
|
|
Verify(input.IsFileOpened());
|
|
|
|
//
|
|
//-------------------------------
|
|
// Figure out how big the file is
|
|
//-------------------------------
|
|
//
|
|
size_t
|
|
spool_size = 0;
|
|
input >> spool_size;
|
|
Verify(spool_size);
|
|
Verify(spool_size <= RIO_SPOOL_SIZE * sizeof(RIOStreamEvent));
|
|
|
|
RIOStreamEvent
|
|
*events = new RIOStreamEvent[RIO_SPOOL_SIZE];
|
|
Register_Pointer(events);
|
|
|
|
Verify(rioStream == NULL);
|
|
rioStream = new MemoryStream(events, spool_size);
|
|
Register_Object(rioStream);
|
|
|
|
input.ReadBytes(events, spool_size);
|
|
}
|
|
|
|
#if defined(TEST_CLASS)
|
|
# include "l4ctrl.tcp"
|
|
#endif
|