Files
RP412/MUNGA_L4/L4CTRL.cpp
T
CydandClaude Opus 5 25e25260b1 Home and End are the bass knob
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>
2026-08-06 00:08:55 -05:00

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