Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
911 lines
20 KiB
C++
911 lines
20 KiB
C++
#pragma once
|
|
|
|
#include "style.h"
|
|
|
|
class Controls;
|
|
class ControlsInstance;
|
|
class ControlsMappingGroup;
|
|
struct ControlsMapping;
|
|
class ControlsOwner;
|
|
class ControlsManager;
|
|
|
|
#include "slot.h"
|
|
#include "chain.h"
|
|
#include "vector2d.h"
|
|
#include "receiver.h"
|
|
#include "simulate.h"
|
|
#include "mode.h"
|
|
|
|
//########################################################################
|
|
//######################## Basic control typedefs ########################
|
|
//########################################################################
|
|
|
|
typedef Scalar ControlsScalar;
|
|
typedef Vector2DOf<Scalar> ControlsJoystick;
|
|
typedef int ControlsKey;
|
|
typedef int ControlsButton; // negative for release
|
|
typedef Vector2DOf<int> ControlsMouse;
|
|
|
|
//#########################################################################
|
|
//######################### ControlsInstance ##############################
|
|
//#########################################################################
|
|
|
|
// The ControlsInstance object exists to serve the ControlsMappingGroup
|
|
// object. It maintains one instance of a mapping from a physical
|
|
// input device to either an entity event message or a value.
|
|
|
|
class ControlsInstance :
|
|
public Node
|
|
{
|
|
friend class ControlsMappingGroup;
|
|
friend class ControlsManager; // required for testing
|
|
friend class L4MappableButtonManager;
|
|
|
|
public:
|
|
ControlsInstance(
|
|
ClassID class_id,
|
|
ModeMask mode_mask,
|
|
Plug *dependant
|
|
);
|
|
~ControlsInstance();
|
|
|
|
ModeMask
|
|
modeMask; // lots of objects (and templates) need access to this
|
|
|
|
protected:
|
|
virtual void Update(void *data_source);
|
|
|
|
SlotOf<Plug*>
|
|
dependantPlug;
|
|
void
|
|
ReleaseLinkHandler(
|
|
Socket *socket,
|
|
Plug *plug
|
|
);
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ControlsInstanceDirectOf ~~~~~~~~~~~~~~~~~~
|
|
|
|
template <class T> class ControlsInstanceDirectOf:
|
|
public ControlsInstance
|
|
{
|
|
friend class ControlsMappingGroup;
|
|
friend class ControlsManager; // required for testing
|
|
|
|
public:
|
|
ControlsInstanceDirectOf(
|
|
ModeMask mode_mask,
|
|
T* data_pointer,
|
|
Plug *dependant
|
|
);
|
|
ControlsInstanceDirectOf(
|
|
ControlsInstanceDirectOf<T> *original
|
|
);
|
|
~ControlsInstanceDirectOf();
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
// protected:
|
|
void Update(void *data_source);
|
|
|
|
T *dataPointer;
|
|
};
|
|
|
|
template <class T> ControlsInstanceDirectOf<T>::ControlsInstanceDirectOf(
|
|
ModeMask mode_mask,
|
|
T* data,
|
|
Plug *dependant
|
|
):
|
|
ControlsInstance(
|
|
DirectControlsInstanceClassID,
|
|
mode_mask,
|
|
dependant
|
|
),
|
|
dataPointer(data)
|
|
{}
|
|
|
|
template <class T> ControlsInstanceDirectOf<T>::ControlsInstanceDirectOf(
|
|
ControlsInstanceDirectOf<T> *original
|
|
):
|
|
ControlsInstance(
|
|
DirectControlsInstanceClassID,
|
|
original->modeMask,
|
|
original->dependantPlug.GetCurrent()
|
|
),
|
|
dataPointer(original->dataPointer)
|
|
{}
|
|
|
|
template <class T> ControlsInstanceDirectOf<T>::~ControlsInstanceDirectOf()
|
|
{}
|
|
|
|
template <class T> void
|
|
ControlsInstanceDirectOf<T>::Update(void *data_source)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(data_source);
|
|
Check_Pointer(dataPointer);
|
|
*dataPointer = *(T*)data_source;
|
|
Verify(*dataPointer == *(T*)data_source);
|
|
Check_Fpu();
|
|
}
|
|
|
|
template <class T> Logical
|
|
ControlsInstanceDirectOf<T>::TestInstance() const
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Pointer(dataPointer);
|
|
Check_Fpu();
|
|
return Plug::TestInstance();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ControlsInstanceEventOf ~~~~~~~~~~~~~~~~~~
|
|
|
|
template <class T> class ControlsInstanceEventOf:
|
|
public ControlsInstance
|
|
{
|
|
friend class ControlsMappingGroup;
|
|
friend class ControlsManager; // required for testing
|
|
|
|
public:
|
|
ControlsInstanceEventOf(
|
|
ModeMask mode_mask,
|
|
Receiver *receiver,
|
|
Receiver::MessageID message_id,
|
|
Plug *dependant
|
|
);
|
|
ControlsInstanceEventOf(
|
|
ControlsInstanceEventOf<T> *original
|
|
);
|
|
|
|
~ControlsInstanceEventOf();
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
// protected:
|
|
void Update(void *data_source);
|
|
|
|
Receiver *receiverPointer;
|
|
Receiver::MessageID messageID;
|
|
};
|
|
|
|
template <class T> ControlsInstanceEventOf<T>::ControlsInstanceEventOf(
|
|
ModeMask mode_mask,
|
|
Receiver *receiver,
|
|
Receiver::MessageID message_id,
|
|
Plug *dependant
|
|
):
|
|
ControlsInstance(
|
|
EventControlsInstanceClassID,
|
|
mode_mask,
|
|
dependant
|
|
),
|
|
receiverPointer(receiver),
|
|
messageID(message_id)
|
|
{}
|
|
|
|
template <class T> ControlsInstanceEventOf<T>::ControlsInstanceEventOf(
|
|
ControlsInstanceEventOf<T> *original
|
|
):
|
|
ControlsInstance(
|
|
EventControlsInstanceClassID,
|
|
original->modeMask,
|
|
original->dependantPlug.GetCurrent()
|
|
),
|
|
receiverPointer(original->receiverPointer),
|
|
messageID(original->messageID)
|
|
{}
|
|
|
|
template <class T> ControlsInstanceEventOf<T>::~ControlsInstanceEventOf()
|
|
{}
|
|
|
|
template <class T> void
|
|
ControlsInstanceEventOf<T>::Update(void *data_source)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(data_source);
|
|
Check(application);
|
|
|
|
ReceiverDataMessageOf<T>
|
|
update_message(
|
|
messageID,
|
|
sizeof(ReceiverDataMessageOf<T>),
|
|
*(T*)data_source
|
|
);
|
|
|
|
application->Post(
|
|
ControlsEventPriority,
|
|
receiverPointer,
|
|
&update_message
|
|
);
|
|
}
|
|
|
|
template <class T> Logical
|
|
ControlsInstanceEventOf<T>::TestInstance() const
|
|
{
|
|
Check_Pointer(this);
|
|
Check(receiverPointer);
|
|
Check_Fpu();
|
|
return Plug::TestInstance();
|
|
}
|
|
|
|
//#########################################################################
|
|
//######################### ControlsMappingGroup ##########################
|
|
//#########################################################################
|
|
|
|
// The ControlsMappingGroup object maintains a group of ControlInstances.
|
|
//
|
|
// ControlsMappingGroup.Update() will call ControlsInstance.Update()
|
|
// for each instance in the group.
|
|
|
|
class ControlsMappingGroup :
|
|
public Node
|
|
{
|
|
friend class ControlsManager; // required for testing
|
|
|
|
public:
|
|
ControlsMappingGroup();
|
|
~ControlsMappingGroup();
|
|
|
|
void
|
|
Add(ControlsInstance *mapping)
|
|
{
|
|
Check(this);
|
|
Check(mapping);
|
|
instanceList.Add(mapping);
|
|
}
|
|
|
|
virtual void
|
|
Remove(ModeMask mode_mask);
|
|
|
|
virtual void
|
|
Update(void *value, ModeMask mode_mask);
|
|
|
|
Logical // returns true if at least one button active
|
|
CurrentFilterStatus(ModeMask mode_mask);
|
|
|
|
protected:
|
|
ChainOf<ControlsInstance*>
|
|
instanceList;
|
|
};
|
|
|
|
//#########################################################################
|
|
//########################## ControlsUpdateManager ########################
|
|
//#########################################################################
|
|
|
|
template <class T> class ControlsUpdateManager :
|
|
public ControlsMappingGroup
|
|
{
|
|
public:
|
|
ControlsUpdateManager();
|
|
~ControlsUpdateManager();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
virtual ControlsInstance*
|
|
Add(
|
|
ModeMask mode_mask,
|
|
Receiver *receiver_pointer,
|
|
Receiver::MessageID id,
|
|
Plug *dependant
|
|
);
|
|
|
|
virtual ControlsInstance*
|
|
Add(
|
|
ModeMask mode_mask,
|
|
T *destination,
|
|
Plug *dependant
|
|
);
|
|
|
|
virtual ControlsInstance*
|
|
AddOrErase(
|
|
ModeMask mode_mask,
|
|
Receiver *target,
|
|
Receiver::MessageID message_ID,
|
|
Plug *dependant
|
|
);
|
|
|
|
virtual ControlsInstance*
|
|
AddOrErase(
|
|
ModeMask mode_mask,
|
|
T *destination,
|
|
Plug *dependant
|
|
);
|
|
|
|
enum
|
|
{
|
|
unmapped = 0,
|
|
mappedByOthers = 1,
|
|
mappedByMe = 2
|
|
};
|
|
|
|
virtual int
|
|
GetMapState(
|
|
void *direct_destination,
|
|
Receiver *event_receiver,
|
|
Receiver::MessageID message_id,
|
|
ModeMask mode_mask
|
|
);
|
|
|
|
virtual void
|
|
Update(void *sourcePointer, ModeMask mode_mask);
|
|
|
|
void
|
|
ForceUpdate(T *sourcePointer, ModeMask mode_mask);
|
|
|
|
T
|
|
previousValue;
|
|
};
|
|
|
|
template <class T> Logical
|
|
ControlsUpdateManager<T>::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
template <class T>
|
|
ControlsUpdateManager<T>::ControlsUpdateManager()
|
|
: ControlsMappingGroup()
|
|
{
|
|
}
|
|
|
|
template <class T> ControlsUpdateManager<T>::~ControlsUpdateManager()
|
|
{
|
|
}
|
|
|
|
template <class T> void
|
|
ControlsUpdateManager<T>::Update(
|
|
void * source_pointer,
|
|
ModeMask mode_mask
|
|
)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(source_pointer);
|
|
|
|
if (previousValue != *(T*) source_pointer)
|
|
{
|
|
ForceUpdate((T*)source_pointer, mode_mask);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
template <class T> void
|
|
ControlsUpdateManager<T>::ForceUpdate(
|
|
T* source_pointer,
|
|
ModeMask mode_mask
|
|
)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(source_pointer);
|
|
previousValue = *source_pointer;
|
|
ControlsMappingGroup::Update(source_pointer, mode_mask);
|
|
Check_Fpu();
|
|
}
|
|
|
|
template <class T> ControlsInstance*
|
|
ControlsUpdateManager<T>::Add(
|
|
ModeMask mode_mask,
|
|
Receiver *receiver_pointer,
|
|
Receiver::MessageID message_id,
|
|
Plug *dependant
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(receiver_pointer);
|
|
|
|
ControlsInstanceEventOf<T> *instance =
|
|
new ControlsInstanceEventOf<T>(
|
|
mode_mask,
|
|
receiver_pointer,
|
|
message_id,
|
|
dependant
|
|
);
|
|
Register_Object(instance);
|
|
ControlsMappingGroup::Add(instance);
|
|
Check_Fpu();
|
|
return instance;
|
|
}
|
|
|
|
template <class T> ControlsInstance*
|
|
ControlsUpdateManager<T>::Add(
|
|
ModeMask mode_mask,
|
|
T *destination,
|
|
Plug *dependant
|
|
)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(destination);
|
|
|
|
ControlsInstanceDirectOf<T> *instance =
|
|
new ControlsInstanceDirectOf<T>(
|
|
mode_mask,
|
|
destination,
|
|
dependant
|
|
);
|
|
Register_Object(instance);
|
|
ControlsMappingGroup::Add(instance);
|
|
Check_Fpu();
|
|
return instance;
|
|
}
|
|
|
|
template <class T> ControlsInstance*
|
|
ControlsUpdateManager<T>::AddOrErase(
|
|
ModeMask mode_mask,
|
|
Receiver *receiver_pointer,
|
|
Receiver::MessageID message_id,
|
|
Plug *dependant
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(receiver_pointer);
|
|
|
|
ChainIteratorOf<ControlsInstance*>
|
|
i(instanceList);
|
|
ControlsInstance
|
|
*controls_instance;
|
|
ControlsInstanceEventOf<T>
|
|
*event_mapping;
|
|
|
|
//-----------------------------------------------
|
|
// Search through all mappings
|
|
//-----------------------------------------------
|
|
while ((controls_instance=i.ReadAndNext()) != NULL)
|
|
{
|
|
Check(controls_instance);
|
|
//-----------------------------------------------
|
|
// Process only the event mappings
|
|
//-----------------------------------------------
|
|
if (controls_instance->GetClassID() == EventControlsInstanceClassID)
|
|
{
|
|
event_mapping = (ControlsInstanceEventOf<T> *)controls_instance;
|
|
Check(event_mapping);
|
|
//-----------------------------------------------
|
|
// Process only if the target is correct, AND
|
|
// if the mapping is allowed under the given
|
|
// mode mask
|
|
//-----------------------------------------------
|
|
if (
|
|
(event_mapping->receiverPointer == receiver_pointer) &&
|
|
(event_mapping->messageID == message_id) &&
|
|
(event_mapping->modeMask & mode_mask)
|
|
)
|
|
{
|
|
//-----------------------------------------------
|
|
// Found! Remove mode enable bit(s)
|
|
//-----------------------------------------------
|
|
event_mapping->modeMask &= ~mode_mask;
|
|
//-----------------------------------------------
|
|
// If this mapping no longer matches ANY mode
|
|
// (i.e., all bits cleared), delete it, 'cuz
|
|
// it doesn't do anything anymore.
|
|
//-----------------------------------------------
|
|
if (event_mapping->modeMask == (ModeMask)0)
|
|
{
|
|
Unregister_Object(event_mapping);
|
|
delete event_mapping;
|
|
}
|
|
//-----------------------------------------------
|
|
// We found the match, break out of the loop
|
|
//-----------------------------------------------
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
// If the mapping wasn't found (controls_instance == NULL),
|
|
// then create one.
|
|
//----------------------------------------------------------
|
|
if (controls_instance == NULL)
|
|
{
|
|
event_mapping =
|
|
new ControlsInstanceEventOf<T>(
|
|
mode_mask,
|
|
receiver_pointer,
|
|
message_id,
|
|
dependant
|
|
);
|
|
Register_Object(event_mapping);
|
|
ControlsMappingGroup::Add(event_mapping);
|
|
Check_Fpu();
|
|
return event_mapping;
|
|
}
|
|
Check_Fpu();
|
|
return NULL;
|
|
}
|
|
|
|
template <class T> ControlsInstance*
|
|
ControlsUpdateManager<T>::AddOrErase(
|
|
ModeMask mode_mask,
|
|
T *destination,
|
|
Plug *dependant
|
|
)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(destination);
|
|
|
|
ChainIteratorOf<ControlsInstance*>
|
|
i(instanceList);
|
|
ControlsInstance
|
|
*controls_instance;
|
|
ControlsInstanceDirectOf<T>
|
|
*direct_mapping;
|
|
|
|
//-----------------------------------------------
|
|
// Search through all mappings
|
|
//-----------------------------------------------
|
|
while ((controls_instance=i.ReadAndNext()) != NULL)
|
|
{
|
|
Check(controls_instance);
|
|
//-----------------------------------------------
|
|
// Process only the direct mappings
|
|
//-----------------------------------------------
|
|
if (controls_instance->GetClassID() == DirectControlsInstanceClassID)
|
|
{
|
|
direct_mapping = (ControlsInstanceDirectOf<T> *)controls_instance;
|
|
Check(direct_mapping);
|
|
//-----------------------------------------------
|
|
// Process only if the target is correct, AND
|
|
// if the mapping is allowed under the given
|
|
// mode mask
|
|
//-----------------------------------------------
|
|
if (
|
|
(direct_mapping->dataPointer == destination) &&
|
|
(direct_mapping->modeMask & mode_mask)
|
|
)
|
|
{
|
|
//-----------------------------------------------
|
|
// Found! Remove mode enable bit(s)
|
|
//-----------------------------------------------
|
|
direct_mapping->modeMask &= ~mode_mask;
|
|
//-----------------------------------------------
|
|
// If this mapping no longer matches ANY mode
|
|
// (i.e., all bits cleared), delete it, 'cuz
|
|
// it doesn't do anything anymore.
|
|
//-----------------------------------------------
|
|
if (direct_mapping->modeMask == (ModeMask)0)
|
|
{
|
|
Unregister_Object(direct_mapping);
|
|
delete direct_mapping;
|
|
}
|
|
//-----------------------------------------------
|
|
// We found the match, break out of the loop
|
|
//-----------------------------------------------
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------
|
|
// If the mapping wasn't found (controls_instance == NULL),
|
|
// then create one.
|
|
//----------------------------------------------------------
|
|
if (controls_instance == NULL)
|
|
{
|
|
direct_mapping =
|
|
new ControlsInstanceDirectOf<T>(
|
|
mode_mask,
|
|
destination,
|
|
dependant
|
|
);
|
|
Register_Object(direct_mapping);
|
|
ControlsMappingGroup::Add(direct_mapping);
|
|
Check_Fpu();
|
|
return direct_mapping;
|
|
}
|
|
Check_Fpu();
|
|
return NULL;
|
|
}
|
|
|
|
template <class T> int
|
|
ControlsUpdateManager<T>::GetMapState(
|
|
void *direct_destination,
|
|
Receiver *event_receiver,
|
|
Receiver::MessageID message_id,
|
|
ModeMask mode_mask
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
ChainIteratorOf<ControlsInstance*>
|
|
i(instanceList);
|
|
ControlsInstance
|
|
*controls_instance;
|
|
int
|
|
map_state = 0;
|
|
|
|
//-----------------------------------------------
|
|
// Search through all mappings
|
|
//-----------------------------------------------
|
|
while ((controls_instance=i.ReadAndNext()) != NULL)
|
|
{
|
|
Check(controls_instance);
|
|
//------------------------------------
|
|
// Process if allowed mode
|
|
//------------------------------------
|
|
if (controls_instance->modeMask & mode_mask)
|
|
{
|
|
//------------------------------------
|
|
// Process direct mappings
|
|
//------------------------------------
|
|
if (controls_instance->GetClassID() ==
|
|
DirectControlsInstanceClassID
|
|
)
|
|
{
|
|
ControlsInstanceDirectOf<T>
|
|
*direct_mapping = (ControlsInstanceDirectOf<T> *)
|
|
controls_instance;
|
|
|
|
Check(direct_mapping);
|
|
if (direct_mapping->dataPointer == direct_destination)
|
|
{
|
|
map_state |= mappedByMe;
|
|
}
|
|
else
|
|
{
|
|
map_state |= mappedByOthers;
|
|
}
|
|
}
|
|
//------------------------------------
|
|
// Process event mappings
|
|
//------------------------------------
|
|
else
|
|
{
|
|
Verify(controls_instance->GetClassID() ==
|
|
EventControlsInstanceClassID
|
|
);
|
|
|
|
ControlsInstanceEventOf<T>
|
|
*event_mapping = (ControlsInstanceEventOf<T> *)
|
|
controls_instance;
|
|
|
|
Check(event_mapping);
|
|
if (
|
|
(event_mapping->receiverPointer == event_receiver) &&
|
|
(event_mapping->messageID == message_id)
|
|
)
|
|
{
|
|
map_state |= mappedByMe;
|
|
}
|
|
else
|
|
{
|
|
map_state |= mappedByOthers;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
return map_state;
|
|
}
|
|
|
|
//#########################################################################
|
|
//############################ ControlsManager ############################
|
|
//#########################################################################
|
|
class ControlsManager:
|
|
public Receiver
|
|
{
|
|
friend class ControlsMappingGroup; // for access to groupEnable
|
|
//-------------------------------------------------------------------
|
|
// Shared data support
|
|
//-------------------------------------------------------------------
|
|
public:
|
|
static Derivation *GetClassDerivations();
|
|
// static SharedData DefaultData;
|
|
|
|
//-------------------------------------------------------------------
|
|
// Construction/destruction/verification
|
|
//-------------------------------------------------------------------
|
|
protected:
|
|
ControlsManager(
|
|
ClassID class_ID = ControlsManagerClassID,
|
|
SharedData &shared_data = ControlsManager::DefaultData
|
|
);
|
|
public:
|
|
~ControlsManager();
|
|
|
|
unsigned int
|
|
UniqueOwnerID()
|
|
{
|
|
if ((nextOwnerID+1)==0) { ++nextOwnerID; }
|
|
Check_Fpu();
|
|
return (++nextOwnerID);
|
|
}
|
|
|
|
virtual void
|
|
Remove(ModeMask mode_mask);
|
|
|
|
virtual void
|
|
Execute();
|
|
|
|
static Logical
|
|
TestClass();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
static void
|
|
Shutdown();
|
|
|
|
virtual void
|
|
LocalShutdown();
|
|
|
|
//-------------------------------------------------------------------
|
|
// Mode control
|
|
//-------------------------------------------------------------------
|
|
virtual void
|
|
StartMappableButtonsConfigure(
|
|
void *active_direct_target,
|
|
Receiver *target,
|
|
Plug *dependant,
|
|
Receiver::MessageID active_message_id,
|
|
ModeMask remove_mode_mask,
|
|
ModeMask add_mode_mask
|
|
);
|
|
|
|
virtual void
|
|
StopMappableButtonsConfigure(
|
|
ModeMask remove_mode_mask,
|
|
ModeMask add_mode_mask
|
|
);
|
|
|
|
virtual void
|
|
AddOrEraseMappableButton(
|
|
int button_number,
|
|
ModeMask mode_mask
|
|
);
|
|
//-------------------------------------------------------------------
|
|
// Gauge support
|
|
//-------------------------------------------------------------------
|
|
void
|
|
*activeDestination;
|
|
Receiver
|
|
*activeReceiver;
|
|
Receiver::MessageID
|
|
activeMessageID;
|
|
Plug
|
|
*activeDependant;
|
|
|
|
private:
|
|
static ControlsManager
|
|
*headControlsManager;
|
|
|
|
ControlsManager
|
|
*nextControlsManager;
|
|
|
|
static unsigned int
|
|
nextOwnerID;
|
|
};
|
|
|
|
|
|
//#########################################################################
|
|
//############################ ControlsMapping ############################
|
|
//#########################################################################
|
|
// Used by tools for building/reading control map streams
|
|
struct ControlsMapping
|
|
{
|
|
public:
|
|
enum {
|
|
DirectMapping=0,
|
|
EventMapping=1
|
|
};
|
|
|
|
Enumeration
|
|
controlsGroup,
|
|
controlsElement,
|
|
mappingType,
|
|
subsystemID;
|
|
ModeMask
|
|
modeMask;
|
|
union
|
|
{
|
|
Simulation::AttributeID attributeID;
|
|
Receiver::MessageID messageID;
|
|
};
|
|
};
|
|
|
|
//#########################################################################
|
|
//############################ ControlsString #############################
|
|
//#########################################################################
|
|
|
|
typedef int ControlsStringID;
|
|
|
|
class ControlsString :
|
|
public Node
|
|
{
|
|
friend class ControlsStringManager;
|
|
protected:
|
|
|
|
enum
|
|
{
|
|
maxStringLength=16
|
|
};
|
|
|
|
ControlsString(
|
|
const char *new_string,
|
|
int keypad_unit_number,
|
|
Receiver *receiver_pointer,
|
|
Receiver::MessageID message_id,
|
|
int user_code
|
|
);
|
|
~ControlsString();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
void
|
|
Update(int keypad_unit_number, ControlsKey new_key);
|
|
|
|
ControlsStringID
|
|
id;
|
|
const char
|
|
*matchStringPointer;
|
|
char
|
|
string[maxStringLength+1];
|
|
int
|
|
stringLength,
|
|
keypadUnitNumber,
|
|
userCode;
|
|
Receiver
|
|
*receiverPointer;
|
|
Receiver::MessageID
|
|
messageID;
|
|
|
|
static ControlsStringID
|
|
nextID;
|
|
};
|
|
|
|
|
|
|
|
//#########################################################################
|
|
//######################## ControlsStringMessage ##########################
|
|
//#########################################################################
|
|
// This is sent by the controlsString object when a match is detected
|
|
|
|
class ControlsStringMessage:
|
|
public Receiver::Message
|
|
{
|
|
public:
|
|
ControlsStringMessage(
|
|
Receiver::MessageID message_ID,
|
|
int user_code
|
|
):
|
|
Receiver::Message(message_ID, sizeof(ControlsStringMessage)),
|
|
userCode(user_code)
|
|
{}
|
|
|
|
int
|
|
userCode;
|
|
};
|
|
|
|
//#########################################################################
|
|
//######################## ControlsStringManager ##########################
|
|
//#########################################################################
|
|
// This class matches strings from a keypad. When the given string
|
|
// is matched, it sends an event to the given receiver.
|
|
|
|
class ControlsStringManager :
|
|
public Node
|
|
{
|
|
public:
|
|
ControlsStringManager();
|
|
~ControlsStringManager();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
ControlsStringID
|
|
Add(
|
|
const char *new_string,
|
|
int keypad_unit_number,
|
|
Receiver *receiver_pointer,
|
|
Receiver::MessageID id,
|
|
int user_code = 0
|
|
);
|
|
void
|
|
Remove(ControlsStringID string_id);
|
|
|
|
void
|
|
Update(int keypad_unit_number, ControlsKey new_key);
|
|
|
|
ChainOf<ControlsString*>
|
|
instanceList;
|
|
};
|