diff options
Diffstat (limited to 'xbmc/games/controllers/input')
-rw-r--r-- | xbmc/games/controllers/input/CMakeLists.txt | 11 | ||||
-rw-r--r-- | xbmc/games/controllers/input/InputSink.cpp | 67 | ||||
-rw-r--r-- | xbmc/games/controllers/input/InputSink.h | 53 | ||||
-rw-r--r-- | xbmc/games/controllers/input/PhysicalFeature.cpp | 162 | ||||
-rw-r--r-- | xbmc/games/controllers/input/PhysicalFeature.h | 65 | ||||
-rw-r--r-- | xbmc/games/controllers/input/PhysicalTopology.cpp | 56 | ||||
-rw-r--r-- | xbmc/games/controllers/input/PhysicalTopology.h | 61 |
7 files changed, 475 insertions, 0 deletions
diff --git a/xbmc/games/controllers/input/CMakeLists.txt b/xbmc/games/controllers/input/CMakeLists.txt new file mode 100644 index 0000000..511fa37 --- /dev/null +++ b/xbmc/games/controllers/input/CMakeLists.txt @@ -0,0 +1,11 @@ +set(SOURCES InputSink.cpp + PhysicalFeature.cpp + PhysicalTopology.cpp +) + +set(HEADERS InputSink.h + PhysicalFeature.h + PhysicalTopology.h +) + +core_add_library(games_controller_input) diff --git a/xbmc/games/controllers/input/InputSink.cpp b/xbmc/games/controllers/input/InputSink.cpp new file mode 100644 index 0000000..a48b4b9 --- /dev/null +++ b/xbmc/games/controllers/input/InputSink.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "InputSink.h" + +#include "games/controllers/ControllerIDs.h" + +using namespace KODI; +using namespace GAME; + +CInputSink::CInputSink(JOYSTICK::IInputHandler* gameInput) : m_gameInput(gameInput) +{ +} + +std::string CInputSink::ControllerID(void) const +{ + return DEFAULT_CONTROLLER_ID; +} + +bool CInputSink::AcceptsInput(const std::string& feature) const +{ + return m_gameInput->AcceptsInput(feature); +} + +bool CInputSink::OnButtonPress(const std::string& feature, bool bPressed) +{ + return true; +} + +bool CInputSink::OnButtonMotion(const std::string& feature, + float magnitude, + unsigned int motionTimeMs) +{ + return true; +} + +bool CInputSink::OnAnalogStickMotion(const std::string& feature, + float x, + float y, + unsigned int motionTimeMs) +{ + return true; +} + +bool CInputSink::OnAccelerometerMotion(const std::string& feature, float x, float y, float z) +{ + return true; +} + +bool CInputSink::OnWheelMotion(const std::string& feature, + float position, + unsigned int motionTimeMs) +{ + return true; +} + +bool CInputSink::OnThrottleMotion(const std::string& feature, + float position, + unsigned int motionTimeMs) +{ + return true; +} diff --git a/xbmc/games/controllers/input/InputSink.h b/xbmc/games/controllers/input/InputSink.h new file mode 100644 index 0000000..5dc331f --- /dev/null +++ b/xbmc/games/controllers/input/InputSink.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "input/joysticks/interfaces/IInputHandler.h" + +namespace KODI +{ +namespace GAME +{ +class CGameClient; + +class CInputSink : public JOYSTICK::IInputHandler +{ +public: + explicit CInputSink(JOYSTICK::IInputHandler* gameInput); + + ~CInputSink() override = default; + + // Implementation of IInputHandler + std::string ControllerID() const override; + bool HasFeature(const std::string& feature) const override { return true; } + bool AcceptsInput(const std::string& feature) const override; + bool OnButtonPress(const std::string& feature, bool bPressed) override; + void OnButtonHold(const std::string& feature, unsigned int holdTimeMs) override {} + bool OnButtonMotion(const std::string& feature, + float magnitude, + unsigned int motionTimeMs) override; + bool OnAnalogStickMotion(const std::string& feature, + float x, + float y, + unsigned int motionTimeMs) override; + bool OnAccelerometerMotion(const std::string& feature, float x, float y, float z) override; + bool OnWheelMotion(const std::string& feature, + float position, + unsigned int motionTimeMs) override; + bool OnThrottleMotion(const std::string& feature, + float position, + unsigned int motionTimeMs) override; + void OnInputFrame() override {} + +private: + // Construction parameters + JOYSTICK::IInputHandler* m_gameInput; +}; +} // namespace GAME +} // namespace KODI diff --git a/xbmc/games/controllers/input/PhysicalFeature.cpp b/xbmc/games/controllers/input/PhysicalFeature.cpp new file mode 100644 index 0000000..24e0c41 --- /dev/null +++ b/xbmc/games/controllers/input/PhysicalFeature.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PhysicalFeature.h" + +#include "games/controllers/Controller.h" +#include "games/controllers/ControllerDefinitions.h" +#include "games/controllers/ControllerTranslator.h" +#include "guilib/LocalizeStrings.h" +#include "utils/XMLUtils.h" +#include "utils/log.h" + +#include <sstream> + +using namespace KODI; +using namespace GAME; +using namespace JOYSTICK; + +CPhysicalFeature::CPhysicalFeature(int labelId) +{ + Reset(); + m_labelId = labelId; +} + +void CPhysicalFeature::Reset(void) +{ + *this = CPhysicalFeature(); +} + +CPhysicalFeature& CPhysicalFeature::operator=(const CPhysicalFeature& rhs) +{ + if (this != &rhs) + { + m_controller = rhs.m_controller; + m_type = rhs.m_type; + m_category = rhs.m_category; + m_categoryLabelId = rhs.m_categoryLabelId; + m_strName = rhs.m_strName; + m_labelId = rhs.m_labelId; + m_inputType = rhs.m_inputType; + m_keycode = rhs.m_keycode; + } + return *this; +} + +std::string CPhysicalFeature::CategoryLabel() const +{ + std::string categoryLabel; + + if (m_categoryLabelId >= 0 && m_controller != nullptr) + categoryLabel = g_localizeStrings.GetAddonString(m_controller->ID(), m_categoryLabelId); + + if (categoryLabel.empty()) + categoryLabel = g_localizeStrings.Get(m_categoryLabelId); + + return categoryLabel; +} + +std::string CPhysicalFeature::Label() const +{ + std::string label; + + if (m_labelId >= 0 && m_controller != nullptr) + label = g_localizeStrings.GetAddonString(m_controller->ID(), m_labelId); + + if (label.empty()) + label = g_localizeStrings.Get(m_labelId); + + return label; +} + +bool CPhysicalFeature::Deserialize(const TiXmlElement* pElement, + const CController* controller, + FEATURE_CATEGORY category, + int categoryLabelId) +{ + Reset(); + + if (!pElement) + return false; + + std::string strType(pElement->Value()); + + // Type + m_type = CControllerTranslator::TranslateFeatureType(strType); + if (m_type == FEATURE_TYPE::UNKNOWN) + { + CLog::Log(LOGDEBUG, "Invalid feature: <{}> ", pElement->Value()); + return false; + } + + // Cagegory was obtained from parent XML node + m_category = category; + m_categoryLabelId = categoryLabelId; + + // Name + m_strName = XMLUtils::GetAttribute(pElement, LAYOUT_XML_ATTR_FEATURE_NAME); + if (m_strName.empty()) + { + CLog::Log(LOGERROR, "<{}> tag has no \"{}\" attribute", strType, LAYOUT_XML_ATTR_FEATURE_NAME); + return false; + } + + // Label ID + std::string strLabel = XMLUtils::GetAttribute(pElement, LAYOUT_XML_ATTR_FEATURE_LABEL); + if (strLabel.empty()) + CLog::Log(LOGDEBUG, "<{}> tag has no \"{}\" attribute", strType, LAYOUT_XML_ATTR_FEATURE_LABEL); + else + std::istringstream(strLabel) >> m_labelId; + + // Input type + if (m_type == FEATURE_TYPE::SCALAR) + { + std::string strInputType = XMLUtils::GetAttribute(pElement, LAYOUT_XML_ATTR_INPUT_TYPE); + if (strInputType.empty()) + { + CLog::Log(LOGERROR, "<{}> tag has no \"{}\" attribute", strType, LAYOUT_XML_ATTR_INPUT_TYPE); + return false; + } + else + { + m_inputType = CControllerTranslator::TranslateInputType(strInputType); + if (m_inputType == INPUT_TYPE::UNKNOWN) + { + CLog::Log(LOGERROR, "<{}> tag - attribute \"{}\" is invalid: \"{}\"", strType, + LAYOUT_XML_ATTR_INPUT_TYPE, strInputType); + return false; + } + } + } + + // Keycode + if (m_type == FEATURE_TYPE::KEY) + { + std::string strSymbol = XMLUtils::GetAttribute(pElement, LAYOUT_XML_ATTR_KEY_SYMBOL); + if (strSymbol.empty()) + { + CLog::Log(LOGERROR, "<{}> tag has no \"{}\" attribute", strType, LAYOUT_XML_ATTR_KEY_SYMBOL); + return false; + } + else + { + m_keycode = CControllerTranslator::TranslateKeysym(strSymbol); + if (m_keycode == XBMCK_UNKNOWN) + { + CLog::Log(LOGERROR, "<{}> tag - attribute \"{}\" is invalid: \"{}\"", strType, + LAYOUT_XML_ATTR_KEY_SYMBOL, strSymbol); + return false; + } + } + } + + // Save controller for string translation + m_controller = controller; + + return true; +} diff --git a/xbmc/games/controllers/input/PhysicalFeature.h b/xbmc/games/controllers/input/PhysicalFeature.h new file mode 100644 index 0000000..6319a63 --- /dev/null +++ b/xbmc/games/controllers/input/PhysicalFeature.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "games/controllers/ControllerTypes.h" +#include "input/joysticks/JoystickTypes.h" +#include "input/keyboard/KeyboardTypes.h" + +#include <string> + +class TiXmlElement; + +namespace KODI +{ +namespace GAME +{ + +class CPhysicalFeature +{ +public: + CPhysicalFeature() = default; + CPhysicalFeature(int labelId); + CPhysicalFeature(const CPhysicalFeature& other) { *this = other; } + + void Reset(void); + + CPhysicalFeature& operator=(const CPhysicalFeature& rhs); + + JOYSTICK::FEATURE_TYPE Type(void) const { return m_type; } + JOYSTICK::FEATURE_CATEGORY Category(void) const { return m_category; } + const std::string& Name(void) const { return m_strName; } + + // GUI properties + std::string Label(void) const; + int LabelID(void) const { return m_labelId; } + std::string CategoryLabel(void) const; + + // Input properties + JOYSTICK::INPUT_TYPE InputType(void) const { return m_inputType; } + KEYBOARD::KeySymbol Keycode() const { return m_keycode; } + + bool Deserialize(const TiXmlElement* pElement, + const CController* controller, + JOYSTICK::FEATURE_CATEGORY category, + int categoryLabelId); + +private: + const CController* m_controller = nullptr; // Used for translating addon-specific labels + JOYSTICK::FEATURE_TYPE m_type = JOYSTICK::FEATURE_TYPE::UNKNOWN; + JOYSTICK::FEATURE_CATEGORY m_category = JOYSTICK::FEATURE_CATEGORY::UNKNOWN; + int m_categoryLabelId = -1; + std::string m_strName; + int m_labelId = -1; + JOYSTICK::INPUT_TYPE m_inputType = JOYSTICK::INPUT_TYPE::UNKNOWN; + KEYBOARD::KeySymbol m_keycode = XBMCK_UNKNOWN; +}; + +} // namespace GAME +} // namespace KODI diff --git a/xbmc/games/controllers/input/PhysicalTopology.cpp b/xbmc/games/controllers/input/PhysicalTopology.cpp new file mode 100644 index 0000000..2fecb5a --- /dev/null +++ b/xbmc/games/controllers/input/PhysicalTopology.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PhysicalTopology.h" + +#include "games/controllers/ControllerDefinitions.h" +#include "utils/XMLUtils.h" +#include "utils/log.h" + +#include <utility> + +using namespace KODI; +using namespace GAME; + +CPhysicalTopology::CPhysicalTopology(bool bProvidesInput, std::vector<CPhysicalPort> ports) + : m_bProvidesInput(bProvidesInput), m_ports(std::move(ports)) +{ +} + +void CPhysicalTopology::Reset() +{ + CPhysicalTopology defaultTopology; + *this = std::move(defaultTopology); +} + +bool CPhysicalTopology::Deserialize(const TiXmlElement* pElement) +{ + Reset(); + + if (pElement == nullptr) + return false; + + m_bProvidesInput = (XMLUtils::GetAttribute(pElement, LAYOUT_XML_ATTR_PROVIDES_INPUT) != "false"); + + for (const TiXmlElement* pChild = pElement->FirstChildElement(); pChild != nullptr; + pChild = pChild->NextSiblingElement()) + { + if (pChild->ValueStr() == LAYOUT_XML_ELM_PORT) + { + CPhysicalPort port; + if (port.Deserialize(pChild)) + m_ports.emplace_back(std::move(port)); + } + else + { + CLog::Log(LOGDEBUG, "Unknown physical topology tag: <{}>", pChild->ValueStr()); + } + } + + return true; +} diff --git a/xbmc/games/controllers/input/PhysicalTopology.h b/xbmc/games/controllers/input/PhysicalTopology.h new file mode 100644 index 0000000..c194de8 --- /dev/null +++ b/xbmc/games/controllers/input/PhysicalTopology.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "games/ports/input/PhysicalPort.h" + +#include <vector> + +class TiXmlElement; + +namespace KODI +{ +namespace GAME +{ + +/*! + * \brief Represents the physical topology of controller add-ons + * + * The physical topology of a controller defines how many ports it has and + * whether it can provide player input (hubs like the Super Multitap don't + * provide input). + */ +class CPhysicalTopology +{ +public: + CPhysicalTopology() = default; + CPhysicalTopology(bool bProvidesInput, std::vector<CPhysicalPort> ports); + + void Reset(); + + /*! + * \brief Check if the controller can provide player input + * + * This allows hubs to specify that they provide no input + * + * \return True if the controller can provide player input, false otherwise + */ + bool ProvidesInput() const { return m_bProvidesInput; } + + /*! + * \brief Get a list of ports provided by this controller + * + * \return The ports + */ + const std::vector<CPhysicalPort>& Ports() const { return m_ports; } + + bool Deserialize(const TiXmlElement* pElement); + +private: + bool m_bProvidesInput = true; + std::vector<CPhysicalPort> m_ports; +}; + +} // namespace GAME +} // namespace KODI |