aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/skin.estuary/xml/Includes_Games.xml8
-rw-r--r--xbmc/games/addons/input/GameClientInput.cpp11
-rw-r--r--xbmc/games/addons/input/GameClientInput.h1
-rw-r--r--xbmc/games/addons/input/GameClientJoystick.cpp5
-rw-r--r--xbmc/games/addons/input/GameClientJoystick.h5
-rw-r--r--xbmc/games/agents/GameAgentManager.cpp10
-rw-r--r--xbmc/games/agents/GameAgentManager.h3
-rw-r--r--xbmc/games/controllers/guicontrols/GUIGameController.cpp74
-rw-r--r--xbmc/games/controllers/guicontrols/GUIGameController.h9
-rw-r--r--xbmc/games/controllers/input/CMakeLists.txt6
-rw-r--r--xbmc/games/controllers/input/ControllerActivity.cpp48
-rw-r--r--xbmc/games/controllers/input/ControllerActivity.h44
-rw-r--r--xbmc/games/ports/input/PortInput.cpp27
-rw-r--r--xbmc/games/ports/input/PortInput.h10
-rw-r--r--xbmc/guilib/GUIControlFactory.cpp10
15 files changed, 255 insertions, 16 deletions
diff --git a/addons/skin.estuary/xml/Includes_Games.xml b/addons/skin.estuary/xml/Includes_Games.xml
index 8c110a7785..e3d553afa0 100644
--- a/addons/skin.estuary/xml/Includes_Games.xml
+++ b/addons/skin.estuary/xml/Includes_Games.xml
@@ -254,10 +254,12 @@
<shadowcolor>text_shadow</shadowcolor>
<align>right</align>
</control>
- <control type="image">
+ <control type="gamecontroller">
<right>12</right>
<width>100</width>
<texture>$INFO[ListItem.Icon]</texture>
+ <portaddress>$INFO[ListItem.FilenameAndPath]</portaddress>
+ <controllerdiffuse>button_focus</controllerdiffuse>
</control>
</control>
</itemlayout>
@@ -287,10 +289,12 @@
<shadowcolor>text_shadow</shadowcolor>
<align>right</align>
</control>
- <control type="image">
+ <control type="gamecontroller">
<right>12</right>
<width>100</width>
<texture>$INFO[ListItem.Icon]</texture>
+ <portaddress>$INFO[ListItem.FilenameAndPath]</portaddress>
+ <controllerdiffuse>button_focus</controllerdiffuse>
</control>
</control>
</focusedlayout>
diff --git a/xbmc/games/addons/input/GameClientInput.cpp b/xbmc/games/addons/input/GameClientInput.cpp
index 5805cbf1bc..13300db461 100644
--- a/xbmc/games/addons/input/GameClientInput.cpp
+++ b/xbmc/games/addons/input/GameClientInput.cpp
@@ -166,6 +166,17 @@ bool CGameClientInput::InputEvent(const game_input_event& event)
return bHandled;
}
+float CGameClientInput::GetPortActivation(const std::string& portAddress)
+{
+ float activation = 0.0f;
+
+ auto it = m_joysticks.find(portAddress);
+ if (it != m_joysticks.end())
+ activation = it->second->GetActivation();
+
+ return activation;
+}
+
void CGameClientInput::LoadTopology()
{
game_input_topology* topologyStruct = nullptr;
diff --git a/xbmc/games/addons/input/GameClientInput.h b/xbmc/games/addons/input/GameClientInput.h
index be7e71c9b9..5dce0fb53b 100644
--- a/xbmc/games/addons/input/GameClientInput.h
+++ b/xbmc/games/addons/input/GameClientInput.h
@@ -62,6 +62,7 @@ public:
bool HasFeature(const std::string& controllerId, const std::string& featureName) const;
bool AcceptsInput() const;
bool InputEvent(const game_input_event& event);
+ float GetPortActivation(const std::string& portAddress);
// Topology functions
const CControllerTree& GetDefaultControllerTree() const;
diff --git a/xbmc/games/addons/input/GameClientJoystick.cpp b/xbmc/games/addons/input/GameClientJoystick.cpp
index d4f083ba08..367fb10d63 100644
--- a/xbmc/games/addons/input/GameClientJoystick.cpp
+++ b/xbmc/games/addons/input/GameClientJoystick.cpp
@@ -184,6 +184,11 @@ std::string CGameClientJoystick::GetSourceLocation() const
return "";
}
+float CGameClientJoystick::GetActivation() const
+{
+ return m_portInput->GetActivation();
+}
+
void CGameClientJoystick::SetSource(PERIPHERALS::PeripheralPtr sourcePeripheral)
{
m_sourcePeripheral = std::move(sourcePeripheral);
diff --git a/xbmc/games/addons/input/GameClientJoystick.h b/xbmc/games/addons/input/GameClientJoystick.h
index cfb1709a12..d5144426b9 100644
--- a/xbmc/games/addons/input/GameClientJoystick.h
+++ b/xbmc/games/addons/input/GameClientJoystick.h
@@ -75,10 +75,11 @@ public:
// Input accessors
const std::string& GetPortAddress() const { return m_portAddress; }
- const ControllerPtr& GetController() const { return m_controller; }
+ ControllerPtr GetController() const { return m_controller; }
std::string GetControllerAddress() const;
- const PERIPHERALS::PeripheralPtr& GetSource() const { return m_sourcePeripheral; }
+ PERIPHERALS::PeripheralPtr GetSource() const { return m_sourcePeripheral; }
std::string GetSourceLocation() const;
+ float GetActivation() const;
// Input mutators
void SetSource(PERIPHERALS::PeripheralPtr sourcePeripheral);
diff --git a/xbmc/games/agents/GameAgentManager.cpp b/xbmc/games/agents/GameAgentManager.cpp
index 76994aaa28..7ddb0f6140 100644
--- a/xbmc/games/agents/GameAgentManager.cpp
+++ b/xbmc/games/agents/GameAgentManager.cpp
@@ -133,6 +133,16 @@ bool CGameAgentManager::OnButtonPress(MOUSE::BUTTON_ID button)
return false;
}
+float CGameAgentManager::GetPortActivation(const std::string& portAddress) const
+{
+ float activation = 0.0f;
+
+ if (m_gameClient)
+ activation = m_gameClient->Input().GetPortActivation(portAddress);
+
+ return activation;
+}
+
void CGameAgentManager::ProcessJoysticks(PERIPHERALS::EventLockHandlePtr& inputHandlingLock)
{
// Get system joysticks.
diff --git a/xbmc/games/agents/GameAgentManager.h b/xbmc/games/agents/GameAgentManager.h
index 901a492e23..621cbe2962 100644
--- a/xbmc/games/agents/GameAgentManager.h
+++ b/xbmc/games/agents/GameAgentManager.h
@@ -78,6 +78,9 @@ public:
bool OnButtonPress(MOUSE::BUTTON_ID button) override;
void OnButtonRelease(MOUSE::BUTTON_ID button) override {}
+ // Public interface
+ float GetPortActivation(const std::string& address) const;
+
private:
//! @todo De-duplicate these types
using PortAddress = std::string;
diff --git a/xbmc/games/controllers/guicontrols/GUIGameController.cpp b/xbmc/games/controllers/guicontrols/GUIGameController.cpp
index 02d9429094..39c49fcdaa 100644
--- a/xbmc/games/controllers/guicontrols/GUIGameController.cpp
+++ b/xbmc/games/controllers/guicontrols/GUIGameController.cpp
@@ -12,6 +12,7 @@
#include "ServiceBroker.h"
#include "games/GameServices.h"
#include "games/addons/input/GameClientTopology.h"
+#include "games/agents/GameAgentManager.h"
#include "games/controllers/Controller.h"
#include "games/controllers/ControllerLayout.h"
#include "guilib/GUIListItem.h"
@@ -40,6 +41,8 @@ CGUIGameController::CGUIGameController(const CGUIGameController& from)
: CGUIImage(from),
m_controllerIdInfo(from.m_controllerIdInfo),
m_controllerAddressInfo(from.m_controllerAddressInfo),
+ m_controllerDiffuse(from.m_controllerDiffuse),
+ m_portAddressInfo(from.m_portAddressInfo),
m_currentController(from.m_currentController),
m_portAddress(from.m_portAddress)
{
@@ -52,16 +55,27 @@ CGUIGameController* CGUIGameController::Clone(void) const
return new CGUIGameController(*this);
}
-void CGUIGameController::Render(void)
+void CGUIGameController::DoProcess(unsigned int currentTime, CDirtyRegionList& dirtyregions)
{
- CGUIImage::Render();
+ std::string portAddress;
- std::lock_guard<std::mutex> lock(m_mutex);
-
- if (m_currentController)
{
- //! @todo Render pressed buttons
+ std::lock_guard<std::mutex> lock(m_mutex);
+ portAddress = m_portAddress;
}
+
+ const GAME::CGameAgentManager& agentManager =
+ CServiceBroker::GetGameServices().GameAgentManager();
+
+ // Highlight the controller if it is active
+ float activation = 0.0f;
+
+ if (!portAddress.empty())
+ activation = agentManager.GetPortActivation(portAddress);
+
+ SetActivation(activation);
+
+ CGUIImage::DoProcess(currentTime, dirtyregions);
}
void CGUIGameController::UpdateInfo(const CGUIListItem* item /* = nullptr */)
@@ -79,6 +93,8 @@ void CGUIGameController::UpdateInfo(const CGUIListItem* item /* = nullptr */)
if (controllerId.empty())
controllerId = m_controllerIdInfo.GetItemLabel(item);
+ portAddress = m_portAddressInfo.GetItemLabel(item);
+
std::string controllerAddress = m_controllerAddressInfo.GetItemLabel(item);
if (!controllerAddress.empty())
std::tie(portAddress, controllerId) = CGameClientTopology::SplitAddress(controllerAddress);
@@ -126,6 +142,25 @@ void CGUIGameController::SetControllerAddress(
}
}
+void CGUIGameController::SetControllerDiffuse(const GUILIB::GUIINFO::CGUIInfoColor& color)
+{
+ m_controllerDiffuse = color;
+}
+
+void CGUIGameController::SetPortAddress(const GUILIB::GUIINFO::CGUIInfoLabel& portAddress)
+{
+ m_portAddressInfo = portAddress;
+
+ // Check if a port address is available without a listitem
+ static const CFileItem empty;
+ const std::string strPortAddress = m_portAddressInfo.GetItemLabel(&empty);
+ if (!strPortAddress.empty())
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_portAddress = strPortAddress;
+ }
+}
+
void CGUIGameController::ActivateController(const std::string& controllerId)
{
CGameServices& gameServices = CServiceBroker::GetGameServices();
@@ -157,3 +192,30 @@ std::string CGUIGameController::GetPortAddress()
std::lock_guard<std::mutex> lock(m_mutex);
return m_portAddress;
}
+
+void CGUIGameController::SetActivation(float activation)
+{
+ // Validate parameters
+ if (activation < 0.0f)
+ activation = 0.0f;
+ if (activation > 1.0f)
+ activation = 1.0f;
+
+ // Get diffuse color parts
+ const uint8_t alpha = (m_controllerDiffuse >> 24) & 0xff;
+ const uint8_t red = (m_controllerDiffuse >> 16) & 0xff;
+ const uint8_t green = (m_controllerDiffuse >> 8) & 0xff;
+ const uint8_t blue = m_controllerDiffuse & 0xff;
+
+ // Merge the diffuse color with white as a portion of the activation
+ const uint8_t newAlpha = static_cast<uint8_t>(0xff - (0xff - alpha) * activation);
+ const uint8_t newRed = static_cast<uint8_t>(0xff - (0xff - red) * activation);
+ const uint8_t newGreen = static_cast<uint8_t>(0xff - (0xff - green) * activation);
+ const uint8_t newBlue = static_cast<uint8_t>(0xff - (0xff - blue) * activation);
+
+ const UTILS::COLOR::Color activationColor =
+ (newAlpha << 24) | (newRed << 16) | (newGreen << 8) | newBlue;
+
+ if (CGUIImage::SetColorDiffuse(activationColor))
+ CGUIImage::UpdateDiffuseColor(nullptr);
+}
diff --git a/xbmc/games/controllers/guicontrols/GUIGameController.h b/xbmc/games/controllers/guicontrols/GUIGameController.h
index e667d77258..351d97f308 100644
--- a/xbmc/games/controllers/guicontrols/GUIGameController.h
+++ b/xbmc/games/controllers/guicontrols/GUIGameController.h
@@ -33,12 +33,14 @@ public:
// implementation of CGUIControl via CGUIImage
CGUIGameController* Clone() const override;
- void Render() override;
+ void DoProcess(unsigned int currentTime, CDirtyRegionList& dirtyregions) override;
void UpdateInfo(const CGUIListItem* item = nullptr) override;
// GUI functions
void SetControllerID(const GUILIB::GUIINFO::CGUIInfoLabel& controllerId);
void SetControllerAddress(const GUILIB::GUIINFO::CGUIInfoLabel& controllerAddress);
+ void SetControllerDiffuse(const GUILIB::GUIINFO::CGUIInfoColor& color);
+ void SetPortAddress(const GUILIB::GUIINFO::CGUIInfoLabel& portAddress);
// Game functions
void ActivateController(const std::string& controllerId);
@@ -46,9 +48,14 @@ public:
std::string GetPortAddress();
private:
+ // GUI functions
+ void SetActivation(float activation);
+
// GUI parameters
GUILIB::GUIINFO::CGUIInfoLabel m_controllerIdInfo;
GUILIB::GUIINFO::CGUIInfoLabel m_controllerAddressInfo;
+ GUILIB::GUIINFO::CGUIInfoColor m_controllerDiffuse;
+ GUILIB::GUIINFO::CGUIInfoLabel m_portAddressInfo;
// Game parameters
ControllerPtr m_currentController;
diff --git a/xbmc/games/controllers/input/CMakeLists.txt b/xbmc/games/controllers/input/CMakeLists.txt
index 511fa3751e..1519b11a9e 100644
--- a/xbmc/games/controllers/input/CMakeLists.txt
+++ b/xbmc/games/controllers/input/CMakeLists.txt
@@ -1,9 +1,11 @@
-set(SOURCES InputSink.cpp
+set(SOURCES ControllerActivity.cpp
+ InputSink.cpp
PhysicalFeature.cpp
PhysicalTopology.cpp
)
-set(HEADERS InputSink.h
+set(HEADERS ControllerActivity.h
+ InputSink.h
PhysicalFeature.h
PhysicalTopology.h
)
diff --git a/xbmc/games/controllers/input/ControllerActivity.cpp b/xbmc/games/controllers/input/ControllerActivity.cpp
new file mode 100644
index 0000000000..1ac2b40d20
--- /dev/null
+++ b/xbmc/games/controllers/input/ControllerActivity.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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 "ControllerActivity.h"
+
+using namespace KODI;
+using namespace GAME;
+
+#include <algorithm>
+#include <cstdlib>
+
+void CControllerActivity::OnButtonPress(bool pressed)
+{
+ if (pressed)
+ m_currentActivation = 1.0f;
+}
+
+void CControllerActivity::OnButtonMotion(float magnitude)
+{
+ m_currentActivation = std::max(magnitude, m_currentActivation);
+}
+
+void CControllerActivity::OnAnalogStickMotion(float x, float y)
+{
+ m_currentActivation = std::max(std::abs(x), m_currentActivation);
+ m_currentActivation = std::max(std::abs(y), m_currentActivation);
+}
+
+void CControllerActivity::OnWheelMotion(float position)
+{
+ m_currentActivation = std::max(std::abs(position), m_currentActivation);
+}
+
+void CControllerActivity::OnThrottleMotion(float position)
+{
+ m_currentActivation = std::max(std::abs(position), m_currentActivation);
+}
+
+void CControllerActivity::OnInputFrame()
+{
+ m_lastActivation = m_currentActivation;
+ m_currentActivation = 0.0f;
+}
diff --git a/xbmc/games/controllers/input/ControllerActivity.h b/xbmc/games/controllers/input/ControllerActivity.h
new file mode 100644
index 0000000000..10627b5cbf
--- /dev/null
+++ b/xbmc/games/controllers/input/ControllerActivity.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 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
+{
+/*!
+ * \ingroup games
+ *
+ * \brief Class to hold state about the current activity of a controller
+ *
+ * The state is held as a single float value, which is updated by the various
+ * On*() methods. The activity is the maximum value on a single input frame.
+ * The value is saved to m_lastActivity on each call to OnInputFrame().
+ */
+class CControllerActivity
+{
+public:
+ CControllerActivity() = default;
+ ~CControllerActivity() = default;
+
+ float GetActivation() const { return m_lastActivation; }
+
+ void OnButtonPress(bool pressed);
+ void OnButtonMotion(float magnitude);
+ void OnAnalogStickMotion(float x, float y);
+ void OnWheelMotion(float position);
+ void OnThrottleMotion(float position);
+ void OnInputFrame();
+
+private:
+ float m_lastActivation{0.0f};
+ float m_currentActivation{0.0f};
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/ports/input/PortInput.cpp b/xbmc/games/ports/input/PortInput.cpp
index af1652b048..ccfe3093ee 100644
--- a/xbmc/games/ports/input/PortInput.cpp
+++ b/xbmc/games/ports/input/PortInput.cpp
@@ -9,6 +9,7 @@
#include "PortInput.h"
#include "games/addons/GameClient.h"
+#include "games/controllers/input/ControllerActivity.h"
#include "games/controllers/input/InputSink.h"
#include "guilib/WindowIDs.h"
#include "input/joysticks/keymaps/KeymapHandling.h"
@@ -18,7 +19,9 @@ using namespace KODI;
using namespace GAME;
CPortInput::CPortInput(JOYSTICK::IInputHandler* gameInput)
- : m_gameInput(gameInput), m_inputSink(new CInputSink(gameInput))
+ : m_gameInput(gameInput),
+ m_inputSink(new CInputSink(gameInput)),
+ m_controllerActivity(std::make_unique<CControllerActivity>())
{
}
@@ -51,6 +54,11 @@ void CPortInput::UnregisterInput(JOYSTICK::IInputProvider* provider)
}
}
+float CPortInput::GetActivation() const
+{
+ return m_controllerActivity->GetActivation();
+}
+
std::string CPortInput::ControllerID() const
{
return m_gameInput->ControllerID();
@@ -63,6 +71,8 @@ bool CPortInput::AcceptsInput(const std::string& feature) const
bool CPortInput::OnButtonPress(const std::string& feature, bool bPressed)
{
+ m_controllerActivity->OnButtonPress(bPressed);
+
if (bPressed && !m_gameInput->AcceptsInput(feature))
return false;
@@ -71,6 +81,8 @@ bool CPortInput::OnButtonPress(const std::string& feature, bool bPressed)
void CPortInput::OnButtonHold(const std::string& feature, unsigned int holdTimeMs)
{
+ m_controllerActivity->OnButtonPress(true);
+
m_gameInput->OnButtonHold(feature, holdTimeMs);
}
@@ -78,6 +90,8 @@ bool CPortInput::OnButtonMotion(const std::string& feature,
float magnitude,
unsigned int motionTimeMs)
{
+ m_controllerActivity->OnButtonMotion(magnitude);
+
if (magnitude > 0.0f && !m_gameInput->AcceptsInput(feature))
return false;
@@ -89,6 +103,8 @@ bool CPortInput::OnAnalogStickMotion(const std::string& feature,
float y,
unsigned int motionTimeMs)
{
+ m_controllerActivity->OnAnalogStickMotion(x, y);
+
if ((x != 0.0f || y != 0.0f) && !m_gameInput->AcceptsInput(feature))
return false;
@@ -107,6 +123,8 @@ bool CPortInput::OnWheelMotion(const std::string& feature,
float position,
unsigned int motionTimeMs)
{
+ m_controllerActivity->OnWheelMotion(position);
+
if ((position != 0.0f) && !m_gameInput->AcceptsInput(feature))
return false;
@@ -117,12 +135,19 @@ bool CPortInput::OnThrottleMotion(const std::string& feature,
float position,
unsigned int motionTimeMs)
{
+ m_controllerActivity->OnThrottleMotion(position);
+
if ((position != 0.0f) && !m_gameInput->AcceptsInput(feature))
return false;
return m_gameInput->OnThrottleMotion(feature, position, motionTimeMs);
}
+void CPortInput::OnInputFrame()
+{
+ m_controllerActivity->OnInputFrame();
+}
+
int CPortInput::GetWindowID() const
{
return WINDOW_FULLSCREEN_GAME;
diff --git a/xbmc/games/ports/input/PortInput.h b/xbmc/games/ports/input/PortInput.h
index d3c6524cce..56a293449e 100644
--- a/xbmc/games/ports/input/PortInput.h
+++ b/xbmc/games/ports/input/PortInput.h
@@ -23,6 +23,8 @@ class IInputProvider;
namespace GAME
{
+class CControllerActivity;
+
class CPortInput : public JOYSTICK::IInputHandler, public IKeymapEnvironment
{
public:
@@ -32,7 +34,8 @@ public:
void RegisterInput(JOYSTICK::IInputProvider* provider);
void UnregisterInput(JOYSTICK::IInputProvider* provider);
- JOYSTICK::IInputHandler* InputHandler() { return m_gameInput; }
+ // Input parameters
+ float GetActivation() const;
// Implementation of IInputHandler
std::string ControllerID() const override;
@@ -54,7 +57,7 @@ public:
bool OnThrottleMotion(const std::string& feature,
float position,
unsigned int motionTimeMs) override;
- void OnInputFrame() override {}
+ void OnInputFrame() override;
// Implementation of IKeymapEnvironment
int GetWindowID() const override;
@@ -72,6 +75,9 @@ private:
// Prevents input falling through to Kodi when not handled by the game
std::unique_ptr<JOYSTICK::IInputHandler> m_inputSink;
+
+ // Records controller activity
+ std::unique_ptr<CControllerActivity> m_controllerActivity;
};
} // namespace GAME
} // namespace KODI
diff --git a/xbmc/guilib/GUIControlFactory.cpp b/xbmc/guilib/GUIControlFactory.cpp
index 3e6b769d73..5d84a45ba4 100644
--- a/xbmc/guilib/GUIControlFactory.cpp
+++ b/xbmc/guilib/GUIControlFactory.cpp
@@ -1576,6 +1576,16 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl
GetInfoLabel(pControlNode, "controlleraddress", controllerAddress, parentID);
gcontrol->SetControllerAddress(controllerAddress);
+ // Set controller diffuse color
+ GUIINFO::CGUIInfoColor controllerDiffuse(0xFFFFFFFF);
+ GetInfoColor(pControlNode, "controllerdiffuse", controllerDiffuse, parentID);
+ gcontrol->SetControllerDiffuse(controllerDiffuse);
+
+ // Set port address
+ GUIINFO::CGUIInfoLabel portAddress;
+ GetInfoLabel(pControlNode, "portaddress", portAddress, parentID);
+ gcontrol->SetPortAddress(portAddress);
+
break;
}
case CGUIControl::GUICONTROL_COLORBUTTON: