/* * Copyright (C) 2014-2017 Team Kodi * http://kodi.tv * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this Program; see the file COPYING. If not, see * . * */ #pragma once #include "Peripheral.h" #include // Requires c++11 #include #include #include #include #define PERIPHERAL_SAFE_DELETE(x) do { delete (x); (x) = NULL; } while (0) #define PERIPHERAL_SAFE_DELETE_ARRAY(x) do { delete[] (x); (x) = NULL; } while (0) namespace kodi { namespace addon { /*! * Utility class to manipulate arrays of peripheral types. */ template class PeripheralVector { public: static void ToStructs(const std::vector& vecObjects, THE_STRUCT** pStructs) { if (!pStructs) return; if (vecObjects.empty()) { *pStructs = NULL; } else { (*pStructs) = new THE_STRUCT[vecObjects.size()]; for (unsigned int i = 0; i < vecObjects.size(); i++) vecObjects.at(i).ToStruct((*pStructs)[i]); } } static void ToStructs(const std::vector& vecObjects, THE_STRUCT** pStructs) { if (!pStructs) return; if (vecObjects.empty()) { *pStructs = NULL; } else { *pStructs = new THE_STRUCT[vecObjects.size()]; for (unsigned int i = 0; i < vecObjects.size(); i++) vecObjects.at(i)->ToStruct((*pStructs)[i]); } } static void FreeStructs(unsigned int structCount, THE_STRUCT* structs) { if (structs) { for (unsigned int i = 0; i < structCount; i++) THE_CLASS::FreeStruct(structs[i]); } PERIPHERAL_SAFE_DELETE_ARRAY(structs); } }; /*! * ADDON::Peripheral * * Wrapper class providing peripheral information. Classes can extend * Peripheral to inherit peripheral properties. */ class Peripheral { public: Peripheral(PERIPHERAL_TYPE type = PERIPHERAL_TYPE_UNKNOWN, const std::string& strName = "") : m_type(type), m_strName(strName), m_vendorId(0), m_productId(0), m_index(0) { } explicit Peripheral(const PERIPHERAL_INFO& info) : m_type(info.type), m_strName(info.name ? info.name : ""), m_vendorId(info.vendor_id), m_productId(info.product_id), m_index(info.index) { } virtual ~Peripheral(void) = default; PERIPHERAL_TYPE Type(void) const { return m_type; } const std::string& Name(void) const { return m_strName; } uint16_t VendorID(void) const { return m_vendorId; } uint16_t ProductID(void) const { return m_productId; } unsigned int Index(void) const { return m_index; } // Derived property: VID and PID are 0x0000 if unknown bool IsVidPidKnown(void) const { return m_vendorId != 0 || m_productId != 0; } void SetType(PERIPHERAL_TYPE type) { m_type = type; } void SetName(const std::string& strName) { m_strName = strName; } void SetVendorID(uint16_t vendorId) { m_vendorId = vendorId; } void SetProductID(uint16_t productId) { m_productId = productId; } void SetIndex(unsigned int index) { m_index = index; } void ToStruct(PERIPHERAL_INFO& info) const { info.type = m_type; info.name = new char[m_strName.size() + 1]; info.vendor_id = m_vendorId; info.product_id = m_productId; info.index = m_index; std::strcpy(info.name, m_strName.c_str()); } static void FreeStruct(PERIPHERAL_INFO& info) { PERIPHERAL_SAFE_DELETE_ARRAY(info.name); } private: PERIPHERAL_TYPE m_type; std::string m_strName; uint16_t m_vendorId; uint16_t m_productId; unsigned int m_index; }; typedef PeripheralVector Peripherals; /*! * ADDON::PeripheralEvent * * Wrapper class for peripheral events. */ class PeripheralEvent { public: PeripheralEvent(void) : m_event() { } PeripheralEvent(unsigned int peripheralIndex, unsigned int buttonIndex, JOYSTICK_STATE_BUTTON state) : m_event() { SetType(PERIPHERAL_EVENT_TYPE_DRIVER_BUTTON); SetPeripheralIndex(peripheralIndex); SetDriverIndex(buttonIndex); SetButtonState(state); } PeripheralEvent(unsigned int peripheralIndex, unsigned int hatIndex, JOYSTICK_STATE_HAT state) : m_event() { SetType(PERIPHERAL_EVENT_TYPE_DRIVER_HAT); SetPeripheralIndex(peripheralIndex); SetDriverIndex(hatIndex); SetHatState(state); } PeripheralEvent(unsigned int peripheralIndex, unsigned int axisIndex, JOYSTICK_STATE_AXIS state) : m_event() { SetType(PERIPHERAL_EVENT_TYPE_DRIVER_AXIS); SetPeripheralIndex(peripheralIndex); SetDriverIndex(axisIndex); SetAxisState(state); } explicit PeripheralEvent(const PERIPHERAL_EVENT& event) : m_event(event) { } PERIPHERAL_EVENT_TYPE Type(void) const { return m_event.type; } unsigned int PeripheralIndex(void) const { return m_event.peripheral_index; } unsigned int DriverIndex(void) const { return m_event.driver_index; } JOYSTICK_STATE_BUTTON ButtonState(void) const { return m_event.driver_button_state; } JOYSTICK_STATE_HAT HatState(void) const { return m_event.driver_hat_state; } JOYSTICK_STATE_AXIS AxisState(void) const { return m_event.driver_axis_state; } JOYSTICK_STATE_MOTOR MotorState(void) const { return m_event.motor_state; } void SetType(PERIPHERAL_EVENT_TYPE type) { m_event.type = type; } void SetPeripheralIndex(unsigned int index) { m_event.peripheral_index = index; } void SetDriverIndex(unsigned int index) { m_event.driver_index = index; } void SetButtonState(JOYSTICK_STATE_BUTTON state) { m_event.driver_button_state = state; } void SetHatState(JOYSTICK_STATE_HAT state) { m_event.driver_hat_state = state; } void SetAxisState(JOYSTICK_STATE_AXIS state) { m_event.driver_axis_state = state; } void SetMotorState(JOYSTICK_STATE_MOTOR state) { m_event.motor_state = state; } void ToStruct(PERIPHERAL_EVENT& event) const { event = m_event; } static void FreeStruct(PERIPHERAL_EVENT& event) { (void)event; } private: PERIPHERAL_EVENT m_event; }; typedef PeripheralVector PeripheralEvents; /*! * kodi::addon::Joystick * * Wrapper class providing additional joystick information not provided by * ADDON::Peripheral. */ class Joystick : public Peripheral { public: Joystick(const std::string& provider = "", const std::string& strName = "") : Peripheral(PERIPHERAL_TYPE_JOYSTICK, strName), m_provider(provider), m_requestedPort(NO_PORT_REQUESTED), m_buttonCount(0), m_hatCount(0), m_axisCount(0), m_motorCount(0), m_supportsPowerOff(false) { } Joystick(const Joystick& other) { *this = other; } explicit Joystick(const JOYSTICK_INFO& info) : Peripheral(info.peripheral), m_provider(info.provider ? info.provider : ""), m_requestedPort(info.requested_port), m_buttonCount(info.button_count), m_hatCount(info.hat_count), m_axisCount(info.axis_count), m_motorCount(info.motor_count), m_supportsPowerOff(info.supports_poweroff) { } ~Joystick(void) override = default; Joystick& operator=(const Joystick& rhs) { if (this != &rhs) { Peripheral::operator=(rhs); m_provider = rhs.m_provider; m_requestedPort = rhs.m_requestedPort; m_buttonCount = rhs.m_buttonCount; m_hatCount = rhs.m_hatCount; m_axisCount = rhs.m_axisCount; m_motorCount = rhs.m_motorCount; m_supportsPowerOff = rhs.m_supportsPowerOff; } return *this; } const std::string& Provider(void) const { return m_provider; } int RequestedPort(void) const { return m_requestedPort; } unsigned int ButtonCount(void) const { return m_buttonCount; } unsigned int HatCount(void) const { return m_hatCount; } unsigned int AxisCount(void) const { return m_axisCount; } unsigned int MotorCount(void) const { return m_motorCount; } bool SupportsPowerOff(void) const { return m_supportsPowerOff; } // Derived property: Counts are unknown if all are zero bool AreElementCountsKnown(void) const { return m_buttonCount != 0 || m_hatCount != 0 || m_axisCount != 0; } void SetProvider(const std::string& provider) { m_provider = provider; } void SetRequestedPort(int requestedPort) { m_requestedPort = requestedPort; } void SetButtonCount(unsigned int buttonCount) { m_buttonCount = buttonCount; } void SetHatCount(unsigned int hatCount) { m_hatCount = hatCount; } void SetAxisCount(unsigned int axisCount) { m_axisCount = axisCount; } void SetMotorCount(unsigned int motorCount) { m_motorCount = motorCount; } void SetSupportsPowerOff(bool supportsPowerOff) { m_supportsPowerOff = supportsPowerOff; } void ToStruct(JOYSTICK_INFO& info) const { Peripheral::ToStruct(info.peripheral); info.provider = new char[m_provider.size() + 1]; info.requested_port = m_requestedPort; info.button_count = m_buttonCount; info.hat_count = m_hatCount; info.axis_count = m_axisCount; info.motor_count = m_motorCount; info.supports_poweroff = m_supportsPowerOff; std::strcpy(info.provider, m_provider.c_str()); } static void FreeStruct(JOYSTICK_INFO& info) { Peripheral::FreeStruct(info.peripheral); PERIPHERAL_SAFE_DELETE_ARRAY(info.provider); } private: std::string m_provider; int m_requestedPort; unsigned int m_buttonCount; unsigned int m_hatCount; unsigned int m_axisCount; unsigned int m_motorCount; bool m_supportsPowerOff; }; typedef PeripheralVector Joysticks; /*! * ADDON::DriverPrimitive * * Base class for joystick driver primitives. A driver primitive can be: * * 1) a button * 2) a hat direction * 3) a semiaxis (either the positive or negative half of an axis) * 4) a motor * * The type determines the fields in use: * * Button: * - driver index * * Hat direction: * - driver index * - hat direction * * Semiaxis: * - driver index * - center * - semiaxis direction * - range * * Motor: * - driver index */ struct DriverPrimitive { protected: /*! * \brief Construct a driver primitive of the specified type */ DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE type, unsigned int driverIndex) : m_type(type), m_driverIndex(driverIndex), m_hatDirection(JOYSTICK_DRIVER_HAT_UNKNOWN), m_center(0), m_semiAxisDirection(JOYSTICK_DRIVER_SEMIAXIS_UNKNOWN), m_range(1) { } public: /*! * \brief Construct an invalid driver primitive */ DriverPrimitive(void) : m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_UNKNOWN), m_driverIndex(0), m_hatDirection(JOYSTICK_DRIVER_HAT_UNKNOWN), m_center(0), m_semiAxisDirection(JOYSTICK_DRIVER_SEMIAXIS_UNKNOWN), m_range(1) { } /*! * \brief Construct a driver primitive representing a button */ static DriverPrimitive CreateButton(unsigned int buttonIndex) { return DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON, buttonIndex); } /*! * \brief Construct a driver primitive representing one of the four direction * arrows on a dpad */ DriverPrimitive(unsigned int hatIndex, JOYSTICK_DRIVER_HAT_DIRECTION direction) : m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION), m_driverIndex(hatIndex), m_hatDirection(direction), m_center(0), m_semiAxisDirection(JOYSTICK_DRIVER_SEMIAXIS_UNKNOWN), m_range(1) { } /*! * \brief Construct a driver primitive representing the positive or negative * half of an axis */ DriverPrimitive(unsigned int axisIndex, int center, JOYSTICK_DRIVER_SEMIAXIS_DIRECTION direction, unsigned int range) : m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS), m_driverIndex(axisIndex), m_hatDirection(JOYSTICK_DRIVER_HAT_UNKNOWN), m_center(center), m_semiAxisDirection(direction), m_range(range) { } /*! * \brief Construct a driver primitive representing a motor */ static DriverPrimitive CreateMotor(unsigned int motorIndex) { return DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR, motorIndex); } explicit DriverPrimitive(const JOYSTICK_DRIVER_PRIMITIVE& primitive) : m_type(primitive.type), m_driverIndex(0), m_hatDirection(JOYSTICK_DRIVER_HAT_UNKNOWN), m_center(0), m_semiAxisDirection(JOYSTICK_DRIVER_SEMIAXIS_UNKNOWN), m_range(1) { switch (m_type) { case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: { m_driverIndex = primitive.button.index; break; } case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: { m_driverIndex = primitive.hat.index; m_hatDirection = primitive.hat.direction; break; } case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: { m_driverIndex = primitive.semiaxis.index; m_center = primitive.semiaxis.center; m_semiAxisDirection = primitive.semiaxis.direction; m_range = primitive.semiaxis.range; break; } case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: { m_driverIndex = primitive.motor.index; break; } default: break; } } JOYSTICK_DRIVER_PRIMITIVE_TYPE Type(void) const { return m_type; } unsigned int DriverIndex(void) const { return m_driverIndex; } JOYSTICK_DRIVER_HAT_DIRECTION HatDirection(void) const { return m_hatDirection; } int Center(void) const { return m_center; } JOYSTICK_DRIVER_SEMIAXIS_DIRECTION SemiAxisDirection(void) const { return m_semiAxisDirection; } unsigned int Range(void) const { return m_range; } bool operator==(const DriverPrimitive& other) const { if (m_type == other.m_type) { switch (m_type) { case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: { return m_driverIndex == other.m_driverIndex; } case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: { return m_driverIndex == other.m_driverIndex && m_hatDirection == other.m_hatDirection; } case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: { return m_driverIndex == other.m_driverIndex && m_center == other.m_center && m_semiAxisDirection == other.m_semiAxisDirection && m_range == other.m_range; } default: break; } } return false; } void ToStruct(JOYSTICK_DRIVER_PRIMITIVE& driver_primitive) const { driver_primitive.type = m_type; switch (m_type) { case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: { driver_primitive.button.index = m_driverIndex; break; } case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: { driver_primitive.hat.index = m_driverIndex; driver_primitive.hat.direction = m_hatDirection; break; } case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: { driver_primitive.semiaxis.index = m_driverIndex; driver_primitive.semiaxis.center = m_center; driver_primitive.semiaxis.direction = m_semiAxisDirection; driver_primitive.semiaxis.range = m_range; break; } case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: { driver_primitive.motor.index = m_driverIndex; break; } default: break; } } static void FreeStruct(JOYSTICK_DRIVER_PRIMITIVE& primitive) { (void)primitive; } private: JOYSTICK_DRIVER_PRIMITIVE_TYPE m_type; unsigned int m_driverIndex; JOYSTICK_DRIVER_HAT_DIRECTION m_hatDirection; int m_center; JOYSTICK_DRIVER_SEMIAXIS_DIRECTION m_semiAxisDirection; unsigned int m_range; }; typedef PeripheralVector DriverPrimitives; /*! * kodi::addon::JoystickFeature * * Class for joystick features. A feature can be: * * 1) scalar[1] * 2) analog stick * 3) accelerometer * 4) motor * 5) relative pointer[2] * * [1] All three driver primitives (buttons, hats and axes) have a state that * can be represented using a single scalar value. For this reason, * features that map to a single primitive are called "scalar features". * * [2] Relative pointers are similar to analog sticks, but they use * relative distances instead of positions. */ class JoystickFeature { public: JoystickFeature(const std::string& name = "", JOYSTICK_FEATURE_TYPE type = JOYSTICK_FEATURE_TYPE_UNKNOWN) : m_name(name), m_type(type), m_primitives() { } JoystickFeature(const JoystickFeature& other) { *this = other; } explicit JoystickFeature(const JOYSTICK_FEATURE& feature) : m_name(feature.name ? feature.name : ""), m_type(feature.type) { for (unsigned int i = 0; i < JOYSTICK_PRIMITIVE_MAX; i++) m_primitives[i] = DriverPrimitive(feature.primitives[i]); } JoystickFeature& operator=(const JoystickFeature& rhs) { if (this != &rhs) { m_name = rhs.m_name; m_type = rhs.m_type; m_primitives = rhs.m_primitives; } return *this; } bool operator==(const JoystickFeature& other) const { return m_name == other.m_name && m_type == other.m_type && m_primitives == other.m_primitives; } const std::string& Name(void) const { return m_name; } JOYSTICK_FEATURE_TYPE Type(void) const { return m_type; } bool IsValid() const { return m_type != JOYSTICK_FEATURE_TYPE_UNKNOWN; } void SetName(const std::string& name) { m_name = name; } void SetType(JOYSTICK_FEATURE_TYPE type) { m_type = type; } void SetInvalid(void) { m_type = JOYSTICK_FEATURE_TYPE_UNKNOWN; } const DriverPrimitive& Primitive(JOYSTICK_FEATURE_PRIMITIVE which) const { return m_primitives[which]; } void SetPrimitive(JOYSTICK_FEATURE_PRIMITIVE which, const DriverPrimitive& primitive) { m_primitives[which] = primitive; } std::array& Primitives() { return m_primitives; } const std::array& Primitives() const { return m_primitives; } void ToStruct(JOYSTICK_FEATURE& feature) const { feature.name = new char[m_name.length() + 1]; feature.type = m_type; for (unsigned int i = 0; i < JOYSTICK_PRIMITIVE_MAX; i++) m_primitives[i].ToStruct(feature.primitives[i]); std::strcpy(feature.name, m_name.c_str()); } static void FreeStruct(JOYSTICK_FEATURE& feature) { PERIPHERAL_SAFE_DELETE_ARRAY(feature.name); } private: std::string m_name; JOYSTICK_FEATURE_TYPE m_type; std::array m_primitives; }; typedef PeripheralVector JoystickFeatures; } /* namespace addon */ } /* namespace kodi */