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