aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Brown <themagnificentmrb@gmail.com>2024-06-26 16:18:31 -0700
committerGitHub <noreply@github.com>2024-06-26 16:18:31 -0700
commit85dcca1fd4932c104ebba40f91756ab66895ef55 (patch)
tree96f318d93a3a9264b24655ce8901cf6f75c37a1f
parent39369a497c72721b6f31c1ba49af2aa9aaadd0c0 (diff)
parentd23e6184029698e234e464c1553ce1ee214256f6 (diff)
Merge pull request #25176 from garbear/android-default-map
Android: Fix unmapped joysticks (default joystick buttonmaps)
-rw-r--r--xbmc/games/controllers/CMakeLists.txt8
-rw-r--r--xbmc/games/controllers/ControllerIDs.h11
-rw-r--r--xbmc/games/controllers/DefaultController.cpp34
-rw-r--r--xbmc/games/controllers/DefaultController.h50
-rw-r--r--xbmc/input/joysticks/JoystickEasterEgg.cpp21
-rw-r--r--xbmc/peripherals/Peripherals.cpp2
-rw-r--r--xbmc/peripherals/addons/AddonButtonMap.cpp29
-rw-r--r--xbmc/peripherals/addons/AddonButtonMap.h5
-rw-r--r--xbmc/peripherals/addons/AddonButtonMapping.cpp2
-rw-r--r--xbmc/peripherals/addons/AddonInputHandling.cpp24
-rw-r--r--xbmc/peripherals/addons/AddonInputHandling.h11
-rw-r--r--xbmc/peripherals/bus/PeripheralBus.h17
-rw-r--r--xbmc/peripherals/devices/Peripheral.cpp6
-rw-r--r--xbmc/peripherals/devices/PeripheralJoystick.cpp3
-rw-r--r--xbmc/platform/android/peripherals/AndroidJoystickState.cpp277
-rw-r--r--xbmc/platform/android/peripherals/AndroidJoystickState.h52
-rw-r--r--xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp52
-rw-r--r--xbmc/platform/android/peripherals/AndroidJoystickTranslator.h33
-rw-r--r--xbmc/platform/android/peripherals/PeripheralBusAndroid.cpp49
-rw-r--r--xbmc/platform/android/peripherals/PeripheralBusAndroid.h2
20 files changed, 603 insertions, 85 deletions
diff --git a/xbmc/games/controllers/CMakeLists.txt b/xbmc/games/controllers/CMakeLists.txt
index b00e1caa4a..b54f5c0604 100644
--- a/xbmc/games/controllers/CMakeLists.txt
+++ b/xbmc/games/controllers/CMakeLists.txt
@@ -1,7 +1,9 @@
set(SOURCES Controller.cpp
ControllerLayout.cpp
ControllerManager.cpp
- ControllerTranslator.cpp)
+ ControllerTranslator.cpp
+ DefaultController.cpp
+)
set(HEADERS Controller.h
ControllerDefinitions.h
@@ -9,6 +11,8 @@ set(HEADERS Controller.h
ControllerLayout.h
ControllerManager.h
ControllerTranslator.h
- ControllerTypes.h)
+ ControllerTypes.h
+ DefaultController.h
+)
core_add_library(games_controller)
diff --git a/xbmc/games/controllers/ControllerIDs.h b/xbmc/games/controllers/ControllerIDs.h
index a9254e015d..68d100d156 100644
--- a/xbmc/games/controllers/ControllerIDs.h
+++ b/xbmc/games/controllers/ControllerIDs.h
@@ -13,3 +13,14 @@
#define DEFAULT_KEYBOARD_ID "game.controller.keyboard"
#define DEFAULT_MOUSE_ID "game.controller.mouse"
#define DEFAULT_REMOTE_ID "game.controller.remote"
+
+namespace KODI
+{
+namespace GAME
+{
+
+// Used to set the appearance of PlayStation controllers
+constexpr const char* CONTROLLER_ID_PLAYSTATION = "game.controller.ps.dualanalog";
+
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/games/controllers/DefaultController.cpp b/xbmc/games/controllers/DefaultController.cpp
new file mode 100644
index 0000000000..58bb464e3d
--- /dev/null
+++ b/xbmc/games/controllers/DefaultController.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 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 "DefaultController.h"
+
+using namespace KODI;
+using namespace GAME;
+
+const char* CDefaultController::FEATURE_A = "a";
+const char* CDefaultController::FEATURE_B = "b";
+const char* CDefaultController::FEATURE_X = "x";
+const char* CDefaultController::FEATURE_Y = "y";
+const char* CDefaultController::FEATURE_START = "start";
+const char* CDefaultController::FEATURE_BACK = "back";
+const char* CDefaultController::FEATURE_GUIDE = "guide";
+const char* CDefaultController::FEATURE_UP = "up";
+const char* CDefaultController::FEATURE_RIGHT = "right";
+const char* CDefaultController::FEATURE_DOWN = "down";
+const char* CDefaultController::FEATURE_LEFT = "left";
+const char* CDefaultController::FEATURE_LEFT_THUMB = "leftthumb";
+const char* CDefaultController::FEATURE_RIGHT_THUMB = "rightthumb";
+const char* CDefaultController::FEATURE_LEFT_BUMPER = "leftbumper";
+const char* CDefaultController::FEATURE_RIGHT_BUMPER = "rightbumper";
+const char* CDefaultController::FEATURE_LEFT_TRIGGER = "lefttrigger";
+const char* CDefaultController::FEATURE_RIGHT_TRIGGER = "righttrigger";
+const char* CDefaultController::FEATURE_LEFT_STICK = "leftstick";
+const char* CDefaultController::FEATURE_RIGHT_STICK = "rightstick";
+const char* CDefaultController::FEATURE_LEFT_MOTOR = "leftmotor";
+const char* CDefaultController::FEATURE_RIGHT_MOTOR = "rightmotor";
diff --git a/xbmc/games/controllers/DefaultController.h b/xbmc/games/controllers/DefaultController.h
new file mode 100644
index 0000000000..f82ce49748
--- /dev/null
+++ b/xbmc/games/controllers/DefaultController.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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
+{
+class CDefaultController
+{
+public:
+ // Face buttons
+ static const char* FEATURE_A;
+ static const char* FEATURE_B;
+ static const char* FEATURE_X;
+ static const char* FEATURE_Y;
+ static const char* FEATURE_START;
+ static const char* FEATURE_BACK;
+ static const char* FEATURE_GUIDE;
+ static const char* FEATURE_UP;
+ static const char* FEATURE_RIGHT;
+ static const char* FEATURE_DOWN;
+ static const char* FEATURE_LEFT;
+ static const char* FEATURE_LEFT_THUMB;
+ static const char* FEATURE_RIGHT_THUMB;
+
+ // Shoulder buttons
+ static const char* FEATURE_LEFT_BUMPER;
+ static const char* FEATURE_RIGHT_BUMPER;
+
+ // Triggers
+ static const char* FEATURE_LEFT_TRIGGER;
+ static const char* FEATURE_RIGHT_TRIGGER;
+
+ // Analog sticks
+ static const char* FEATURE_LEFT_STICK;
+ static const char* FEATURE_RIGHT_STICK;
+
+ // Haptics
+ static const char* FEATURE_LEFT_MOTOR;
+ static const char* FEATURE_RIGHT_MOTOR;
+};
+} // namespace GAME
+} // namespace KODI
diff --git a/xbmc/input/joysticks/JoystickEasterEgg.cpp b/xbmc/input/joysticks/JoystickEasterEgg.cpp
index ab02ba0bde..a25c4baf78 100644
--- a/xbmc/input/joysticks/JoystickEasterEgg.cpp
+++ b/xbmc/input/joysticks/JoystickEasterEgg.cpp
@@ -12,6 +12,7 @@
#include "games/GameServices.h"
#include "games/GameSettings.h"
#include "games/controllers/ControllerIDs.h"
+#include "games/controllers/DefaultController.h"
#include "guilib/GUIAudioManager.h"
#include "guilib/WindowIDs.h"
@@ -22,16 +23,16 @@ const std::map<std::string, std::vector<FeatureName>> CJoystickEasterEgg::m_sequ
{
DEFAULT_CONTROLLER_ID,
{
- "up",
- "up",
- "down",
- "down",
- "left",
- "right",
- "left",
- "right",
- "b",
- "a",
+ GAME::CDefaultController::FEATURE_UP,
+ GAME::CDefaultController::FEATURE_UP,
+ GAME::CDefaultController::FEATURE_DOWN,
+ GAME::CDefaultController::FEATURE_DOWN,
+ GAME::CDefaultController::FEATURE_LEFT,
+ GAME::CDefaultController::FEATURE_RIGHT,
+ GAME::CDefaultController::FEATURE_LEFT,
+ GAME::CDefaultController::FEATURE_RIGHT,
+ GAME::CDefaultController::FEATURE_B,
+ GAME::CDefaultController::FEATURE_A,
},
},
{
diff --git a/xbmc/peripherals/Peripherals.cpp b/xbmc/peripherals/Peripherals.cpp
index e282fbf700..1276cf52d6 100644
--- a/xbmc/peripherals/Peripherals.cpp
+++ b/xbmc/peripherals/Peripherals.cpp
@@ -917,7 +917,7 @@ void CPeripherals::ResetButtonMaps(const std::string& controllerId)
PeripheralAddonPtr addon;
if (addonBus->GetAddonWithButtonMap(peripheral.get(), addon))
{
- CAddonButtonMap buttonMap(peripheral.get(), addon, controllerId);
+ CAddonButtonMap buttonMap(peripheral.get(), addon, controllerId, *this);
buttonMap.Reset();
}
}
diff --git a/xbmc/peripherals/addons/AddonButtonMap.cpp b/xbmc/peripherals/addons/AddonButtonMap.cpp
index e9764ba81c..0471d293eb 100644
--- a/xbmc/peripherals/addons/AddonButtonMap.cpp
+++ b/xbmc/peripherals/addons/AddonButtonMap.cpp
@@ -10,6 +10,7 @@
#include "PeripheralAddonTranslator.h"
#include "input/joysticks/JoystickUtils.h"
+#include "peripherals/Peripherals.h"
#include "peripherals/devices/Peripheral.h"
#include "utils/log.h"
@@ -24,8 +25,9 @@ using namespace PERIPHERALS;
CAddonButtonMap::CAddonButtonMap(CPeripheral* device,
const std::weak_ptr<CPeripheralAddon>& addon,
- const std::string& strControllerId)
- : m_device(device), m_addon(addon), m_strControllerId(strControllerId)
+ const std::string& strControllerId,
+ CPeripherals& manager)
+ : m_device(device), m_addon(addon), m_strControllerId(strControllerId), m_manager(manager)
{
auto peripheralAddon = m_addon.lock();
assert(peripheralAddon != nullptr);
@@ -59,6 +61,29 @@ bool CAddonButtonMap::Load(void)
bSuccess |= addon->GetIgnoredPrimitives(m_device, ignoredPrimitives);
}
+ if (features.empty())
+ {
+ // Check if we can initialize a buttonmap from the peripheral bus
+ PeripheralBusPtr peripheralBus = m_manager.GetBusByType(m_device->GetBusType());
+ if (peripheralBus)
+ {
+ CLog::Log(LOGDEBUG,
+ "Buttonmap not found for {}, attempting to initialize from peripheral bus",
+ m_device->Location());
+ if (peripheralBus->InitializeButtonMap(*m_device, *this))
+ {
+ bSuccess = true;
+
+ if (auto addon = m_addon.lock())
+ {
+ addon->GetAppearance(m_device, controllerAppearance);
+ addon->GetFeatures(m_device, m_strControllerId, features);
+ addon->GetIgnoredPrimitives(m_device, ignoredPrimitives);
+ }
+ }
+ }
+ }
+
// GetFeatures() was changed to always return false if no features were
// retrieved. Check here, just in case its contract is changed or violated in
// the future.
diff --git a/xbmc/peripherals/addons/AddonButtonMap.h b/xbmc/peripherals/addons/AddonButtonMap.h
index b4b6463fee..7bbc91947f 100644
--- a/xbmc/peripherals/addons/AddonButtonMap.h
+++ b/xbmc/peripherals/addons/AddonButtonMap.h
@@ -18,6 +18,7 @@
namespace PERIPHERALS
{
class CPeripheral;
+class CPeripherals;
/*!
* \ingroup peripherals
@@ -27,7 +28,8 @@ class CAddonButtonMap : public KODI::JOYSTICK::IButtonMap
public:
CAddonButtonMap(CPeripheral* device,
const std::weak_ptr<CPeripheralAddon>& addon,
- const std::string& strControllerId);
+ const std::string& strControllerId,
+ CPeripherals& manager);
~CAddonButtonMap(void) override;
@@ -133,6 +135,7 @@ private:
CPeripheral* const m_device;
const std::weak_ptr<CPeripheralAddon> m_addon;
const std::string m_strControllerId;
+ CPeripherals& m_manager;
// Button map state
std::string m_controllerAppearance;
diff --git a/xbmc/peripherals/addons/AddonButtonMapping.cpp b/xbmc/peripherals/addons/AddonButtonMapping.cpp
index 3be55df3f6..0da424ab27 100644
--- a/xbmc/peripherals/addons/AddonButtonMapping.cpp
+++ b/xbmc/peripherals/addons/AddonButtonMapping.cpp
@@ -33,7 +33,7 @@ CAddonButtonMapping::CAddonButtonMapping(CPeripherals& manager,
else
{
const std::string controllerId = mapper->ControllerID();
- m_buttonMap = std::make_unique<CAddonButtonMap>(peripheral, addon, controllerId);
+ m_buttonMap = std::make_unique<CAddonButtonMap>(peripheral, addon, controllerId, manager);
if (m_buttonMap->Load())
{
KEYMAP::IKeymap* keymap = peripheral->GetKeymap(controllerId);
diff --git a/xbmc/peripherals/addons/AddonInputHandling.cpp b/xbmc/peripherals/addons/AddonInputHandling.cpp
index 088d01a2f1..4643e84e3f 100644
--- a/xbmc/peripherals/addons/AddonInputHandling.cpp
+++ b/xbmc/peripherals/addons/AddonInputHandling.cpp
@@ -24,28 +24,38 @@ using namespace KODI;
using namespace JOYSTICK;
using namespace PERIPHERALS;
-CAddonInputHandling::CAddonInputHandling(CPeripheral* peripheral,
+CAddonInputHandling::CAddonInputHandling(CPeripherals& manager,
+ CPeripheral* peripheral,
std::shared_ptr<CPeripheralAddon> addon,
IInputHandler* handler,
IDriverReceiver* receiver)
- : m_peripheral(peripheral),
+ : m_manager(manager),
+ m_peripheral(peripheral),
m_addon(std::move(addon)),
m_joystickInputHandler(handler),
m_joystickDriverReceiver(receiver)
{
}
-CAddonInputHandling::CAddonInputHandling(CPeripheral* peripheral,
+CAddonInputHandling::CAddonInputHandling(CPeripherals& manager,
+ CPeripheral* peripheral,
std::shared_ptr<CPeripheralAddon> addon,
KEYBOARD::IKeyboardInputHandler* handler)
- : m_peripheral(peripheral), m_addon(std::move(addon)), m_keyboardInputHandler(handler)
+ : m_manager(manager),
+ m_peripheral(peripheral),
+ m_addon(std::move(addon)),
+ m_keyboardInputHandler(handler)
{
}
-CAddonInputHandling::CAddonInputHandling(CPeripheral* peripheral,
+CAddonInputHandling::CAddonInputHandling(CPeripherals& manager,
+ CPeripheral* peripheral,
std::shared_ptr<CPeripheralAddon> addon,
MOUSE::IMouseInputHandler* handler)
- : m_peripheral(peripheral), m_addon(std::move(addon)), m_mouseInputHandler(handler)
+ : m_manager(manager),
+ m_peripheral(peripheral),
+ m_addon(std::move(addon)),
+ m_mouseInputHandler(handler)
{
}
@@ -69,7 +79,7 @@ bool CAddonInputHandling::Load()
controllerId = m_mouseInputHandler->ControllerID();
if (!controllerId.empty())
- m_buttonMap = std::make_unique<CAddonButtonMap>(m_peripheral, m_addon, controllerId);
+ m_buttonMap = std::make_unique<CAddonButtonMap>(m_peripheral, m_addon, controllerId, m_manager);
if (m_buttonMap && m_buttonMap->Load())
{
diff --git a/xbmc/peripherals/addons/AddonInputHandling.h b/xbmc/peripherals/addons/AddonInputHandling.h
index e5c98e3748..19816a6ca5 100644
--- a/xbmc/peripherals/addons/AddonInputHandling.h
+++ b/xbmc/peripherals/addons/AddonInputHandling.h
@@ -38,6 +38,7 @@ class IMouseInputHandler;
namespace PERIPHERALS
{
class CPeripheral;
+class CPeripherals;
class CPeripheralAddon;
/*!
@@ -49,16 +50,19 @@ class CAddonInputHandling : public KODI::JOYSTICK::IDriverHandler,
public KODI::MOUSE::IMouseDriverHandler
{
public:
- CAddonInputHandling(CPeripheral* peripheral,
+ CAddonInputHandling(CPeripherals& manager,
+ CPeripheral* peripheral,
std::shared_ptr<CPeripheralAddon> addon,
KODI::JOYSTICK::IInputHandler* handler,
KODI::JOYSTICK::IDriverReceiver* receiver);
- CAddonInputHandling(CPeripheral* peripheral,
+ CAddonInputHandling(CPeripherals& manager,
+ CPeripheral* peripheral,
std::shared_ptr<CPeripheralAddon> addon,
KODI::KEYBOARD::IKeyboardInputHandler* handler);
- CAddonInputHandling(CPeripheral* peripheral,
+ CAddonInputHandling(CPeripherals& manager,
+ CPeripheral* peripheral,
std::shared_ptr<CPeripheralAddon> addon,
KODI::MOUSE::IMouseInputHandler* handler);
@@ -89,6 +93,7 @@ public:
private:
// Construction parameters
+ CPeripherals& m_manager;
CPeripheral* const m_peripheral;
const std::shared_ptr<CPeripheralAddon> m_addon;
KODI::JOYSTICK::IInputHandler* const m_joystickInputHandler{nullptr};
diff --git a/xbmc/peripherals/bus/PeripheralBus.h b/xbmc/peripherals/bus/PeripheralBus.h
index 424d012d9f..33594a0faa 100644
--- a/xbmc/peripherals/bus/PeripheralBus.h
+++ b/xbmc/peripherals/bus/PeripheralBus.h
@@ -17,6 +17,14 @@
class CFileItemList;
+namespace KODI
+{
+namespace JOYSTICK
+{
+class IButtonMap;
+} // namespace JOYSTICK
+} // namespace KODI
+
namespace PERIPHERALS
{
class CPeripheral;
@@ -60,6 +68,15 @@ public:
virtual bool InitializeProperties(CPeripheral& peripheral);
/*!
+ * \brief Initialize a joystick buttonmap, if possible
+ */
+ virtual bool InitializeButtonMap(const CPeripheral& peripheral,
+ KODI::JOYSTICK::IButtonMap& buttonMap) const
+ {
+ return false;
+ }
+
+ /*!
* @brief Get the instance of the peripheral at the given location.
* @param strLocation The location.
* @return The peripheral or NULL if it wasn't found.
diff --git a/xbmc/peripherals/devices/Peripheral.cpp b/xbmc/peripherals/devices/Peripheral.cpp
index ff9910c2ef..bb00d516a3 100644
--- a/xbmc/peripherals/devices/Peripheral.cpp
+++ b/xbmc/peripherals/devices/Peripheral.cpp
@@ -597,7 +597,7 @@ void CPeripheral::RegisterInputHandler(IInputHandler* handler, bool bPromiscuous
if (addon)
{
std::unique_ptr<CAddonInputHandling> addonInput = std::make_unique<CAddonInputHandling>(
- this, std::move(addon), handler, GetDriverReceiver());
+ m_manager, this, std::move(addon), handler, GetDriverReceiver());
if (addonInput->Load())
{
RegisterJoystickDriverHandler(addonInput.get(), bPromiscuous);
@@ -638,7 +638,7 @@ void CPeripheral::RegisterKeyboardHandler(KEYBOARD::IKeyboardInputHandler* handl
if (addon)
{
std::unique_ptr<CAddonInputHandling> addonInput =
- std::make_unique<CAddonInputHandling>(this, std::move(addon), handler);
+ std::make_unique<CAddonInputHandling>(m_manager, this, std::move(addon), handler);
if (addonInput->Load())
keyboardDriverHandler = std::move(addonInput);
}
@@ -689,7 +689,7 @@ void CPeripheral::RegisterMouseHandler(MOUSE::IMouseInputHandler* handler,
if (addon)
{
std::unique_ptr<CAddonInputHandling> addonInput =
- std::make_unique<CAddonInputHandling>(this, std::move(addon), handler);
+ std::make_unique<CAddonInputHandling>(m_manager, this, std::move(addon), handler);
if (addonInput->Load())
mouseDriverHandler = std::move(addonInput);
}
diff --git a/xbmc/peripherals/devices/PeripheralJoystick.cpp b/xbmc/peripherals/devices/PeripheralJoystick.cpp
index a6029561d6..c5285c245e 100644
--- a/xbmc/peripherals/devices/PeripheralJoystick.cpp
+++ b/xbmc/peripherals/devices/PeripheralJoystick.cpp
@@ -92,7 +92,8 @@ bool CPeripheralJoystick::InitialiseFeature(const PeripheralFeature feature)
if (bSuccess)
{
- m_buttonMap = std::make_unique<CAddonButtonMap>(this, addon, DEFAULT_CONTROLLER_ID);
+ m_buttonMap =
+ std::make_unique<CAddonButtonMap>(this, addon, DEFAULT_CONTROLLER_ID, m_manager);
if (m_buttonMap->Load())
{
InitializeDeadzoneFiltering(*m_buttonMap);
diff --git a/xbmc/platform/android/peripherals/AndroidJoystickState.cpp b/xbmc/platform/android/peripherals/AndroidJoystickState.cpp
index 18bbb557e0..c3032b4352 100644
--- a/xbmc/platform/android/peripherals/AndroidJoystickState.cpp
+++ b/xbmc/platform/android/peripherals/AndroidJoystickState.cpp
@@ -9,6 +9,11 @@
#include "AndroidJoystickState.h"
#include "AndroidJoystickTranslator.h"
+#include "games/controllers/ControllerIDs.h"
+#include "games/controllers/DefaultController.h"
+#include "input/joysticks/DriverPrimitive.h"
+#include "input/joysticks/JoystickTypes.h"
+#include "input/joysticks/interfaces/IButtonMap.h"
#include "utils/StringUtils.h"
#include "utils/log.h"
@@ -19,8 +24,42 @@
#include <android/input.h>
#include <androidjni/View.h>
+using namespace KODI;
using namespace PERIPHERALS;
+namespace
+{
+// clang-format off
+static const std::vector<int> ButtonKeycodes{
+ // add the usual suspects
+ AKEYCODE_BUTTON_A,
+ AKEYCODE_BUTTON_B,
+ AKEYCODE_BUTTON_C,
+ AKEYCODE_BUTTON_X,
+ AKEYCODE_BUTTON_Y,
+ AKEYCODE_BUTTON_Z,
+ AKEYCODE_BACK,
+ AKEYCODE_MENU,
+ AKEYCODE_HOME,
+ AKEYCODE_BUTTON_SELECT,
+ AKEYCODE_BUTTON_MODE,
+ AKEYCODE_BUTTON_START,
+ AKEYCODE_BUTTON_L1,
+ AKEYCODE_BUTTON_R1,
+ AKEYCODE_BUTTON_L2,
+ AKEYCODE_BUTTON_R2,
+ AKEYCODE_BUTTON_THUMBL,
+ AKEYCODE_BUTTON_THUMBR,
+ AKEYCODE_DPAD_UP,
+ AKEYCODE_DPAD_RIGHT,
+ AKEYCODE_DPAD_DOWN,
+ AKEYCODE_DPAD_LEFT,
+ AKEYCODE_DPAD_CENTER,
+ // only add additional buttons at the end of the list
+};
+// clang-format on
+} // namespace
+
static std::string PrintAxisIds(const std::vector<int>& axisIds)
{
if (axisIds.empty())
@@ -54,15 +93,15 @@ static void MapAxisIds(int axisId,
if (axisIds.empty())
{
- axisIds.push_back(primaryAxisId);
- axisIds.push_back(secondaryAxisId);
+ axisIds.emplace_back(primaryAxisId);
+ axisIds.emplace_back(secondaryAxisId);
}
if (axisIds.size() > 1)
return;
if (axisId == primaryAxisId)
- axisIds.push_back(secondaryAxisId);
+ axisIds.emplace_back(secondaryAxisId);
else if (axisId == secondaryAxisId)
axisIds.insert(axisIds.begin(), primaryAxisId);
}
@@ -140,10 +179,10 @@ bool CAndroidJoystickState::Initialize(const CJNIViewInputDevice& inputDevice)
MapAxisIds(axisId, AMOTION_EVENT_AXIS_LTRIGGER, AMOTION_EVENT_AXIS_BRAKE, axis.ids);
MapAxisIds(axisId, AMOTION_EVENT_AXIS_RTRIGGER, AMOTION_EVENT_AXIS_GAS, axis.ids);
- m_axes.push_back(axis);
+ m_axes.emplace_back(std::move(axis));
CLog::Log(LOGDEBUG,
"CAndroidJoystickState: axis {} on input device \"{}\" with ID {} detected",
- PrintAxisIds(axis.ids), deviceName, m_deviceId);
+ PrintAxisIds(m_axes.back().ids), deviceName, m_deviceId);
}
else
CLog::Log(LOGWARNING,
@@ -151,30 +190,9 @@ bool CAndroidJoystickState::Initialize(const CJNIViewInputDevice& inputDevice)
axisId, deviceName, m_deviceId);
}
- // add the usual suspects
- m_buttons.push_back({{AKEYCODE_BUTTON_A}});
- m_buttons.push_back({{AKEYCODE_BUTTON_B}});
- m_buttons.push_back({{AKEYCODE_BUTTON_C}});
- m_buttons.push_back({{AKEYCODE_BUTTON_X}});
- m_buttons.push_back({{AKEYCODE_BUTTON_Y}});
- m_buttons.push_back({{AKEYCODE_BUTTON_Z}});
- m_buttons.push_back({{AKEYCODE_BACK}});
- m_buttons.push_back({{AKEYCODE_MENU}});
- m_buttons.push_back({{AKEYCODE_HOME}});
- m_buttons.push_back({{AKEYCODE_BUTTON_SELECT}});
- m_buttons.push_back({{AKEYCODE_BUTTON_MODE}});
- m_buttons.push_back({{AKEYCODE_BUTTON_START}});
- m_buttons.push_back({{AKEYCODE_BUTTON_L1}});
- m_buttons.push_back({{AKEYCODE_BUTTON_R1}});
- m_buttons.push_back({{AKEYCODE_BUTTON_L2}});
- m_buttons.push_back({{AKEYCODE_BUTTON_R2}});
- m_buttons.push_back({{AKEYCODE_BUTTON_THUMBL}});
- m_buttons.push_back({{AKEYCODE_BUTTON_THUMBR}});
- m_buttons.push_back({{AKEYCODE_DPAD_UP}});
- m_buttons.push_back({{AKEYCODE_DPAD_RIGHT}});
- m_buttons.push_back({{AKEYCODE_DPAD_DOWN}});
- m_buttons.push_back({{AKEYCODE_DPAD_LEFT}});
- m_buttons.push_back({{AKEYCODE_DPAD_CENTER}});
+ // map buttons
+ for (int buttonKeycode : ButtonKeycodes)
+ m_buttons.emplace_back(JoystickAxis{{buttonKeycode}});
// check if there are no buttons or axes at all
if (GetButtonCount() == 0 && GetAxisCount() == 0)
@@ -200,6 +218,67 @@ void CAndroidJoystickState::Deinitialize(void)
m_digitalEvents.clear();
}
+bool CAndroidJoystickState::InitializeButtonMap(JOYSTICK::IButtonMap& buttonMap) const
+{
+ // We only map the default controller
+ if (buttonMap.ControllerID() != DEFAULT_CONTROLLER_ID)
+ return false;
+
+ bool success = false;
+
+ // Map buttons
+ for (int buttonKeycode : ButtonKeycodes)
+ success |= MapButton(buttonMap, buttonKeycode);
+
+ // Map D-pad
+ success |= MapDpad(buttonMap, AMOTION_EVENT_AXIS_HAT_X, AMOTION_EVENT_AXIS_HAT_Y);
+
+ // Map triggers
+ // Note: This should come after buttons, because the PS4 controller uses
+ // both a digital button and an analog axis for the triggers, and we want
+ // the analog axis to override the button for full range of motion.
+ success |= MapTrigger(buttonMap, AMOTION_EVENT_AXIS_LTRIGGER,
+ GAME::CDefaultController::FEATURE_LEFT_TRIGGER);
+ success |= MapTrigger(buttonMap, AMOTION_EVENT_AXIS_RTRIGGER,
+ GAME::CDefaultController::FEATURE_RIGHT_TRIGGER);
+
+ // Map analog sticks
+ success |= MapAnalogStick(buttonMap, AMOTION_EVENT_AXIS_X, AMOTION_EVENT_AXIS_Y,
+ GAME::CDefaultController::FEATURE_LEFT_STICK);
+ success |= MapAnalogStick(buttonMap, AMOTION_EVENT_AXIS_Z, AMOTION_EVENT_AXIS_RZ,
+ GAME::CDefaultController::FEATURE_RIGHT_STICK);
+
+ if (success)
+ {
+ // If the controller has both L2/R2 buttons and LTRIGGER/RTRIGGER axes, it's
+ // probably a PS controller
+ size_t indexL2 = 0;
+ size_t indexR2 = 0;
+ size_t indexLTrigger = 0;
+ size_t indexRTrigger = 0;
+ if (GetAxesIndex({AKEYCODE_BUTTON_L2}, m_buttons, indexL2) &&
+ GetAxesIndex({AKEYCODE_BUTTON_R2}, m_buttons, indexR2) &&
+ GetAxesIndex({AMOTION_EVENT_AXIS_LTRIGGER}, m_axes, indexLTrigger) &&
+ GetAxesIndex({AMOTION_EVENT_AXIS_RTRIGGER}, m_axes, indexRTrigger))
+ {
+ CLog::Log(LOGDEBUG, "Detected dual-input triggers, ignoring digital buttons");
+ std::vector<JOYSTICK::CDriverPrimitive> ignoredPrimitives{
+ {JOYSTICK::PRIMITIVE_TYPE::BUTTON, static_cast<unsigned int>(indexL2)},
+ {JOYSTICK::PRIMITIVE_TYPE::BUTTON, static_cast<unsigned int>(indexR2)},
+ };
+ buttonMap.SetIgnoredPrimitives(ignoredPrimitives);
+
+ CLog::Log(LOGDEBUG, "Setting appearance to {}", GAME::CONTROLLER_ID_PLAYSTATION);
+ buttonMap.SetAppearance(GAME::CONTROLLER_ID_PLAYSTATION);
+ }
+
+ // Save the buttonmap
+ buttonMap.SaveButtonMap();
+ }
+
+ return success;
+}
+
bool CAndroidJoystickState::ProcessEvent(const AInputEvent* event)
{
int32_t type = AInputEvent_getType(event);
@@ -238,7 +317,7 @@ bool CAndroidJoystickState::ProcessEvent(const AInputEvent* event)
std::vector<float> values;
values.reserve(axis.ids.size());
for (const auto& axisId : axis.ids)
- values.push_back(AMotionEvent_getAxisValue(event, axisId, pointer));
+ values.emplace_back(AMotionEvent_getAxisValue(event, axisId, pointer));
// remove all zero values
values.erase(std::remove(values.begin(), values.end(), 0.0f), values.end());
@@ -334,6 +413,144 @@ bool CAndroidJoystickState::SetAxisValue(const std::vector<int>& axisIds,
return true;
}
+bool CAndroidJoystickState::MapButton(JOYSTICK::IButtonMap& buttonMap, int buttonKeycode) const
+{
+ size_t buttonIndex = 0;
+ std::string featureName;
+
+ if (!GetAxesIndex({buttonKeycode}, m_buttons, buttonIndex))
+ return false;
+
+ // Check if button is already mapped
+ JOYSTICK::CDriverPrimitive buttonPrimitive{JOYSTICK::PRIMITIVE_TYPE::BUTTON,
+ static_cast<unsigned int>(buttonIndex)};
+ if (buttonMap.GetFeature(buttonPrimitive, featureName))
+ return false;
+
+ // Translate the button
+ std::string controllerButton = CAndroidJoystickTranslator::TranslateJoystickButton(buttonKeycode);
+ if (controllerButton.empty())
+ return false;
+
+ // Map the button
+ CLog::Log(LOGDEBUG, "Automatically mapping {} to {}", controllerButton,
+ buttonPrimitive.ToString());
+ buttonMap.AddScalar(controllerButton, buttonPrimitive);
+
+ return true;
+}
+
+bool CAndroidJoystickState::MapTrigger(JOYSTICK::IButtonMap& buttonMap,
+ int axisId,
+ const std::string& triggerName) const
+{
+ size_t axisIndex = 0;
+ std::string featureName;
+
+ if (!GetAxesIndex({axisId}, m_axes, axisIndex))
+ return false;
+
+ const JOYSTICK::CDriverPrimitive semiaxis{static_cast<unsigned int>(axisIndex), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::POSITIVE, 1};
+ if (buttonMap.GetFeature(semiaxis, featureName))
+ return false;
+
+ CLog::Log(LOGDEBUG, "Automatically mapping {} to {}", triggerName, semiaxis.ToString());
+ buttonMap.AddScalar(triggerName, semiaxis);
+
+ return true;
+}
+
+bool CAndroidJoystickState::MapDpad(JOYSTICK::IButtonMap& buttonMap,
+ int horizAxisId,
+ int vertAxisId) const
+{
+ bool success = false;
+
+ size_t axisIndex = 0;
+ std::string featureName;
+
+ // Map horizontal axis
+ if (GetAxesIndex({horizAxisId}, m_axes, axisIndex))
+ {
+ const JOYSTICK::CDriverPrimitive positiveSemiaxis{static_cast<unsigned int>(axisIndex), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::POSITIVE, 1};
+ const JOYSTICK::CDriverPrimitive negativeSemiaxis{static_cast<unsigned int>(axisIndex), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::NEGATIVE, 1};
+ if (!buttonMap.GetFeature(positiveSemiaxis, featureName) &&
+ !buttonMap.GetFeature(negativeSemiaxis, featureName))
+ {
+ CLog::Log(LOGDEBUG, "Automatically mapping {} to {}", GAME::CDefaultController::FEATURE_LEFT,
+ negativeSemiaxis.ToString());
+ CLog::Log(LOGDEBUG, "Automatically mapping {} to {}", GAME::CDefaultController::FEATURE_RIGHT,
+ positiveSemiaxis.ToString());
+ buttonMap.AddScalar(GAME::CDefaultController::FEATURE_LEFT, negativeSemiaxis);
+ buttonMap.AddScalar(GAME::CDefaultController::FEATURE_RIGHT, positiveSemiaxis);
+ success |= true;
+ }
+ }
+
+ // Map vertical axis
+ if (GetAxesIndex({vertAxisId}, m_axes, axisIndex))
+ {
+ const JOYSTICK::CDriverPrimitive positiveSemiaxis{static_cast<unsigned int>(axisIndex), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::POSITIVE, 1};
+ const JOYSTICK::CDriverPrimitive negativeSemiaxis{static_cast<unsigned int>(axisIndex), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::NEGATIVE, 1};
+ if (!buttonMap.GetFeature(positiveSemiaxis, featureName) &&
+ !buttonMap.GetFeature(negativeSemiaxis, featureName))
+ {
+ CLog::Log(LOGDEBUG, "Automatically mapping {} to {}", GAME::CDefaultController::FEATURE_UP,
+ negativeSemiaxis.ToString());
+ CLog::Log(LOGDEBUG, "Automatically mapping {} to {}", GAME::CDefaultController::FEATURE_DOWN,
+ positiveSemiaxis.ToString());
+ buttonMap.AddScalar(GAME::CDefaultController::FEATURE_DOWN, positiveSemiaxis);
+ buttonMap.AddScalar(GAME::CDefaultController::FEATURE_UP, negativeSemiaxis);
+ success |= true;
+ }
+ }
+
+ return success;
+}
+
+bool CAndroidJoystickState::MapAnalogStick(JOYSTICK::IButtonMap& buttonMap,
+ int horizAxisId,
+ int vertAxisId,
+ const std::string& analogStickName) const
+{
+ size_t axisIndex1 = 0;
+ size_t axisIndex2 = 0;
+ std::string featureName;
+
+ if (!GetAxesIndex({horizAxisId}, m_axes, axisIndex1) ||
+ !GetAxesIndex({vertAxisId}, m_axes, axisIndex2))
+ return false;
+
+ const JOYSTICK::CDriverPrimitive upSemiaxis{static_cast<unsigned int>(axisIndex2), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::NEGATIVE, 1};
+ const JOYSTICK::CDriverPrimitive downSemiaxis{static_cast<unsigned int>(axisIndex2), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::POSITIVE, 1};
+ const JOYSTICK::CDriverPrimitive leftSemiaxis{static_cast<unsigned int>(axisIndex1), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::NEGATIVE, 1};
+ const JOYSTICK::CDriverPrimitive rightSemiaxis{static_cast<unsigned int>(axisIndex1), 0,
+ JOYSTICK::SEMIAXIS_DIRECTION::POSITIVE, 1};
+ if (buttonMap.GetFeature(upSemiaxis, featureName) ||
+ buttonMap.GetFeature(downSemiaxis, featureName) ||
+ buttonMap.GetFeature(leftSemiaxis, featureName) ||
+ buttonMap.GetFeature(rightSemiaxis, featureName))
+ return false;
+
+ CLog::Log(LOGDEBUG, "Automatically mapping {} to [{}, {}, {}, {}]", analogStickName,
+ upSemiaxis.ToString(), downSemiaxis.ToString(), leftSemiaxis.ToString(),
+ rightSemiaxis.ToString());
+ buttonMap.AddAnalogStick(analogStickName, JOYSTICK::ANALOG_STICK_DIRECTION::UP, upSemiaxis);
+ buttonMap.AddAnalogStick(analogStickName, JOYSTICK::ANALOG_STICK_DIRECTION::DOWN, downSemiaxis);
+ buttonMap.AddAnalogStick(analogStickName, JOYSTICK::ANALOG_STICK_DIRECTION::LEFT, leftSemiaxis);
+ buttonMap.AddAnalogStick(analogStickName, JOYSTICK::ANALOG_STICK_DIRECTION::RIGHT, rightSemiaxis);
+
+ return true;
+}
+
float CAndroidJoystickState::Contain(float value, float min, float max)
{
if (value < min)
diff --git a/xbmc/platform/android/peripherals/AndroidJoystickState.h b/xbmc/platform/android/peripherals/AndroidJoystickState.h
index 33ff953a46..550222d6f7 100644
--- a/xbmc/platform/android/peripherals/AndroidJoystickState.h
+++ b/xbmc/platform/android/peripherals/AndroidJoystickState.h
@@ -18,6 +18,14 @@
struct AInputEvent;
class CJNIViewInputDevice;
+namespace KODI
+{
+namespace JOYSTICK
+{
+class IButtonMap;
+} // namespace JOYSTICK
+} // namespace KODI
+
namespace PERIPHERALS
{
class CAndroidJoystickState
@@ -33,25 +41,39 @@ public:
unsigned int GetAxisCount() const { return static_cast<unsigned int>(m_axes.size()); }
/*!
- * Initialize the joystick object. Joystick will be initialized before the
- * first call to GetEvents().
- */
+ * \brief Initialize the joystick object
+ *
+ * Joystick will be initialized before the first call to GetEvents().
+ */
bool Initialize(const CJNIViewInputDevice& inputDevice);
/*!
- * Deinitialize the joystick object. GetEvents() will not be called after
- * deinitialization.
- */
+ * \brief Initialize a joystick buttonmap, if possible
+ *
+ * Android has a large database of buttonmaps, which it uses to provide
+ * mapped button keycodes such as AKEYCODE_BUTTON_A. We can take advantage of
+ * this to initialize a default buttonmap based on these mappings.
+ *
+ * If Android can't map the buttons, it will use generic button keycodes such
+ * as AKEYCODE_BUTTON_1, in which case we can't initialize the buttonmap.
+ */
+ bool InitializeButtonMap(KODI::JOYSTICK::IButtonMap& buttonMap) const;
+
+ /*!
+ * \brief Deinitialize the joystick object
+ *
+ * GetEvents() will not be called after deinitialization.
+ */
void Deinitialize();
/*!
- * Processes the given input event.
- */
+ * \brief Processes the given input event.
+ */
bool ProcessEvent(const AInputEvent* event);
/*!
- * Get events that have occurred since the last call to GetEvents()
- */
+ * \brief Get events that have occurred since the last call to GetEvents()
+ */
void GetEvents(std::vector<kodi::addon::PeripheralEvent>& events);
private:
@@ -61,6 +83,16 @@ private:
void GetButtonEvents(std::vector<kodi::addon::PeripheralEvent>& events);
void GetAxisEvents(std::vector<kodi::addon::PeripheralEvent>& events) const;
+ bool MapButton(KODI::JOYSTICK::IButtonMap& buttonMap, int buttonKeycode) const;
+ bool MapTrigger(KODI::JOYSTICK::IButtonMap& buttonMap,
+ int axisId,
+ const std::string& triggerName) const;
+ bool MapDpad(KODI::JOYSTICK::IButtonMap& buttonMap, int horizAxisId, int vertAxisId) const;
+ bool MapAnalogStick(KODI::JOYSTICK::IButtonMap& buttonMap,
+ int horizAxisId,
+ int vertAxisId,
+ const std::string& analogStickName) const;
+
static float Contain(float value, float min, float max);
static float Scale(float value, float max, float scaledMax);
static float Deadzone(float value, float deadzone);
diff --git a/xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp b/xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp
index 3717616413..f8f638cbde 100644
--- a/xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp
+++ b/xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp
@@ -8,9 +8,12 @@
#include "AndroidJoystickTranslator.h"
+#include "games/controllers/DefaultController.h"
+
#include <android/input.h>
#include <android/keycodes.h>
+using namespace KODI;
using namespace PERIPHERALS;
const char* CAndroidJoystickTranslator::TranslateAxis(int axisId)
@@ -726,3 +729,52 @@ const char* CAndroidJoystickTranslator::TranslateKeyCode(int keyCode)
return "unknown";
}
+
+const char* CAndroidJoystickTranslator::TranslateJoystickButton(int buttonKeycode)
+{
+ switch (buttonKeycode)
+ {
+ case AKEYCODE_BUTTON_A:
+ case AKEYCODE_DPAD_CENTER:
+ return GAME::CDefaultController::FEATURE_A;
+ case AKEYCODE_BUTTON_B:
+ return GAME::CDefaultController::FEATURE_B;
+ case AKEYCODE_BUTTON_X:
+ return GAME::CDefaultController::FEATURE_X;
+ case AKEYCODE_BUTTON_Y:
+ return GAME::CDefaultController::FEATURE_Y;
+ case AKEYCODE_BUTTON_START:
+ case AKEYCODE_MENU:
+ return GAME::CDefaultController::FEATURE_START;
+ case AKEYCODE_BUTTON_SELECT:
+ case AKEYCODE_BACK:
+ return GAME::CDefaultController::FEATURE_BACK;
+ case AKEYCODE_BUTTON_MODE:
+ case AKEYCODE_HOME:
+ return GAME::CDefaultController::FEATURE_GUIDE;
+ case AKEYCODE_DPAD_UP:
+ return GAME::CDefaultController::FEATURE_UP;
+ case AKEYCODE_DPAD_RIGHT:
+ return GAME::CDefaultController::FEATURE_RIGHT;
+ case AKEYCODE_DPAD_DOWN:
+ return GAME::CDefaultController::FEATURE_DOWN;
+ case AKEYCODE_DPAD_LEFT:
+ return GAME::CDefaultController::FEATURE_LEFT;
+ case AKEYCODE_BUTTON_L1:
+ return GAME::CDefaultController::FEATURE_LEFT_BUMPER;
+ case AKEYCODE_BUTTON_R1:
+ return GAME::CDefaultController::FEATURE_RIGHT_BUMPER;
+ case AKEYCODE_BUTTON_L2:
+ return GAME::CDefaultController::FEATURE_LEFT_TRIGGER;
+ case AKEYCODE_BUTTON_R2:
+ return GAME::CDefaultController::FEATURE_RIGHT_TRIGGER;
+ case AKEYCODE_BUTTON_THUMBL:
+ return GAME::CDefaultController::FEATURE_LEFT_THUMB;
+ case AKEYCODE_BUTTON_THUMBR:
+ return GAME::CDefaultController::FEATURE_RIGHT_THUMB;
+ default:
+ break;
+ }
+
+ return "";
+}
diff --git a/xbmc/platform/android/peripherals/AndroidJoystickTranslator.h b/xbmc/platform/android/peripherals/AndroidJoystickTranslator.h
index 53a953f0ac..8681de0c12 100644
--- a/xbmc/platform/android/peripherals/AndroidJoystickTranslator.h
+++ b/xbmc/platform/android/peripherals/AndroidJoystickTranslator.h
@@ -14,21 +14,30 @@ class CAndroidJoystickTranslator
{
public:
/*!
- * \brief Translate an axis ID to an Android enum suitable for logging
- *
- * \param axisId The axis ID given in <android/input.h>
- *
- * \return The translated enum label, or "unknown" if unknown
- */
+ * \brief Translate an axis ID to an Android enum suitable for logging
+ *
+ * \param axisId The axis ID given in <android/input.h>
+ *
+ * \return The translated enum label, or "unknown" if unknown
+ */
static const char* TranslateAxis(int axisId);
/*!
- * \brief Translate a key code to an Android enum suitable for logging
- *
- * \param keyCode The key code given in <android/keycodes.h>
- *
- * \return The translated enum label, or "unknown" if unknown
- */
+ * \brief Translate a key code to an Android enum suitable for logging
+ *
+ * \param keyCode The key code given in <android/keycodes.h>
+ *
+ * \return The translated enum label, or "unknown" if unknown
+ */
static const char* TranslateKeyCode(int keyCode);
+
+ /*!
+ * \brief Translate a button key code to a feature on the default controller
+ *
+ * \param buttonKeycode The key code given in <android/keycodes.h>
+ *
+ * \return The translated feature, or "" if unknown
+ */
+ static const char* TranslateJoystickButton(int buttonKeycode);
};
} // namespace PERIPHERALS
diff --git a/xbmc/platform/android/peripherals/PeripheralBusAndroid.cpp b/xbmc/platform/android/peripherals/PeripheralBusAndroid.cpp
index 753dc71099..f8282eeb55 100644
--- a/xbmc/platform/android/peripherals/PeripheralBusAndroid.cpp
+++ b/xbmc/platform/android/peripherals/PeripheralBusAndroid.cpp
@@ -16,6 +16,7 @@
#include "utils/log.h"
#include "platform/android/activity/XBMCApp.h"
+#include "platform/android/peripherals/AndroidJoystickState.h"
#include <algorithm>
#include <mutex>
@@ -120,6 +121,50 @@ bool CPeripheralBusAndroid::InitializeProperties(CPeripheral& peripheral)
return true;
}
+bool CPeripheralBusAndroid::InitializeButtonMap(const CPeripheral& peripheral,
+ JOYSTICK::IButtonMap& buttonMap) const
+{
+ int deviceId;
+ if (!GetDeviceId(peripheral.Location(), deviceId))
+ {
+ CLog::Log(LOGWARNING,
+ "CPeripheralBusAndroid: failed to initialize buttonmap due to unknown device ID for "
+ "peripheral \"{}\"",
+ peripheral.Location());
+ return false;
+ }
+
+ // get the joystick state
+ auto it = m_joystickStates.find(deviceId);
+ if (it == m_joystickStates.end())
+ {
+ CLog::Log(LOGWARNING,
+ "CPeripheralBusAndroid: joystick with device ID {} not found for peripheral \"{}\"",
+ deviceId, peripheral.Location());
+ return false;
+ }
+
+ const CAndroidJoystickState& joystick = it->second;
+ if (joystick.GetButtonCount() == 0 && joystick.GetAxisCount() == 0)
+ {
+ CLog::Log(LOGDEBUG,
+ "CPeripheralBusAndroid: joystick has no buttons or axes for peripheral \"{}\"",
+ peripheral.Location());
+ return false;
+ }
+
+ if (!joystick.InitializeButtonMap(buttonMap))
+ {
+ CLog::Log(
+ LOGDEBUG,
+ "CPeripheralBusAndroid: failed to initialize joystick buttonmap for peripheral \"{}\"",
+ peripheral.Location());
+ return false;
+ }
+
+ return true;
+}
+
void CPeripheralBusAndroid::Initialise(void)
{
CPeripheralBus::Initialise();
@@ -208,7 +253,7 @@ void CPeripheralBusAndroid::OnInputDeviceAdded(int deviceId)
PeripheralScanResult result;
if (!ConvertToPeripheralScanResult(device, result))
return;
- m_scanResults.m_results.push_back(result);
+ m_scanResults.m_results.emplace_back(std::move(result));
}
CLog::Log(LOGDEBUG, "CPeripheralBusAndroid: input device with ID {} added", deviceId);
@@ -345,7 +390,7 @@ PeripheralScanResults CPeripheralBusAndroid::GetInputDevices()
continue;
CLog::Log(LOGINFO, "CPeripheralBusAndroid: added input device");
- results.m_results.push_back(result);
+ results.m_results.emplace_back(std::move(result));
}
return results;
diff --git a/xbmc/platform/android/peripherals/PeripheralBusAndroid.h b/xbmc/platform/android/peripherals/PeripheralBusAndroid.h
index c3c42aa730..5ee9480970 100644
--- a/xbmc/platform/android/peripherals/PeripheralBusAndroid.h
+++ b/xbmc/platform/android/peripherals/PeripheralBusAndroid.h
@@ -35,6 +35,8 @@ public:
// specialisation of CPeripheralBus
bool InitializeProperties(CPeripheral& peripheral) override;
+ bool InitializeButtonMap(const CPeripheral& peripheral,
+ KODI::JOYSTICK::IButtonMap& buttonMap) const override;
void Initialise(void) override;
void ProcessEvents() override;