Ported from RP412: RIOBase split out of the serial RIO (L4RIO.h), rioPointer is RIOBase* (L4CTRL.h), PAD token -> new PadRIO() speaking the RIO surface from an XInput pad + keyboard (L4PADRIO/L4PADBINDINGS, vRIO bindings.txt grammar, hot-plug), KeyLight RGB mirror TU (BT412KEYLIGHT, /std:c++17 per-file). BT-side fixes PadRIO forced into the open: - Both keyboard input bridges (mech4.cpp, mechmppr.cpp BT_KEY_BRIDGE) stand down when a RIO device exists -- they overwrote the engine controls push every frame. M/X conveniences stay live. - Mapper attribute chain OFF BY ONE (latent real-pod bug): the DOS chain below MechControlsMapper carried two base attributes, WinTesla carries one, and AttributeIndexSet::Find is positional -- the .CTL stick mapping wrote throttlePosition. Pad slot + binary-locked enum; gotcha ledgered (reconstruction-gotchas #11). Verified: PAD throttle lever ramps + sticks, stick turns with the authentic speed-vs-turn clamp (61.5 -> 22.0 u/s), mech drives; keyboard fallback intact (BT_FORCE_THROTTLE harness). New diags: BT_CTRLMAP_LOG, BT_STICK_LOG. (Phase 2 of docs/BT412-ROADMAP.md) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2656 lines
66 KiB
C++
2656 lines
66 KiB
C++
#include "mungal4.h"
|
|
#pragma hdrstop
|
|
|
|
#include "l4padrio.h"
|
|
|
|
#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;
|
|
}
|
|
}
|
|
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;
|
|
|
|
{
|
|
// BT412 diagnostic (BT_STICK_LOG=1): trace the RIO stick push.
|
|
static const int s_stickLog = (getenv("BT_STICK_LOG") != 0);
|
|
if (s_stickLog && (stick.x != (Scalar)0 || stick.y != (Scalar)0))
|
|
{
|
|
DEBUG_STREAM << "[stick-push] x=" << (float)stick.x
|
|
<< " y=" << (float)stick.y << "\n" << std::flush;
|
|
}
|
|
}
|
|
|
|
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;
|
|
//
|
|
// BT port fix: for WM_KEYUP this wParam is a VIRTUAL-KEY code, not a
|
|
// character, but every consumer (Application::KeyCommandMessageHandler
|
|
// and friends) compares against typed CHARACTERS. The navigation
|
|
// block VK_PRIOR..VK_DELETE (0x21-0x2E: PgUp/PgDn/End/Home/arrows/
|
|
// Insert/Delete) collides with the '!'..'.' hotkey characters --
|
|
// releasing the UP ARROW (VK_UP==0x26=='&') silently killed the
|
|
// mission via the '&' stop command. Drop non-character keyups;
|
|
// deliberately TYPED hotkeys still arrive via WM_CHAR.
|
|
//
|
|
if (msg.message == WM_KEYUP
|
|
&& msg.wParam >= VK_PRIOR && msg.wParam <= VK_DELETE)
|
|
{
|
|
// swallowed: navigation key, not a character command
|
|
}
|
|
else
|
|
{
|
|
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();
|
|
// DEV-COMPOSITE GUARD: when the gauge renderer is woken (BT_DEV_GAUGES) but its
|
|
// reconstructed lamp manager isn't wired (GetLampManager returns NULL -- a recon
|
|
// offset gap in BTL4GaugeRenderer), skip the linked cockpit lamp rather than
|
|
// constructing an L4Lamp with a NULL manager (crashes in LampManager::AddLamp).
|
|
// The lamp is a secondary cockpit indicator; inert on the pod (manager valid).
|
|
if (lamp_manager == NULL)
|
|
return NULL;
|
|
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);
|
|
{
|
|
// BT412 diagnostic (BT_CTRLMAP_LOG=1): dump each streamed
|
|
// mapping as it installs -- group/element/attribute/mask.
|
|
static const int s_mapLog = (getenv("BT_CTRLMAP_LOG") != 0);
|
|
if (s_mapLog)
|
|
{
|
|
DEBUG_STREAM << "[ctrlmap] direct grp=" << (int)mapping->controlsGroup
|
|
<< " elem=" << element
|
|
<< " attrID=" << (int)mapping->attributeID
|
|
<< " mask=" << (unsigned)mode_mask
|
|
<< " ptr=" << attribute << "\n" << std::flush;
|
|
}
|
|
}
|
|
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
|