diff --git a/CMakeLists.txt b/CMakeLists.txt index 17046915..863f50bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ include_directories(${INCLUDES} ${PCRE_INCLUDE_DIRS}) set(JOYSTICK_SOURCES src/addon.cpp - src/api/AnomalousTriggerFilter.cpp + src/api/AnomalousTrigger.cpp src/api/Joystick.cpp src/api/JoystickAsync.cpp src/api/JoystickInterfaceCallback.cpp diff --git a/src/api/AnomalousTriggerFilter.cpp b/src/api/AnomalousTrigger.cpp similarity index 80% rename from src/api/AnomalousTriggerFilter.cpp rename to src/api/AnomalousTrigger.cpp index e23781eb..b22300d1 100644 --- a/src/api/AnomalousTriggerFilter.cpp +++ b/src/api/AnomalousTrigger.cpp @@ -17,15 +17,15 @@ * . */ -#include "AnomalousTriggerFilter.h" +#include "AnomalousTrigger.h" #include "log/Log.h" using namespace JOYSTICK; #define ANOMOLOUS_MAGNITUDE 0.5f -CAnomalousTriggerFilter::CAnomalousTriggerFilter(unsigned int axisIndex) - : axisIndex(axisIndex), +CAnomalousTrigger::CAnomalousTrigger(unsigned int axisIndex) + : m_axisIndex(axisIndex), m_state(STATE_UNKNOWN), m_center(CENTER_ZERO), m_range(TRIGGER_RANGE_HALF), @@ -35,7 +35,7 @@ CAnomalousTriggerFilter::CAnomalousTriggerFilter(unsigned int axisIndex) { } -float CAnomalousTriggerFilter::Filter(float value) +float CAnomalousTrigger::Filter(float value) { // First, check for discrete D-pad if (m_state == STATE_UNKNOWN) @@ -51,7 +51,7 @@ float CAnomalousTriggerFilter::Filter(float value) if (m_bCenterSeen && m_bPositiveOneSeen && m_bNegativeOneSeen) { m_state = STATE_DISCRETE_DPAD; - dsyslog("Discrete D-pad detected on axis %u", axisIndex); + dsyslog("Discrete D-pad detected on axis %u", m_axisIndex); } } else @@ -71,7 +71,7 @@ float CAnomalousTriggerFilter::Filter(float value) m_center = CENTER_ZERO; if (IsAnomalousTrigger()) - dsyslog("Anomalous trigger detected on axis %u (initial value = %f)", axisIndex, value); + dsyslog("Anomalous trigger detected on axis %u (initial value = %f)", m_axisIndex, value); m_state = STATE_CENTER_KNOWN; } @@ -105,19 +105,31 @@ float CAnomalousTriggerFilter::Filter(float value) return value; } -bool CAnomalousTriggerFilter::IsAnomalousTrigger(void) +bool CAnomalousTrigger::IsAnomalousTrigger(void) const { return m_center != CENTER_ZERO; } -float CAnomalousTriggerFilter::GetCenter(AXIS_CENTER center) +int CAnomalousTrigger::GetCenter(AXIS_CENTER center) { switch (center) { - case CENTER_NEGATIVE_ONE: return -1.0f; - case CENTER_POSITIVE_ONE: return 1.0f; + case CENTER_NEGATIVE_ONE: return -1; + case CENTER_POSITIVE_ONE: return 1; default: break; } - return 0.0f; + return 0; +} + +int CAnomalousTrigger::GetRange(TRIGGER_RANGE range) +{ + switch (range) + { + case TRIGGER_RANGE_HALF: return 1; + case TRIGGER_RANGE_FULL: return 2; + default: + break; + } + return 1; } diff --git a/src/api/AnomalousTriggerFilter.h b/src/api/AnomalousTrigger.h similarity index 87% rename from src/api/AnomalousTriggerFilter.h rename to src/api/AnomalousTrigger.h index 4b946bfe..d10de676 100644 --- a/src/api/AnomalousTriggerFilter.h +++ b/src/api/AnomalousTrigger.h @@ -45,14 +45,25 @@ namespace JOYSTICK * * Triggers centered about 1.0 are transformed to travel from zero to -1.0. */ - class CAnomalousTriggerFilter : public IJoystickAxisFilter + class CAnomalousTrigger : public IJoystickAxisFilter { public: - CAnomalousTriggerFilter(unsigned int axisIndex); + CAnomalousTrigger(unsigned int axisIndex); // implementation of IJoystickAxisFilter virtual float Filter(float value) override; + /*! + * \brief Has this axis been detected as an anomalous trigger + */ + bool IsAnomalousTrigger(void) const; + + unsigned int AxisIndex(void) const { return m_axisIndex; } + + unsigned int Center(void) const { return GetCenter(m_center); } + + unsigned int Range(void) const { return GetRange(m_range); } + private: enum AXIS_STATE { @@ -95,17 +106,13 @@ namespace JOYSTICK TRIGGER_RANGE_FULL, // trigger value is in the interval [-1.0, 1.0] }; - /*! - * \brief Has this axis been detected as an anomalous trigger - */ - bool IsAnomalousTrigger(void); - /*! * \brief Helper functions */ - static float GetCenter(AXIS_CENTER center); + static int GetCenter(AXIS_CENTER center); + static int GetRange(TRIGGER_RANGE range); - const unsigned int axisIndex; + const unsigned int m_axisIndex; AXIS_STATE m_state; AXIS_CENTER m_center; TRIGGER_RANGE m_range; diff --git a/src/api/Joystick.cpp b/src/api/Joystick.cpp index d2f2d08a..2f32761b 100644 --- a/src/api/Joystick.cpp +++ b/src/api/Joystick.cpp @@ -17,8 +17,8 @@ * . */ -#include "AnomalousTriggerFilter.h" #include "Joystick.h" +#include "AnomalousTrigger.h" #include "log/Log.h" #include "settings/Settings.h" #include "utils/CommonMacros.h" @@ -82,8 +82,9 @@ bool CJoystick::Initialize(void) m_stateBuffer.axes.assign(AxisCount(), 0.0f); // Filter for anomalous triggers + m_axisFilters.reserve(AxisCount()); for (unsigned int i = 0; i < AxisCount(); i++) - m_axisFilters.push_back(new CAnomalousTriggerFilter(i)); + m_axisFilters.push_back(new CAnomalousTrigger(i)); return true; } @@ -137,6 +138,23 @@ bool CJoystick::SendEvent(const ADDON::PeripheralEvent& event) return bHandled; } +std::vector CJoystick::GetAnomalousTriggers() +{ + std::vector result; + + for (IJoystickAxisFilter* filter : m_axisFilters) + { + CAnomalousTrigger* trigger = dynamic_cast(filter); + if (!trigger) + continue; + + if (trigger->IsAnomalousTrigger()) + result.push_back(trigger); + } + + return result; +} + void CJoystick::GetButtonEvents(std::vector& events) { const std::vector& buttons = m_stateBuffer.buttons; diff --git a/src/api/Joystick.h b/src/api/Joystick.h index d0edd522..ed347088 100644 --- a/src/api/Joystick.h +++ b/src/api/Joystick.h @@ -25,6 +25,7 @@ namespace JOYSTICK { + class CAnomalousTrigger; class IJoystickAxisFilter; class CJoystick : public ADDON::Joystick @@ -90,6 +91,8 @@ namespace JOYSTICK */ virtual void PowerOff() { } + std::vector GetAnomalousTriggers(); + protected: /*! * Implemented by derived class to scan for events diff --git a/src/api/JoystickManager.cpp b/src/api/JoystickManager.cpp index 2bda5a93..ab2e9e80 100644 --- a/src/api/JoystickManager.cpp +++ b/src/api/JoystickManager.cpp @@ -219,6 +219,24 @@ JoystickPtr CJoystickManager::GetJoystick(unsigned int index) const return JoystickPtr(); } +JoystickVector CJoystickManager::GetJoysticks(const ADDON::Joystick& joystickInfo) const +{ + JoystickVector result; + + CLockObject lock(m_joystickMutex); + + for (const auto& joystick : m_joysticks) + { + if (joystick->Name() == joystickInfo.Name() && + joystick->Provider() == joystickInfo.Provider()) + { + result.push_back(joystick); + } + } + + return result; +} + bool CJoystickManager::GetEvents(std::vector& events) { CLockObject lock(m_joystickMutex); diff --git a/src/api/JoystickManager.h b/src/api/JoystickManager.h index 8af98be5..69f0c626 100644 --- a/src/api/JoystickManager.h +++ b/src/api/JoystickManager.h @@ -74,6 +74,8 @@ namespace JOYSTICK JoystickPtr GetJoystick(unsigned int index) const; + JoystickVector GetJoysticks(const ADDON::Joystick& joystickInfo) const; + /*! * \brief Get all events that have occurred since the last call to GetEvents() */ diff --git a/src/storage/xml/ButtonMapDefinitions.h b/src/storage/xml/ButtonMapDefinitions.h index 332f6bcf..b069e2e5 100644 --- a/src/storage/xml/ButtonMapDefinitions.h +++ b/src/storage/xml/ButtonMapDefinitions.h @@ -21,6 +21,8 @@ #define BUTTONMAP_XML_ROOT "buttonmap" #define BUTTONMAP_XML_ELEM_DEVICE "device" +#define BUTTONMAP_XML_ELEM_CONFIGURATION "configuration" +#define BUTTONMAP_XML_ELEM_AXIS "axis" #define BUTTONMAP_XML_ELEM_CONTROLLER "controller" #define BUTTONMAP_XML_ELEM_FEATURE "feature" @@ -50,3 +52,7 @@ #define BUTTONMAP_XML_ATTR_FEATURE_HAT "hat" #define BUTTONMAP_XML_ATTR_FEATURE_AXIS "axis" #define BUTTONMAP_XML_ATTR_FEATURE_MOTOR "motor" + +#define BUTTONMAP_XML_ATTR_AXIS_INDEX "index" +#define BUTTONMAP_XML_ATTR_AXIS_CENTER "center" +#define BUTTONMAP_XML_ATTR_AXIS_RANGE "range" diff --git a/src/storage/xml/ButtonMapXml.cpp b/src/storage/xml/ButtonMapXml.cpp index ff0e3e3c..b04b971d 100644 --- a/src/storage/xml/ButtonMapXml.cpp +++ b/src/storage/xml/ButtonMapXml.cpp @@ -21,12 +21,16 @@ #include "ButtonMapXml.h" #include "ButtonMapDefinitions.h" #include "DeviceXml.h" +#include "api/AnomalousTrigger.h" +#include "api/Joystick.h" +#include "api/JoystickManager.h" #include "buttonmapper/ButtonMapTranslator.h" #include "storage/Device.h" #include "log/Log.h" #include "tinyxml.h" +#include #include #include #include @@ -145,12 +149,68 @@ bool CButtonMapXml::Save(void) const CDeviceXml::Serialize(*m_device, deviceElem); + if (!SerializeTriggers(deviceElem)) + return false; + if (!SerializeButtonMaps(deviceElem)) return false; return xmlFile.SaveFile(m_strResourcePath); } +bool CButtonMapXml::SerializeTriggers(TiXmlElement* pElement) const +{ + std::map triggers; + + // Get triggers + JoystickVector joysticks = CJoystickManager::Get().GetJoysticks(*m_device); + for (const auto& joystick : joysticks) + { + std::vector triggerVec = joystick->GetAnomalousTriggers(); + for (CAnomalousTrigger* trigger : triggerVec) + triggers[trigger->AxisIndex()] = trigger; + } + + // Serialize triggers + if (!triggers.empty()) + { + TiXmlElement configurationElement(BUTTONMAP_XML_ELEM_CONFIGURATION); + TiXmlNode* configurationNode = pElement->InsertEndChild(configurationElement); + if (configurationNode == nullptr) + return false; + + TiXmlElement* configurationElem = configurationNode->ToElement(); + if (configurationElem == nullptr) + return false; + + for (auto itTrigger = triggers.begin(); itTrigger != triggers.end(); ++itTrigger) + { + if (!SerializeTrigger(configurationElem, itTrigger->second)) + return false; + } + } + + return true; +} + +bool CButtonMapXml::SerializeTrigger(TiXmlElement* pElement, const CAnomalousTrigger* trigger) +{ + TiXmlElement axisElement(BUTTONMAP_XML_ELEM_AXIS); + TiXmlNode* axisNode = pElement->InsertEndChild(axisElement); + if (axisNode == nullptr) + return false; + + TiXmlElement* axisElem = axisNode->ToElement(); + if (axisElem == nullptr) + return false; + + axisElem->SetAttribute(BUTTONMAP_XML_ATTR_AXIS_INDEX, trigger->AxisIndex()); + axisElem->SetAttribute(BUTTONMAP_XML_ATTR_AXIS_CENTER, trigger->Center()); + axisElem->SetAttribute(BUTTONMAP_XML_ATTR_AXIS_RANGE, trigger->Range()); + + return true; +} + bool CButtonMapXml::SerializeButtonMaps(TiXmlElement* pElement) const { for (ButtonMap::const_iterator it = m_buttonMap.begin(); it != m_buttonMap.end(); ++it) diff --git a/src/storage/xml/ButtonMapXml.h b/src/storage/xml/ButtonMapXml.h index 0a260670..b87b1067 100644 --- a/src/storage/xml/ButtonMapXml.h +++ b/src/storage/xml/ButtonMapXml.h @@ -33,6 +33,7 @@ namespace ADDON namespace JOYSTICK { + class CAnomalousTrigger; class CButtonMap; class CButtonMapXml : public CButtonMap @@ -50,11 +51,13 @@ namespace JOYSTICK private: bool SerializeButtonMaps(TiXmlElement* pElement) const; + bool SerializeTriggers(TiXmlElement* pElement) const; static bool Serialize(const FeatureVector& features, TiXmlElement* pElement); static bool Deserialize(const TiXmlElement* pElement, FeatureVector& features); static bool IsValid(const ADDON::JoystickFeature& feature); + static bool SerializeTrigger(TiXmlElement* pElement, const CAnomalousTrigger* trigger); static bool SerializeFeature(TiXmlElement* pElement, const ADDON::DriverPrimitive& primitive, const char* tagName); static bool SerializePrimitiveTag(TiXmlElement* pElement, const ADDON::DriverPrimitive& primitive, const char* tagName); static void SerializePrimitive(TiXmlElement* pElement, const ADDON::DriverPrimitive& primitive);