summaryrefslogtreecommitdiffstats
path: root/xbmc/games/controllers/input
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/games/controllers/input')
-rw-r--r--xbmc/games/controllers/input/CMakeLists.txt11
-rw-r--r--xbmc/games/controllers/input/InputSink.cpp67
-rw-r--r--xbmc/games/controllers/input/InputSink.h53
-rw-r--r--xbmc/games/controllers/input/PhysicalFeature.cpp162
-rw-r--r--xbmc/games/controllers/input/PhysicalFeature.h65
-rw-r--r--xbmc/games/controllers/input/PhysicalTopology.cpp56
-rw-r--r--xbmc/games/controllers/input/PhysicalTopology.h61
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