summaryrefslogtreecommitdiffstats
path: root/xbmc/games/controllers/guicontrols
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /xbmc/games/controllers/guicontrols
parentInitial commit. (diff)
downloadkodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz
kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/games/controllers/guicontrols')
-rw-r--r--xbmc/games/controllers/guicontrols/CMakeLists.txt28
-rw-r--r--xbmc/games/controllers/guicontrols/GUICardinalFeatureButton.cpp100
-rw-r--r--xbmc/games/controllers/guicontrols/GUICardinalFeatureButton.h49
-rw-r--r--xbmc/games/controllers/guicontrols/GUIControlTypes.h29
-rw-r--r--xbmc/games/controllers/guicontrols/GUIControllerButton.cpp26
-rw-r--r--xbmc/games/controllers/guicontrols/GUIControllerButton.h29
-rw-r--r--xbmc/games/controllers/guicontrols/GUIFeatureButton.cpp86
-rw-r--r--xbmc/games/controllers/guicontrols/GUIFeatureButton.h68
-rw-r--r--xbmc/games/controllers/guicontrols/GUIFeatureControls.cpp36
-rw-r--r--xbmc/games/controllers/guicontrols/GUIFeatureControls.h38
-rw-r--r--xbmc/games/controllers/guicontrols/GUIFeatureFactory.cpp51
-rw-r--r--xbmc/games/controllers/guicontrols/GUIFeatureFactory.h37
-rw-r--r--xbmc/games/controllers/guicontrols/GUIFeatureTranslator.cpp39
-rw-r--r--xbmc/games/controllers/guicontrols/GUIFeatureTranslator.h27
-rw-r--r--xbmc/games/controllers/guicontrols/GUIGameController.cpp64
-rw-r--r--xbmc/games/controllers/guicontrols/GUIGameController.h39
-rw-r--r--xbmc/games/controllers/guicontrols/GUIScalarFeatureButton.cpp59
-rw-r--r--xbmc/games/controllers/guicontrols/GUIScalarFeatureButton.h42
-rw-r--r--xbmc/games/controllers/guicontrols/GUISelectKeyButton.cpp87
-rw-r--r--xbmc/games/controllers/guicontrols/GUISelectKeyButton.h51
-rw-r--r--xbmc/games/controllers/guicontrols/GUIThrottleButton.cpp88
-rw-r--r--xbmc/games/controllers/guicontrols/GUIThrottleButton.h44
-rw-r--r--xbmc/games/controllers/guicontrols/GUIWheelButton.cpp88
-rw-r--r--xbmc/games/controllers/guicontrols/GUIWheelButton.h44
24 files changed, 1249 insertions, 0 deletions
diff --git a/xbmc/games/controllers/guicontrols/CMakeLists.txt b/xbmc/games/controllers/guicontrols/CMakeLists.txt
new file mode 100644
index 0000000..e6babcc
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/CMakeLists.txt
@@ -0,0 +1,28 @@
+set(SOURCES GUICardinalFeatureButton.cpp
+ GUIControllerButton.cpp
+ GUIFeatureButton.cpp
+ GUIFeatureControls.cpp
+ GUIFeatureFactory.cpp
+ GUIFeatureTranslator.cpp
+ GUIGameController.cpp
+ GUIScalarFeatureButton.cpp
+ GUISelectKeyButton.cpp
+ GUIThrottleButton.cpp
+ GUIWheelButton.cpp
+)
+
+set(HEADERS GUICardinalFeatureButton.h
+ GUIControllerButton.h
+ GUIControlTypes.h
+ GUIFeatureButton.h
+ GUIFeatureControls.h
+ GUIFeatureFactory.h
+ GUIFeatureTranslator.h
+ GUIGameController.h
+ GUIScalarFeatureButton.h
+ GUISelectKeyButton.h
+ GUIThrottleButton.h
+ GUIWheelButton.h
+)
+
+core_add_library(games_controller_guicontrols)
diff --git a/xbmc/games/controllers/guicontrols/GUICardinalFeatureButton.cpp b/xbmc/games/controllers/guicontrols/GUICardinalFeatureButton.cpp
new file mode 100644
index 0000000..3c8732c
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUICardinalFeatureButton.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016-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 "GUICardinalFeatureButton.h"
+
+#include "guilib/LocalizeStrings.h"
+
+#include <string>
+
+using namespace KODI;
+using namespace GAME;
+
+CGUICardinalFeatureButton::CGUICardinalFeatureButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index)
+ : CGUIFeatureButton(buttonTemplate, wizard, feature, index)
+{
+ Reset();
+}
+
+bool CGUICardinalFeatureButton::PromptForInput(CEvent& waitEvent)
+{
+ using namespace JOYSTICK;
+
+ bool bInterrupted = false;
+
+ // Get the prompt for the current analog stick direction
+ std::string strPrompt;
+ std::string strWarn;
+ switch (m_state)
+ {
+ case STATE::CARDINAL_DIRECTION_UP:
+ strPrompt = g_localizeStrings.Get(35092); // "Move %s up"
+ strWarn = g_localizeStrings.Get(35093); // "Move %s up (%d)"
+ break;
+ case STATE::CARDINAL_DIRECTION_RIGHT:
+ strPrompt = g_localizeStrings.Get(35096); // "Move %s right"
+ strWarn = g_localizeStrings.Get(35097); // "Move %s right (%d)"
+ break;
+ case STATE::CARDINAL_DIRECTION_DOWN:
+ strPrompt = g_localizeStrings.Get(35094); // "Move %s down"
+ strWarn = g_localizeStrings.Get(35095); // "Move %s down (%d)"
+ break;
+ case STATE::CARDINAL_DIRECTION_LEFT:
+ strPrompt = g_localizeStrings.Get(35098); // "Move %s left"
+ strWarn = g_localizeStrings.Get(35099); // "Move %s left (%d)"
+ break;
+ default:
+ break;
+ }
+
+ if (!strPrompt.empty())
+ {
+ bInterrupted = DoPrompt(strPrompt, strWarn, m_feature.Label(), waitEvent);
+
+ if (!bInterrupted)
+ m_state = STATE::FINISHED; // Not interrupted, must have timed out
+ else
+ m_state = GetNextState(m_state); // Interrupted by input, proceed
+ }
+
+ return bInterrupted;
+}
+
+bool CGUICardinalFeatureButton::IsFinished(void) const
+{
+ return m_state >= STATE::FINISHED;
+}
+
+KODI::INPUT::CARDINAL_DIRECTION CGUICardinalFeatureButton::GetCardinalDirection(void) const
+{
+ using namespace INPUT;
+
+ switch (m_state)
+ {
+ case STATE::CARDINAL_DIRECTION_UP:
+ return CARDINAL_DIRECTION::UP;
+ case STATE::CARDINAL_DIRECTION_RIGHT:
+ return CARDINAL_DIRECTION::RIGHT;
+ case STATE::CARDINAL_DIRECTION_DOWN:
+ return CARDINAL_DIRECTION::DOWN;
+ case STATE::CARDINAL_DIRECTION_LEFT:
+ return CARDINAL_DIRECTION::LEFT;
+ default:
+ break;
+ }
+
+ return CARDINAL_DIRECTION::NONE;
+}
+
+void CGUICardinalFeatureButton::Reset(void)
+{
+ m_state = STATE::CARDINAL_DIRECTION_UP;
+}
diff --git a/xbmc/games/controllers/guicontrols/GUICardinalFeatureButton.h b/xbmc/games/controllers/guicontrols/GUICardinalFeatureButton.h
new file mode 100644
index 0000000..48eb0e8
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUICardinalFeatureButton.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016-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 "GUIFeatureButton.h"
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUICardinalFeatureButton : public CGUIFeatureButton
+{
+public:
+ CGUICardinalFeatureButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index);
+
+ ~CGUICardinalFeatureButton() override = default;
+
+ // implementation of IFeatureButton
+ bool PromptForInput(CEvent& waitEvent) override;
+ bool IsFinished() const override;
+ INPUT::CARDINAL_DIRECTION GetCardinalDirection() const override;
+ void Reset() override;
+
+private:
+ enum class STATE
+ {
+ CARDINAL_DIRECTION_UP,
+ CARDINAL_DIRECTION_RIGHT,
+ CARDINAL_DIRECTION_DOWN,
+ CARDINAL_DIRECTION_LEFT,
+ FINISHED,
+ };
+
+ STATE m_state;
+};
+
+using CGUIAnalogStickButton = CGUICardinalFeatureButton;
+using CGUIRelativePointerButton = CGUICardinalFeatureButton;
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIControlTypes.h b/xbmc/games/controllers/guicontrols/GUIControlTypes.h
new file mode 100644
index 0000000..bf91b6e
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIControlTypes.h
@@ -0,0 +1,29 @@
+/*
+ * 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
+
+namespace KODI
+{
+namespace GAME
+{
+/*!
+ * \brief Types of button controls that can populate the feature list
+ */
+enum class BUTTON_TYPE
+{
+ UNKNOWN,
+ BUTTON,
+ ANALOG_STICK,
+ RELATIVE_POINTER,
+ WHEEL,
+ THROTTLE,
+ SELECT_KEY,
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIControllerButton.cpp b/xbmc/games/controllers/guicontrols/GUIControllerButton.cpp
new file mode 100644
index 0000000..c8156ce
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIControllerButton.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014-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 "GUIControllerButton.h"
+
+#include "games/controllers/windows/GUIControllerDefines.h"
+
+using namespace KODI;
+using namespace GAME;
+
+CGUIControllerButton::CGUIControllerButton(const CGUIButtonControl& buttonControl,
+ const std::string& label,
+ unsigned int index)
+ : CGUIButtonControl(buttonControl)
+{
+ // Initialize CGUIButtonControl
+ SetLabel(label);
+ SetID(CONTROL_CONTROLLER_BUTTONS_START + index);
+ SetVisible(true);
+ AllocResources();
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIControllerButton.h b/xbmc/games/controllers/guicontrols/GUIControllerButton.h
new file mode 100644
index 0000000..ebdc924
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIControllerButton.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016-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 "guilib/GUIButtonControl.h"
+
+#include <string>
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUIControllerButton : public CGUIButtonControl
+{
+public:
+ CGUIControllerButton(const CGUIButtonControl& buttonControl,
+ const std::string& label,
+ unsigned int index);
+
+ ~CGUIControllerButton() override = default;
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureButton.cpp b/xbmc/games/controllers/guicontrols/GUIFeatureButton.cpp
new file mode 100644
index 0000000..0f1bfd6
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIFeatureButton.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016-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 "GUIFeatureButton.h"
+
+#include "ServiceBroker.h"
+#include "games/controllers/windows/GUIControllerDefines.h"
+#include "guilib/GUIMessage.h"
+#include "guilib/WindowIDs.h"
+#include "messaging/ApplicationMessenger.h"
+#include "threads/Event.h"
+#include "utils/StringUtils.h"
+
+using namespace KODI;
+using namespace GAME;
+using namespace std::chrono_literals;
+
+CGUIFeatureButton::CGUIFeatureButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index)
+ : CGUIButtonControl(buttonTemplate), m_feature(feature), m_wizard(wizard)
+{
+ // Initialize CGUIButtonControl
+ SetLabel(m_feature.Label());
+ SetID(CONTROL_FEATURE_BUTTONS_START + index);
+ SetVisible(true);
+ AllocResources();
+}
+
+void CGUIFeatureButton::OnUnFocus(void)
+{
+ CGUIButtonControl::OnUnFocus();
+ m_wizard->OnUnfocus(this);
+}
+
+bool CGUIFeatureButton::DoPrompt(const std::string& strPrompt,
+ const std::string& strWarn,
+ const std::string& strFeature,
+ CEvent& waitEvent)
+{
+ bool bInterrupted = false;
+
+ if (!HasFocus())
+ {
+ CGUIMessage msgFocus(GUI_MSG_SETFOCUS, GetID(), GetID());
+ CServiceBroker::GetAppMessenger()->SendGUIMessage(msgFocus, WINDOW_INVALID, false);
+ }
+
+ CGUIMessage msgLabel(GUI_MSG_LABEL_SET, GetID(), GetID());
+
+ for (unsigned int i = 0; i < COUNTDOWN_DURATION_SEC; i++)
+ {
+ const unsigned int secondsElapsed = i;
+ const unsigned int secondsRemaining = COUNTDOWN_DURATION_SEC - i;
+
+ const bool bWarn = secondsElapsed >= WAIT_TO_WARN_SEC;
+
+ std::string strLabel;
+
+ if (bWarn)
+ strLabel = StringUtils::Format(strWarn, strFeature, secondsRemaining);
+ else
+ strLabel = StringUtils::Format(strPrompt, strFeature, secondsRemaining);
+
+ msgLabel.SetLabel(strLabel);
+ CServiceBroker::GetAppMessenger()->SendGUIMessage(msgLabel, WINDOW_INVALID, false);
+
+ waitEvent.Reset();
+ bInterrupted = waitEvent.Wait(1000ms); // Wait 1 second
+
+ if (bInterrupted)
+ break;
+ }
+
+ // Reset label
+ msgLabel.SetLabel(m_feature.Label());
+ CServiceBroker::GetAppMessenger()->SendGUIMessage(msgLabel, WINDOW_INVALID, false);
+
+ return bInterrupted;
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureButton.h b/xbmc/games/controllers/guicontrols/GUIFeatureButton.h
new file mode 100644
index 0000000..b69f521
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIFeatureButton.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016-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/input/PhysicalFeature.h"
+#include "games/controllers/windows/IConfigurationWindow.h"
+#include "guilib/GUIButtonControl.h"
+
+#include <string>
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUIFeatureButton : public CGUIButtonControl, public IFeatureButton
+{
+public:
+ CGUIFeatureButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index);
+
+ ~CGUIFeatureButton() override = default;
+
+ // implementation of CGUIControl via CGUIButtonControl
+ void OnUnFocus() override;
+
+ // partial implementation of IFeatureButton
+ const CPhysicalFeature& Feature() const override { return m_feature; }
+ INPUT::CARDINAL_DIRECTION GetCardinalDirection() const override
+ {
+ return INPUT::CARDINAL_DIRECTION::NONE;
+ }
+ JOYSTICK::WHEEL_DIRECTION GetWheelDirection() const override
+ {
+ return JOYSTICK::WHEEL_DIRECTION::NONE;
+ }
+ JOYSTICK::THROTTLE_DIRECTION GetThrottleDirection() const override
+ {
+ return JOYSTICK::THROTTLE_DIRECTION::NONE;
+ }
+
+protected:
+ bool DoPrompt(const std::string& strPrompt,
+ const std::string& strWarn,
+ const std::string& strFeature,
+ CEvent& waitEvent);
+
+ // FSM helper
+ template<typename T>
+ T GetNextState(T state)
+ {
+ return static_cast<T>(static_cast<int>(state) + 1);
+ }
+
+ const CPhysicalFeature m_feature;
+
+private:
+ IConfigurationWizard* const m_wizard;
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureControls.cpp b/xbmc/games/controllers/guicontrols/GUIFeatureControls.cpp
new file mode 100644
index 0000000..63d4757
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIFeatureControls.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016-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 "GUIFeatureControls.h"
+
+#include "games/controllers/windows/GUIControllerDefines.h"
+
+using namespace KODI;
+using namespace GAME;
+
+CGUIFeatureGroupTitle::CGUIFeatureGroupTitle(const CGUILabelControl& groupTitleTemplate,
+ const std::string& groupName,
+ unsigned int buttonIndex)
+ : CGUILabelControl(groupTitleTemplate)
+{
+ // Initialize CGUILabelControl
+ SetLabel(groupName);
+ SetID(CONTROL_FEATURE_GROUPS_START + buttonIndex);
+ SetVisible(true);
+ AllocResources();
+}
+
+CGUIFeatureSeparator::CGUIFeatureSeparator(const CGUIImage& separatorTemplate,
+ unsigned int buttonIndex)
+ : CGUIImage(separatorTemplate)
+{
+ // Initialize CGUIImage
+ SetID(CONTROL_FEATURE_SEPARATORS_START + buttonIndex);
+ SetVisible(true);
+ AllocResources();
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureControls.h b/xbmc/games/controllers/guicontrols/GUIFeatureControls.h
new file mode 100644
index 0000000..c72a11a
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIFeatureControls.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016-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 "guilib/GUIImage.h"
+#include "guilib/GUILabelControl.h"
+
+#include <string>
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUIFeatureGroupTitle : public CGUILabelControl
+{
+public:
+ CGUIFeatureGroupTitle(const CGUILabelControl& groupTitleTemplate,
+ const std::string& groupName,
+ unsigned int buttonIndex);
+
+ ~CGUIFeatureGroupTitle() override = default;
+};
+
+class CGUIFeatureSeparator : public CGUIImage
+{
+public:
+ CGUIFeatureSeparator(const CGUIImage& separatorTemplate, unsigned int buttonIndex);
+
+ ~CGUIFeatureSeparator() override = default;
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureFactory.cpp b/xbmc/games/controllers/guicontrols/GUIFeatureFactory.cpp
new file mode 100644
index 0000000..2cce033
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIFeatureFactory.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 "GUIFeatureFactory.h"
+
+#include "GUICardinalFeatureButton.h"
+#include "GUIScalarFeatureButton.h"
+#include "GUISelectKeyButton.h"
+#include "GUIThrottleButton.h"
+#include "GUIWheelButton.h"
+
+using namespace KODI;
+using namespace GAME;
+
+CGUIButtonControl* CGUIFeatureFactory::CreateButton(BUTTON_TYPE type,
+ const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index)
+{
+ switch (type)
+ {
+ case BUTTON_TYPE::BUTTON:
+ return new CGUIScalarFeatureButton(buttonTemplate, wizard, feature, index);
+
+ case BUTTON_TYPE::ANALOG_STICK:
+ return new CGUIAnalogStickButton(buttonTemplate, wizard, feature, index);
+
+ case BUTTON_TYPE::WHEEL:
+ return new CGUIWheelButton(buttonTemplate, wizard, feature, index);
+
+ case BUTTON_TYPE::THROTTLE:
+ return new CGUIThrottleButton(buttonTemplate, wizard, feature, index);
+
+ case BUTTON_TYPE::SELECT_KEY:
+ return new CGUISelectKeyButton(buttonTemplate, wizard, index);
+
+ case BUTTON_TYPE::RELATIVE_POINTER:
+ return new CGUIRelativePointerButton(buttonTemplate, wizard, feature, index);
+
+ default:
+ break;
+ }
+
+ return nullptr;
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureFactory.h b/xbmc/games/controllers/guicontrols/GUIFeatureFactory.h
new file mode 100644
index 0000000..e35070d
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIFeatureFactory.h
@@ -0,0 +1,37 @@
+/*
+ * 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 "GUIControlTypes.h"
+
+class CGUIButtonControl;
+
+namespace KODI
+{
+namespace GAME
+{
+class CPhysicalFeature;
+class IConfigurationWizard;
+
+class CGUIFeatureFactory
+{
+public:
+ /*!
+ * \brief Create a button of the specified type
+ * \param type The type of button control being created
+ * \return A button control, or nullptr if type is invalid
+ */
+ static CGUIButtonControl* CreateButton(BUTTON_TYPE type,
+ const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index);
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureTranslator.cpp b/xbmc/games/controllers/guicontrols/GUIFeatureTranslator.cpp
new file mode 100644
index 0000000..ab941c5
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIFeatureTranslator.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "GUIFeatureTranslator.h"
+
+using namespace KODI;
+using namespace GAME;
+
+BUTTON_TYPE CGUIFeatureTranslator::GetButtonType(JOYSTICK::FEATURE_TYPE featureType)
+{
+ switch (featureType)
+ {
+ case JOYSTICK::FEATURE_TYPE::SCALAR:
+ case JOYSTICK::FEATURE_TYPE::KEY:
+ return BUTTON_TYPE::BUTTON;
+
+ case JOYSTICK::FEATURE_TYPE::ANALOG_STICK:
+ return BUTTON_TYPE::ANALOG_STICK;
+
+ case JOYSTICK::FEATURE_TYPE::RELPOINTER:
+ return BUTTON_TYPE::RELATIVE_POINTER;
+
+ case JOYSTICK::FEATURE_TYPE::WHEEL:
+ return BUTTON_TYPE::WHEEL;
+
+ case JOYSTICK::FEATURE_TYPE::THROTTLE:
+ return BUTTON_TYPE::THROTTLE;
+
+ default:
+ break;
+ }
+
+ return BUTTON_TYPE::UNKNOWN;
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureTranslator.h b/xbmc/games/controllers/guicontrols/GUIFeatureTranslator.h
new file mode 100644
index 0000000..8e28d16
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIFeatureTranslator.h
@@ -0,0 +1,27 @@
+/*
+ * 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 "GUIControlTypes.h"
+#include "input/joysticks/JoystickTypes.h"
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUIFeatureTranslator
+{
+public:
+ /*!
+ * \brief Get the type of button control used to map the feature
+ */
+ static BUTTON_TYPE GetButtonType(JOYSTICK::FEATURE_TYPE featureType);
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIGameController.cpp b/xbmc/games/controllers/guicontrols/GUIGameController.cpp
new file mode 100644
index 0000000..8990cf2
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIGameController.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014-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 "GUIGameController.h"
+
+#include "games/controllers/Controller.h"
+#include "games/controllers/ControllerLayout.h"
+#include "utils/log.h"
+
+#include <mutex>
+
+using namespace KODI;
+using namespace GAME;
+
+CGUIGameController::CGUIGameController(
+ int parentID, int controlID, float posX, float posY, float width, float height)
+ : CGUIImage(parentID, controlID, posX, posY, width, height, CTextureInfo())
+{
+ // Initialize CGUIControl
+ ControlType = GUICONTROL_GAMECONTROLLER;
+}
+
+CGUIGameController::CGUIGameController(const CGUIGameController& from) : CGUIImage(from)
+{
+ // Initialize CGUIControl
+ ControlType = GUICONTROL_GAMECONTROLLER;
+}
+
+CGUIGameController* CGUIGameController::Clone(void) const
+{
+ return new CGUIGameController(*this);
+}
+
+void CGUIGameController::Render(void)
+{
+ CGUIImage::Render();
+
+ std::unique_lock<CCriticalSection> lock(m_mutex);
+
+ if (m_currentController)
+ {
+ //! @todo Render pressed buttons
+ }
+}
+
+void CGUIGameController::ActivateController(const ControllerPtr& controller)
+{
+ std::unique_lock<CCriticalSection> lock(m_mutex);
+
+ if (controller && controller != m_currentController)
+ {
+ m_currentController = controller;
+
+ lock.unlock();
+
+ //! @todo Sometimes this fails on window init
+ SetFileName(m_currentController->Layout().ImagePath());
+ }
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIGameController.h b/xbmc/games/controllers/guicontrols/GUIGameController.h
new file mode 100644
index 0000000..d62819a
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIGameController.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014-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 "guilib/GUIImage.h"
+#include "threads/CriticalSection.h"
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUIGameController : public CGUIImage
+{
+public:
+ CGUIGameController(
+ int parentID, int controlID, float posX, float posY, float width, float height);
+ CGUIGameController(const CGUIGameController& from);
+
+ ~CGUIGameController() override = default;
+
+ // implementation of CGUIControl via CGUIImage
+ CGUIGameController* Clone() const override;
+ void Render() override;
+
+ void ActivateController(const ControllerPtr& controller);
+
+private:
+ ControllerPtr m_currentController;
+ CCriticalSection m_mutex;
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIScalarFeatureButton.cpp b/xbmc/games/controllers/guicontrols/GUIScalarFeatureButton.cpp
new file mode 100644
index 0000000..5358aea
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIScalarFeatureButton.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016-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 "GUIScalarFeatureButton.h"
+
+#include "guilib/LocalizeStrings.h"
+
+#include <string>
+
+using namespace KODI;
+using namespace GAME;
+
+CGUIScalarFeatureButton::CGUIScalarFeatureButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index)
+ : CGUIFeatureButton(buttonTemplate, wizard, feature, index)
+{
+ Reset();
+}
+
+bool CGUIScalarFeatureButton::PromptForInput(CEvent& waitEvent)
+{
+ bool bInterrupted = false;
+
+ switch (m_state)
+ {
+ case STATE::NEED_INPUT:
+ {
+ const std::string& strPrompt = g_localizeStrings.Get(35090); // "Press %s"
+ const std::string& strWarn = g_localizeStrings.Get(35091); // "Press %s (%d)"
+
+ bInterrupted = DoPrompt(strPrompt, strWarn, m_feature.Label(), waitEvent);
+
+ m_state = GetNextState(m_state);
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return bInterrupted;
+}
+
+bool CGUIScalarFeatureButton::IsFinished(void) const
+{
+ return m_state >= STATE::FINISHED;
+}
+
+void CGUIScalarFeatureButton::Reset(void)
+{
+ m_state = STATE::NEED_INPUT;
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIScalarFeatureButton.h b/xbmc/games/controllers/guicontrols/GUIScalarFeatureButton.h
new file mode 100644
index 0000000..6505684
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIScalarFeatureButton.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016-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 "GUIFeatureButton.h"
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUIScalarFeatureButton : public CGUIFeatureButton
+{
+public:
+ CGUIScalarFeatureButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index);
+
+ ~CGUIScalarFeatureButton() override = default;
+
+ // implementation of IFeatureButton
+ bool PromptForInput(CEvent& waitEvent) override;
+ bool IsFinished() const override;
+ void Reset() override;
+
+private:
+ enum class STATE
+ {
+ NEED_INPUT,
+ FINISHED,
+ };
+
+ STATE m_state;
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUISelectKeyButton.cpp b/xbmc/games/controllers/guicontrols/GUISelectKeyButton.cpp
new file mode 100644
index 0000000..ea4a656
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUISelectKeyButton.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "GUISelectKeyButton.h"
+
+#include "guilib/LocalizeStrings.h"
+
+#include <string>
+
+using namespace KODI;
+using namespace GAME;
+
+CGUISelectKeyButton::CGUISelectKeyButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ unsigned int index)
+ : CGUIFeatureButton(buttonTemplate, wizard, GetFeature(), index)
+{
+}
+
+const CPhysicalFeature& CGUISelectKeyButton::Feature(void) const
+{
+ if (m_state == STATE::NEED_INPUT)
+ return m_selectedKey;
+
+ return CGUIFeatureButton::Feature();
+}
+
+bool CGUISelectKeyButton::PromptForInput(CEvent& waitEvent)
+{
+ bool bInterrupted = false;
+
+ switch (m_state)
+ {
+ case STATE::NEED_KEY:
+ {
+ const std::string& strPrompt = g_localizeStrings.Get(35169); // "Press a key"
+ const std::string& strWarn = g_localizeStrings.Get(35170); // "Press a key ({1:d})"
+
+ bInterrupted = DoPrompt(strPrompt, strWarn, "", waitEvent);
+
+ m_state = GetNextState(m_state);
+
+ break;
+ }
+ case STATE::NEED_INPUT:
+ {
+ const std::string& strPrompt = g_localizeStrings.Get(35090); // "Press {0:s}"
+ const std::string& strWarn = g_localizeStrings.Get(35091); // "Press {0:s} ({1:d})"
+
+ bInterrupted = DoPrompt(strPrompt, strWarn, m_selectedKey.Label(), waitEvent);
+
+ m_state = GetNextState(m_state);
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return bInterrupted;
+}
+
+bool CGUISelectKeyButton::IsFinished(void) const
+{
+ return m_state >= STATE::FINISHED;
+}
+
+void CGUISelectKeyButton::SetKey(const CPhysicalFeature& key)
+{
+ m_selectedKey = key;
+}
+
+void CGUISelectKeyButton::Reset(void)
+{
+ m_state = STATE::NEED_KEY;
+ m_selectedKey.Reset();
+}
+
+CPhysicalFeature CGUISelectKeyButton::GetFeature()
+{
+ return CPhysicalFeature(35168); // "Select key"
+}
diff --git a/xbmc/games/controllers/guicontrols/GUISelectKeyButton.h b/xbmc/games/controllers/guicontrols/GUISelectKeyButton.h
new file mode 100644
index 0000000..e96f78b
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUISelectKeyButton.h
@@ -0,0 +1,51 @@
+/*
+ * 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 "GUIFeatureButton.h"
+#include "games/controllers/input/PhysicalFeature.h"
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUISelectKeyButton : public CGUIFeatureButton
+{
+public:
+ CGUISelectKeyButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ unsigned int index);
+
+ ~CGUISelectKeyButton() override = default;
+
+ // implementation of IFeatureButton
+ const CPhysicalFeature& Feature(void) const override;
+ bool AllowWizard() const override { return false; }
+ bool PromptForInput(CEvent& waitEvent) override;
+ bool IsFinished() const override;
+ bool NeedsKey() const override { return m_state == STATE::NEED_KEY; }
+ void SetKey(const CPhysicalFeature& key) override;
+ void Reset() override;
+
+private:
+ static CPhysicalFeature GetFeature();
+
+ enum class STATE
+ {
+ NEED_KEY,
+ NEED_INPUT,
+ FINISHED,
+ };
+
+ STATE m_state = STATE::NEED_KEY;
+
+ CPhysicalFeature m_selectedKey;
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIThrottleButton.cpp b/xbmc/games/controllers/guicontrols/GUIThrottleButton.cpp
new file mode 100644
index 0000000..69f32a1
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIThrottleButton.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016-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 "GUIThrottleButton.h"
+
+#include "guilib/LocalizeStrings.h"
+
+#include <string>
+
+using namespace KODI;
+using namespace GAME;
+
+CGUIThrottleButton::CGUIThrottleButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index)
+ : CGUIFeatureButton(buttonTemplate, wizard, feature, index)
+{
+ Reset();
+}
+
+bool CGUIThrottleButton::PromptForInput(CEvent& waitEvent)
+{
+ using namespace JOYSTICK;
+
+ bool bInterrupted = false;
+
+ // Get the prompt for the current analog stick direction
+ std::string strPrompt;
+ std::string strWarn;
+ switch (m_state)
+ {
+ case STATE::THROTTLE_UP:
+ strPrompt = g_localizeStrings.Get(35092); // "Move %s up"
+ strWarn = g_localizeStrings.Get(35093); // "Move %s up (%d)"
+ break;
+ case STATE::THROTTLE_DOWN:
+ strPrompt = g_localizeStrings.Get(35094); // "Move %s down"
+ strWarn = g_localizeStrings.Get(35095); // "Move %s down (%d)"
+ break;
+ default:
+ break;
+ }
+
+ if (!strPrompt.empty())
+ {
+ bInterrupted = DoPrompt(strPrompt, strWarn, m_feature.Label(), waitEvent);
+
+ if (!bInterrupted)
+ m_state = STATE::FINISHED; // Not interrupted, must have timed out
+ else
+ m_state = GetNextState(m_state); // Interrupted by input, proceed
+ }
+
+ return bInterrupted;
+}
+
+bool CGUIThrottleButton::IsFinished(void) const
+{
+ return m_state >= STATE::FINISHED;
+}
+
+JOYSTICK::THROTTLE_DIRECTION CGUIThrottleButton::GetThrottleDirection(void) const
+{
+ using namespace JOYSTICK;
+
+ switch (m_state)
+ {
+ case STATE::THROTTLE_UP:
+ return THROTTLE_DIRECTION::UP;
+ case STATE::THROTTLE_DOWN:
+ return THROTTLE_DIRECTION::DOWN;
+ default:
+ break;
+ }
+
+ return THROTTLE_DIRECTION::NONE;
+}
+
+void CGUIThrottleButton::Reset(void)
+{
+ m_state = STATE::THROTTLE_UP;
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIThrottleButton.h b/xbmc/games/controllers/guicontrols/GUIThrottleButton.h
new file mode 100644
index 0000000..72b7ee3
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIThrottleButton.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016-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 "GUIFeatureButton.h"
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUIThrottleButton : public CGUIFeatureButton
+{
+public:
+ CGUIThrottleButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index);
+
+ ~CGUIThrottleButton() override = default;
+
+ // implementation of IFeatureButton
+ bool PromptForInput(CEvent& waitEvent) override;
+ bool IsFinished() const override;
+ JOYSTICK::THROTTLE_DIRECTION GetThrottleDirection() const override;
+ void Reset() override;
+
+private:
+ enum class STATE
+ {
+ THROTTLE_UP,
+ THROTTLE_DOWN,
+ FINISHED,
+ };
+
+ STATE m_state;
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/guicontrols/GUIWheelButton.cpp b/xbmc/games/controllers/guicontrols/GUIWheelButton.cpp
new file mode 100644
index 0000000..63c3819
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIWheelButton.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016-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 "GUIWheelButton.h"
+
+#include "guilib/LocalizeStrings.h"
+
+#include <string>
+
+using namespace KODI;
+using namespace GAME;
+
+CGUIWheelButton::CGUIWheelButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index)
+ : CGUIFeatureButton(buttonTemplate, wizard, feature, index)
+{
+ Reset();
+}
+
+bool CGUIWheelButton::PromptForInput(CEvent& waitEvent)
+{
+ using namespace JOYSTICK;
+
+ bool bInterrupted = false;
+
+ // Get the prompt for the current analog stick direction
+ std::string strPrompt;
+ std::string strWarn;
+ switch (m_state)
+ {
+ case STATE::WHEEL_LEFT:
+ strPrompt = g_localizeStrings.Get(35098); // "Move %s left"
+ strWarn = g_localizeStrings.Get(35099); // "Move %s left (%d)"
+ break;
+ case STATE::WHEEL_RIGHT:
+ strPrompt = g_localizeStrings.Get(35096); // "Move %s right"
+ strWarn = g_localizeStrings.Get(35097); // "Move %s right (%d)"
+ break;
+ default:
+ break;
+ }
+
+ if (!strPrompt.empty())
+ {
+ bInterrupted = DoPrompt(strPrompt, strWarn, m_feature.Label(), waitEvent);
+
+ if (!bInterrupted)
+ m_state = STATE::FINISHED; // Not interrupted, must have timed out
+ else
+ m_state = GetNextState(m_state); // Interrupted by input, proceed
+ }
+
+ return bInterrupted;
+}
+
+bool CGUIWheelButton::IsFinished(void) const
+{
+ return m_state >= STATE::FINISHED;
+}
+
+JOYSTICK::WHEEL_DIRECTION CGUIWheelButton::GetWheelDirection(void) const
+{
+ using namespace JOYSTICK;
+
+ switch (m_state)
+ {
+ case STATE::WHEEL_LEFT:
+ return WHEEL_DIRECTION::LEFT;
+ case STATE::WHEEL_RIGHT:
+ return WHEEL_DIRECTION::RIGHT;
+ default:
+ break;
+ }
+
+ return WHEEL_DIRECTION::NONE;
+}
+
+void CGUIWheelButton::Reset(void)
+{
+ m_state = STATE::WHEEL_LEFT;
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIWheelButton.h b/xbmc/games/controllers/guicontrols/GUIWheelButton.h
new file mode 100644
index 0000000..937703a
--- /dev/null
+++ b/xbmc/games/controllers/guicontrols/GUIWheelButton.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016-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 "GUIFeatureButton.h"
+
+namespace KODI
+{
+namespace GAME
+{
+class CGUIWheelButton : public CGUIFeatureButton
+{
+public:
+ CGUIWheelButton(const CGUIButtonControl& buttonTemplate,
+ IConfigurationWizard* wizard,
+ const CPhysicalFeature& feature,
+ unsigned int index);
+
+ ~CGUIWheelButton() override = default;
+
+ // implementation of IFeatureButton
+ bool PromptForInput(CEvent& waitEvent) override;
+ bool IsFinished() const override;
+ JOYSTICK::WHEEL_DIRECTION GetWheelDirection() const override;
+ void Reset() override;
+
+private:
+ enum class STATE
+ {
+ WHEEL_LEFT,
+ WHEEL_RIGHT,
+ FINISHED,
+ };
+
+ STATE m_state;
+};
+} // namespace GAME
+} // namespace KODI