#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 ControlsJoystick; typedef int ControlsKey; typedef int ControlsButton; // negative for release typedef Vector2DOf 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 dependantPlug; void ReleaseLinkHandler( Socket *socket, Plug *plug ); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ControlsInstanceDirectOf ~~~~~~~~~~~~~~~~~~ template 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 *original ); ~ControlsInstanceDirectOf(); Logical TestInstance() const; // protected: void Update(void *data_source); T *dataPointer; }; template ControlsInstanceDirectOf::ControlsInstanceDirectOf( ModeMask mode_mask, T* data, Plug *dependant ): ControlsInstance( DirectControlsInstanceClassID, mode_mask, dependant ), dataPointer(data) {} template ControlsInstanceDirectOf::ControlsInstanceDirectOf( ControlsInstanceDirectOf *original ): ControlsInstance( DirectControlsInstanceClassID, original->modeMask, original->dependantPlug.GetCurrent() ), dataPointer(original->dataPointer) {} template ControlsInstanceDirectOf::~ControlsInstanceDirectOf() {} template void ControlsInstanceDirectOf::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 Logical ControlsInstanceDirectOf::TestInstance() const { Check_Pointer(this); Check_Pointer(dataPointer); Check_Fpu(); return Plug::TestInstance(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ControlsInstanceEventOf ~~~~~~~~~~~~~~~~~~ template 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 *original ); ~ControlsInstanceEventOf(); Logical TestInstance() const; // protected: void Update(void *data_source); Receiver *receiverPointer; Receiver::MessageID messageID; }; template ControlsInstanceEventOf::ControlsInstanceEventOf( ModeMask mode_mask, Receiver *receiver, Receiver::MessageID message_id, Plug *dependant ): ControlsInstance( EventControlsInstanceClassID, mode_mask, dependant ), receiverPointer(receiver), messageID(message_id) {} template ControlsInstanceEventOf::ControlsInstanceEventOf( ControlsInstanceEventOf *original ): ControlsInstance( EventControlsInstanceClassID, original->modeMask, original->dependantPlug.GetCurrent() ), receiverPointer(original->receiverPointer), messageID(original->messageID) {} template ControlsInstanceEventOf::~ControlsInstanceEventOf() {} template void ControlsInstanceEventOf::Update(void *data_source) { Check(this); Check_Pointer(data_source); Check(application); ReceiverDataMessageOf update_message( messageID, sizeof(ReceiverDataMessageOf), *(T*)data_source ); application->Post( ControlsEventPriority, receiverPointer, &update_message ); } template Logical ControlsInstanceEventOf::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 instanceList; }; //######################################################################### //########################## ControlsUpdateManager ######################## //######################################################################### template 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 Logical ControlsUpdateManager::TestInstance() const { return True; } template ControlsUpdateManager::ControlsUpdateManager() : ControlsMappingGroup() { } template ControlsUpdateManager::~ControlsUpdateManager() { } template void ControlsUpdateManager::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 void ControlsUpdateManager::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 ControlsInstance* ControlsUpdateManager::Add( ModeMask mode_mask, Receiver *receiver_pointer, Receiver::MessageID message_id, Plug *dependant ) { Check(this); Check(receiver_pointer); ControlsInstanceEventOf *instance = new ControlsInstanceEventOf( mode_mask, receiver_pointer, message_id, dependant ); Register_Object(instance); ControlsMappingGroup::Add(instance); Check_Fpu(); return instance; } template ControlsInstance* ControlsUpdateManager::Add( ModeMask mode_mask, T *destination, Plug *dependant ) { Check(this); Check_Pointer(destination); ControlsInstanceDirectOf *instance = new ControlsInstanceDirectOf( mode_mask, destination, dependant ); Register_Object(instance); ControlsMappingGroup::Add(instance); Check_Fpu(); return instance; } template ControlsInstance* ControlsUpdateManager::AddOrErase( ModeMask mode_mask, Receiver *receiver_pointer, Receiver::MessageID message_id, Plug *dependant ) { Check(this); Check(receiver_pointer); ChainIteratorOf i(instanceList); ControlsInstance *controls_instance; ControlsInstanceEventOf *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 *)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( 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 ControlsInstance* ControlsUpdateManager::AddOrErase( ModeMask mode_mask, T *destination, Plug *dependant ) { Check(this); Check_Pointer(destination); ChainIteratorOf i(instanceList); ControlsInstance *controls_instance; ControlsInstanceDirectOf *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 *)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( mode_mask, destination, dependant ); Register_Object(direct_mapping); ControlsMappingGroup::Add(direct_mapping); Check_Fpu(); return direct_mapping; } Check_Fpu(); return NULL; } template int ControlsUpdateManager::GetMapState( void *direct_destination, Receiver *event_receiver, Receiver::MessageID message_id, ModeMask mode_mask ) { Check(this); ChainIteratorOf 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 *direct_mapping = (ControlsInstanceDirectOf *) 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 *event_mapping = (ControlsInstanceEventOf *) 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 instanceList; };