Files
CydandClaude Opus 4.8 4abbf8879f Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:

- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies

Removed stale Subversion metadata and added .gitignore/.gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 07:59:51 -05:00

2593 lines
63 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "l4ctrl.h"
#include "l4keybd.h"
#include "l4app.h"
#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;
}
}
}
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
//-------------------------------------------------------------------------
//
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