aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Brown <themagnificentmrb@gmail.com>2024-02-04 02:30:22 -0800
committerGitHub <noreply@github.com>2024-02-04 02:30:22 -0800
commita24fb814d87da91508141da9f89df7f190f11428 (patch)
treedd82112c897f25c7260b37267ff7da65d112365e
parentf1caa0dc88bf290bdb348e3bab26f0c43e75296b (diff)
parent33cd322a114e8cd782e710697f3c14645641471b (diff)
Merge pull request #24625 from garbear/backport-android-joysticks
[Backport] Android joystick fixes
-rw-r--r--xbmc/games/controllers/CMakeLists.txt8
-rw-r--r--xbmc/games/controllers/DefaultController.cpp34
-rw-r--r--xbmc/games/controllers/DefaultController.h50
-rw-r--r--xbmc/games/controllers/windows/GUIConfigurationWizard.cpp4
-rw-r--r--xbmc/input/joysticks/DriverPrimitive.cpp70
-rw-r--r--xbmc/input/joysticks/DriverPrimitive.h7
-rw-r--r--xbmc/input/joysticks/JoystickEasterEgg.cpp21
-rw-r--r--xbmc/input/joysticks/generic/ButtonMapping.cpp41
-rw-r--r--xbmc/peripherals/Peripherals.cpp2
-rw-r--r--xbmc/peripherals/addons/AddonButtonMap.cpp28
-rw-r--r--xbmc/peripherals/addons/AddonButtonMap.h5
-rw-r--r--xbmc/peripherals/addons/AddonButtonMapping.cpp2
-rw-r--r--xbmc/peripherals/addons/AddonInputHandling.cpp167
-rw-r--r--xbmc/peripherals/addons/AddonInputHandling.h24
-rw-r--r--xbmc/peripherals/bus/PeripheralBus.h17
-rw-r--r--xbmc/peripherals/devices/Peripheral.cpp67
-rw-r--r--xbmc/peripherals/devices/PeripheralJoystick.cpp3
-rw-r--r--xbmc/platform/android/activity/EventLoop.cpp4
-rw-r--r--xbmc/platform/android/peripherals/AndroidJoystickState.cpp483
-rw-r--r--xbmc/platform/android/peripherals/AndroidJoystickState.h177
-rw-r--r--xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp1021
-rw-r--r--xbmc/platform/android/peripherals/AndroidJoystickTranslator.h51
-rw-r--r--xbmc/platform/android/peripherals/PeripheralBusAndroid.cpp171
-rw-r--r--xbmc/platform/android/peripherals/PeripheralBusAndroid.h71
24 files changed, 1824 insertions, 704 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/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/games/controllers/windows/GUIConfigurationWizard.cpp b/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp
index ff5f8d8e9d..c2ac2f560f 100644
--- a/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp
+++ b/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp
@@ -290,8 +290,8 @@ bool CGUIConfigurationWizard::MapPrimitive(JOYSTICK::IButtonMap* buttonMap,
}
else
{
- CLog::Log(LOGDEBUG, "{}: mapping feature \"{}\" for device {}", m_strControllerId,
- feature.Name(), buttonMap->Location());
+ CLog::Log(LOGDEBUG, "{}: mapping feature \"{}\" for device {} to \"{}\"",
+ m_strControllerId, feature.Name(), buttonMap->Location(), primitive.ToString());
switch (feature.Type())
{
diff --git a/xbmc/input/joysticks/DriverPrimitive.cpp b/xbmc/input/joysticks/DriverPrimitive.cpp
index 9540dfd2ed..166e9268ea 100644
--- a/xbmc/input/joysticks/DriverPrimitive.cpp
+++ b/xbmc/input/joysticks/DriverPrimitive.cpp
@@ -8,6 +8,9 @@
#include "DriverPrimitive.h"
+#include "games/controllers/ControllerTranslator.h"
+#include "utils/StringUtils.h"
+
#include <utility>
using namespace KODI;
@@ -199,3 +202,70 @@ bool CDriverPrimitive::IsValid(void) const
return false;
}
+
+std::string CDriverPrimitive::ToString() const
+{
+ switch (m_type)
+ {
+ case PRIMITIVE_TYPE::BUTTON:
+ return StringUtils::Format("button {}", m_driverIndex);
+ case PRIMITIVE_TYPE::MOTOR:
+ return StringUtils::Format("motor {}", m_driverIndex);
+ case PRIMITIVE_TYPE::MOUSE_BUTTON:
+ return StringUtils::Format("mouse button {}", m_driverIndex);
+ case PRIMITIVE_TYPE::HAT:
+ {
+ switch (m_hatDirection)
+ {
+ case HAT_DIRECTION::UP:
+ return StringUtils::Format("hat {} up", m_driverIndex);
+ case HAT_DIRECTION::DOWN:
+ return StringUtils::Format("hat {} down", m_driverIndex);
+ case HAT_DIRECTION::RIGHT:
+ return StringUtils::Format("hat {} right", m_driverIndex);
+ case HAT_DIRECTION::LEFT:
+ return StringUtils::Format("hat {} left", m_driverIndex);
+ default:
+ break;
+ }
+ break;
+ }
+ case PRIMITIVE_TYPE::SEMIAXIS:
+ {
+ switch (m_semiAxisDirection)
+ {
+ case SEMIAXIS_DIRECTION::POSITIVE:
+ return StringUtils::Format("semiaxis +{}", m_driverIndex);
+ case SEMIAXIS_DIRECTION::NEGATIVE:
+ return StringUtils::Format("semiaxis -{}", m_driverIndex);
+ default:
+ break;
+ }
+ break;
+ }
+ case PRIMITIVE_TYPE::KEY:
+ return StringUtils::Format("key {}",
+ GAME::CControllerTranslator::TranslateKeycode(m_keycode));
+ case PRIMITIVE_TYPE::RELATIVE_POINTER:
+ {
+ switch (m_pointerDirection)
+ {
+ case RELATIVE_POINTER_DIRECTION::UP:
+ return StringUtils::Format("pointer {} up", m_driverIndex);
+ case RELATIVE_POINTER_DIRECTION::DOWN:
+ return StringUtils::Format("pointer {} down", m_driverIndex);
+ case RELATIVE_POINTER_DIRECTION::RIGHT:
+ return StringUtils::Format("pointer {} right", m_driverIndex);
+ case RELATIVE_POINTER_DIRECTION::LEFT:
+ return StringUtils::Format("pointer {} left", m_driverIndex);
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return "";
+}
diff --git a/xbmc/input/joysticks/DriverPrimitive.h b/xbmc/input/joysticks/DriverPrimitive.h
index abe372411d..11d391b59a 100644
--- a/xbmc/input/joysticks/DriverPrimitive.h
+++ b/xbmc/input/joysticks/DriverPrimitive.h
@@ -179,6 +179,13 @@ public:
*/
bool IsValid(void) const;
+ /*!
+ * \brief Convert primitive to a string suitable for logging
+ *
+ * \return The primitive as described by a short string, or empty if invalid
+ */
+ std::string ToString() const;
+
private:
PRIMITIVE_TYPE m_type = PRIMITIVE_TYPE::UNKNOWN;
unsigned int m_driverIndex = 0;
diff --git a/xbmc/input/joysticks/JoystickEasterEgg.cpp b/xbmc/input/joysticks/JoystickEasterEgg.cpp
index 0c63e66470..b0259a60b8 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/input/joysticks/generic/ButtonMapping.cpp b/xbmc/input/joysticks/generic/ButtonMapping.cpp
index af6bf8692f..665a23378c 100644
--- a/xbmc/input/joysticks/generic/ButtonMapping.cpp
+++ b/xbmc/input/joysticks/generic/ButtonMapping.cpp
@@ -454,31 +454,34 @@ bool CButtonMapping::MapPrimitive(const CDriverPrimitive& primitive)
{
bool bHandled = false;
- auto now = std::chrono::steady_clock::now();
-
- bool bTimeoutElapsed = true;
-
- if (m_buttonMapper->NeedsCooldown())
- bTimeoutElapsed = (now >= m_lastAction + std::chrono::milliseconds(MAPPING_COOLDOWN_MS));
-
- if (bTimeoutElapsed)
- {
- bHandled = m_buttonMapper->MapPrimitive(m_buttonMap, m_keymap, primitive);
-
- if (bHandled)
- m_lastAction = std::chrono::steady_clock::now();
- }
- else if (m_buttonMap->IsIgnored(primitive))
+ if (m_buttonMap->IsIgnored(primitive))
{
bHandled = true;
}
else
{
- auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastAction);
+ auto now = std::chrono::steady_clock::now();
- CLog::Log(LOGDEBUG, "Button mapping: rapid input after {}ms dropped for profile \"{}\"",
- duration.count(), m_buttonMapper->ControllerID());
- bHandled = true;
+ bool bTimeoutElapsed = true;
+
+ if (m_buttonMapper->NeedsCooldown())
+ bTimeoutElapsed = (now >= m_lastAction + std::chrono::milliseconds(MAPPING_COOLDOWN_MS));
+
+ if (bTimeoutElapsed)
+ {
+ bHandled = m_buttonMapper->MapPrimitive(m_buttonMap, m_keymap, primitive);
+
+ if (bHandled)
+ m_lastAction = std::chrono::steady_clock::now();
+ }
+ else
+ {
+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastAction);
+
+ CLog::Log(LOGDEBUG, "Button mapping: rapid input after {}ms dropped for profile \"{}\"",
+ duration.count(), m_buttonMapper->ControllerID());
+ bHandled = true;
+ }
}
return bHandled;
diff --git a/xbmc/peripherals/Peripherals.cpp b/xbmc/peripherals/Peripherals.cpp
index 3dc5ca6a9c..c178158dec 100644
--- a/xbmc/peripherals/Peripherals.cpp
+++ b/xbmc/peripherals/Peripherals.cpp
@@ -915,7 +915,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 f2c894ca4d..0d76ec96a4 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);
@@ -58,6 +60,28 @@ 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->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 b6a629fef5..cade54bb14 100644
--- a/xbmc/peripherals/addons/AddonButtonMap.h
+++ b/xbmc/peripherals/addons/AddonButtonMap.h
@@ -18,13 +18,15 @@
namespace PERIPHERALS
{
class CPeripheral;
+class CPeripherals;
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;
@@ -130,6 +132,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 af838aaf7f..abf981fdd2 100644
--- a/xbmc/peripherals/addons/AddonButtonMapping.cpp
+++ b/xbmc/peripherals/addons/AddonButtonMapping.cpp
@@ -31,7 +31,7 @@ CAddonButtonMapping::CAddonButtonMapping(CPeripherals& manager,
else
{
const std::string controllerId = mapper->ControllerID();
- m_buttonMap.reset(new CAddonButtonMap(peripheral, addon, controllerId));
+ m_buttonMap = std::make_unique<CAddonButtonMap>(peripheral, addon, controllerId, manager);
if (m_buttonMap->Load())
{
IKeymap* keymap = peripheral->GetKeymap(controllerId);
diff --git a/xbmc/peripherals/addons/AddonInputHandling.cpp b/xbmc/peripherals/addons/AddonInputHandling.cpp
index 644c33ea53..7490b9618b 100644
--- a/xbmc/peripherals/addons/AddonInputHandling.cpp
+++ b/xbmc/peripherals/addons/AddonInputHandling.cpp
@@ -16,8 +16,8 @@
#include "input/keyboard/interfaces/IKeyboardInputHandler.h"
#include "input/mouse/generic/MouseInputHandling.h"
#include "input/mouse/interfaces/IMouseInputHandler.h"
-#include "peripherals/Peripherals.h"
#include "peripherals/addons/AddonButtonMap.h"
+#include "peripherals/devices/Peripheral.h"
#include "utils/log.h"
using namespace KODI;
@@ -26,105 +26,106 @@ using namespace PERIPHERALS;
CAddonInputHandling::CAddonInputHandling(CPeripherals& manager,
CPeripheral* peripheral,
+ std::shared_ptr<CPeripheralAddon> addon,
IInputHandler* handler,
IDriverReceiver* receiver)
+ : m_manager(manager),
+ m_peripheral(peripheral),
+ m_addon(std::move(addon)),
+ m_joystickInputHandler(handler),
+ m_joystickDriverReceiver(receiver)
{
- PeripheralAddonPtr addon = manager.GetAddonWithButtonMap(peripheral);
-
- if (!addon)
- {
- CLog::Log(LOGDEBUG, "Failed to locate add-on for \"{}\"", peripheral->DeviceName());
- }
- else
- {
- m_buttonMap.reset(new CAddonButtonMap(peripheral, addon, handler->ControllerID()));
- if (m_buttonMap->Load())
- {
- m_driverHandler.reset(new CInputHandling(handler, m_buttonMap.get()));
-
- if (receiver)
- {
- m_inputReceiver.reset(new CDriverReceiving(receiver, m_buttonMap.get()));
-
- // Interfaces are connected here because they share button map as a common resource
- handler->SetInputReceiver(m_inputReceiver.get());
- }
- }
- else
- {
- m_buttonMap.reset();
- }
- }
}
CAddonInputHandling::CAddonInputHandling(CPeripherals& manager,
CPeripheral* peripheral,
+ std::shared_ptr<CPeripheralAddon> addon,
KEYBOARD::IKeyboardInputHandler* handler)
+ : m_manager(manager),
+ m_peripheral(peripheral),
+ m_addon(std::move(addon)),
+ m_keyboardInputHandler(handler)
{
- PeripheralAddonPtr addon = manager.GetAddonWithButtonMap(peripheral);
-
- if (!addon)
- {
- CLog::Log(LOGDEBUG, "Failed to locate add-on for \"{}\"", peripheral->DeviceName());
- }
- else
- {
- m_buttonMap.reset(new CAddonButtonMap(peripheral, addon, handler->ControllerID()));
- if (m_buttonMap->Load())
- {
- m_keyboardHandler.reset(new KEYBOARD::CKeyboardInputHandling(handler, m_buttonMap.get()));
- }
- else
- {
- m_buttonMap.reset();
- }
- }
}
CAddonInputHandling::CAddonInputHandling(CPeripherals& manager,
CPeripheral* peripheral,
+ std::shared_ptr<CPeripheralAddon> addon,
MOUSE::IMouseInputHandler* handler)
+ : m_manager(manager),
+ m_peripheral(peripheral),
+ m_addon(std::move(addon)),
+ m_mouseInputHandler(handler)
{
- PeripheralAddonPtr addon = manager.GetAddonWithButtonMap(peripheral);
+}
- if (!addon)
- {
- CLog::Log(LOGDEBUG, "Failed to locate add-on for \"{}\"", peripheral->DeviceName());
- }
- else
+CAddonInputHandling::~CAddonInputHandling(void)
+{
+ m_joystickDriverHandler.reset();
+ m_joystickInputReceiver.reset();
+ m_keyboardDriverHandler.reset();
+ m_mouseDriverHandler.reset();
+ m_buttonMap.reset();
+}
+
+bool CAddonInputHandling::Load()
+{
+ std::string controllerId;
+ if (m_joystickInputHandler != nullptr)
+ controllerId = m_joystickInputHandler->ControllerID();
+ else if (m_keyboardInputHandler != nullptr)
+ controllerId = m_keyboardInputHandler->ControllerID();
+ else if (m_mouseInputHandler != nullptr)
+ controllerId = m_mouseInputHandler->ControllerID();
+
+ if (!controllerId.empty())
+ m_buttonMap = std::make_unique<CAddonButtonMap>(m_peripheral, m_addon, controllerId, m_manager);
+
+ if (m_buttonMap && m_buttonMap->Load())
{
- m_buttonMap.reset(new CAddonButtonMap(peripheral, addon, handler->ControllerID()));
- if (m_buttonMap->Load())
+ if (m_joystickInputHandler != nullptr)
{
- m_mouseHandler.reset(new MOUSE::CMouseInputHandling(handler, m_buttonMap.get()));
+ m_joystickDriverHandler =
+ std::make_unique<CInputHandling>(m_joystickInputHandler, m_buttonMap.get());
+ if (m_joystickDriverReceiver != nullptr)
+ {
+ m_joystickInputReceiver =
+ std::make_unique<CDriverReceiving>(m_joystickDriverReceiver, m_buttonMap.get());
+
+ // Interfaces are connected here because they share button map as a common resource
+ m_joystickInputHandler->SetInputReceiver(m_joystickInputReceiver.get());
+ }
+ return true;
+ }
+ else if (m_keyboardInputHandler != nullptr)
+ {
+ m_keyboardDriverHandler = std::make_unique<KEYBOARD::CKeyboardInputHandling>(
+ m_keyboardInputHandler, m_buttonMap.get());
+ return true;
}
- else
+ else if (m_mouseInputHandler != nullptr)
{
- m_buttonMap.reset();
+ m_mouseDriverHandler =
+ std::make_unique<MOUSE::CMouseInputHandling>(m_mouseInputHandler, m_buttonMap.get());
+ return true;
}
}
-}
-CAddonInputHandling::~CAddonInputHandling(void)
-{
- m_driverHandler.reset();
- m_inputReceiver.reset();
- m_keyboardHandler.reset();
- m_buttonMap.reset();
+ return false;
}
bool CAddonInputHandling::OnButtonMotion(unsigned int buttonIndex, bool bPressed)
{
- if (m_driverHandler)
- return m_driverHandler->OnButtonMotion(buttonIndex, bPressed);
+ if (m_joystickDriverHandler)
+ return m_joystickDriverHandler->OnButtonMotion(buttonIndex, bPressed);
return false;
}
bool CAddonInputHandling::OnHatMotion(unsigned int hatIndex, HAT_STATE state)
{
- if (m_driverHandler)
- return m_driverHandler->OnHatMotion(hatIndex, state);
+ if (m_joystickDriverHandler)
+ return m_joystickDriverHandler->OnHatMotion(hatIndex, state);
return false;
}
@@ -134,58 +135,58 @@ bool CAddonInputHandling::OnAxisMotion(unsigned int axisIndex,
int center,
unsigned int range)
{
- if (m_driverHandler)
- return m_driverHandler->OnAxisMotion(axisIndex, position, center, range);
+ if (m_joystickDriverHandler)
+ return m_joystickDriverHandler->OnAxisMotion(axisIndex, position, center, range);
return false;
}
void CAddonInputHandling::OnInputFrame(void)
{
- if (m_driverHandler)
- m_driverHandler->OnInputFrame();
+ if (m_joystickDriverHandler)
+ m_joystickDriverHandler->OnInputFrame();
}
bool CAddonInputHandling::OnKeyPress(const CKey& key)
{
- if (m_keyboardHandler)
- return m_keyboardHandler->OnKeyPress(key);
+ if (m_keyboardDriverHandler)
+ return m_keyboardDriverHandler->OnKeyPress(key);
return false;
}
void CAddonInputHandling::OnKeyRelease(const CKey& key)
{
- if (m_keyboardHandler)
- m_keyboardHandler->OnKeyRelease(key);
+ if (m_keyboardDriverHandler)
+ m_keyboardDriverHandler->OnKeyRelease(key);
}
bool CAddonInputHandling::OnPosition(int x, int y)
{
- if (m_mouseHandler)
- return m_mouseHandler->OnPosition(x, y);
+ if (m_mouseDriverHandler)
+ return m_mouseDriverHandler->OnPosition(x, y);
return false;
}
bool CAddonInputHandling::OnButtonPress(MOUSE::BUTTON_ID button)
{
- if (m_mouseHandler)
- return m_mouseHandler->OnButtonPress(button);
+ if (m_mouseDriverHandler)
+ return m_mouseDriverHandler->OnButtonPress(button);
return false;
}
void CAddonInputHandling::OnButtonRelease(MOUSE::BUTTON_ID button)
{
- if (m_mouseHandler)
- m_mouseHandler->OnButtonRelease(button);
+ if (m_mouseDriverHandler)
+ m_mouseDriverHandler->OnButtonRelease(button);
}
bool CAddonInputHandling::SetRumbleState(const JOYSTICK::FeatureName& feature, float magnitude)
{
- if (m_inputReceiver)
- return m_inputReceiver->SetRumbleState(feature, magnitude);
+ if (m_joystickInputReceiver)
+ return m_joystickInputReceiver->SetRumbleState(feature, magnitude);
return false;
}
diff --git a/xbmc/peripherals/addons/AddonInputHandling.h b/xbmc/peripherals/addons/AddonInputHandling.h
index 2a59162647..295e6d4240 100644
--- a/xbmc/peripherals/addons/AddonInputHandling.h
+++ b/xbmc/peripherals/addons/AddonInputHandling.h
@@ -39,6 +39,7 @@ namespace PERIPHERALS
{
class CPeripheral;
class CPeripherals;
+class CPeripheralAddon;
class CAddonInputHandling : public KODI::JOYSTICK::IDriverHandler,
public KODI::JOYSTICK::IInputReceiver,
@@ -48,19 +49,24 @@ class CAddonInputHandling : public KODI::JOYSTICK::IDriverHandler,
public:
CAddonInputHandling(CPeripherals& manager,
CPeripheral* peripheral,
+ std::shared_ptr<CPeripheralAddon> addon,
KODI::JOYSTICK::IInputHandler* handler,
KODI::JOYSTICK::IDriverReceiver* receiver);
CAddonInputHandling(CPeripherals& manager,
CPeripheral* peripheral,
+ std::shared_ptr<CPeripheralAddon> addon,
KODI::KEYBOARD::IKeyboardInputHandler* handler);
CAddonInputHandling(CPeripherals& manager,
CPeripheral* peripheral,
+ std::shared_ptr<CPeripheralAddon> addon,
KODI::MOUSE::IMouseInputHandler* handler);
~CAddonInputHandling(void) override;
+ bool Load();
+
// implementation of IDriverHandler
bool OnButtonMotion(unsigned int buttonIndex, bool bPressed) override;
bool OnHatMotion(unsigned int hatIndex, KODI::JOYSTICK::HAT_STATE state) override;
@@ -83,10 +89,20 @@ public:
bool SetRumbleState(const KODI::JOYSTICK::FeatureName& feature, float magnitude) override;
private:
- std::unique_ptr<KODI::JOYSTICK::IDriverHandler> m_driverHandler;
- std::unique_ptr<KODI::JOYSTICK::IInputReceiver> m_inputReceiver;
- std::unique_ptr<KODI::KEYBOARD::IKeyboardDriverHandler> m_keyboardHandler;
- std::unique_ptr<KODI::MOUSE::IMouseDriverHandler> m_mouseHandler;
+ // Construction parameters
+ CPeripherals& m_manager;
+ CPeripheral* const m_peripheral;
+ const std::shared_ptr<CPeripheralAddon> m_addon;
+ KODI::JOYSTICK::IInputHandler* const m_joystickInputHandler{nullptr};
+ KODI::JOYSTICK::IDriverReceiver* const m_joystickDriverReceiver{nullptr};
+ KODI::KEYBOARD::IKeyboardInputHandler* m_keyboardInputHandler{nullptr};
+ KODI::MOUSE::IMouseInputHandler* const m_mouseInputHandler{nullptr};
+
+ // Input parameters
+ std::unique_ptr<KODI::JOYSTICK::IDriverHandler> m_joystickDriverHandler;
+ std::unique_ptr<KODI::JOYSTICK::IInputReceiver> m_joystickInputReceiver;
+ std::unique_ptr<KODI::KEYBOARD::IKeyboardDriverHandler> m_keyboardDriverHandler;
+ std::unique_ptr<KODI::MOUSE::IMouseDriverHandler> m_mouseDriverHandler;
std::unique_ptr<KODI::JOYSTICK::IButtonMap> m_buttonMap;
};
} // namespace PERIPHERALS
diff --git a/xbmc/peripherals/bus/PeripheralBus.h b/xbmc/peripherals/bus/PeripheralBus.h
index c23abff7b7..6b67a7f662 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;
@@ -58,6 +66,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 2c656a392b..6c3f7791dd 100644
--- a/xbmc/peripherals/devices/Peripheral.cpp
+++ b/xbmc/peripherals/devices/Peripheral.cpp
@@ -588,10 +588,21 @@ void CPeripheral::RegisterInputHandler(IInputHandler* handler, bool bPromiscuous
auto it = m_inputHandlers.find(handler);
if (it == m_inputHandlers.end())
{
- CAddonInputHandling* addonInput =
- new CAddonInputHandling(m_manager, this, handler, GetDriverReceiver());
- RegisterJoystickDriverHandler(addonInput, bPromiscuous);
- m_inputHandlers[handler].reset(addonInput);
+ PeripheralAddonPtr addon = m_manager.GetAddonWithButtonMap(this);
+ if (addon)
+ {
+ std::unique_ptr<CAddonInputHandling> addonInput = std::make_unique<CAddonInputHandling>(
+ m_manager, this, std::move(addon), handler, GetDriverReceiver());
+ if (addonInput->Load())
+ {
+ RegisterJoystickDriverHandler(addonInput.get(), bPromiscuous);
+ m_inputHandlers[handler] = std::move(addonInput);
+ }
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "Failed to locate add-on for \"{}\"", m_strLocation);
+ }
}
}
@@ -613,10 +624,26 @@ void CPeripheral::RegisterKeyboardHandler(KEYBOARD::IKeyboardInputHandler* handl
auto it = m_keyboardHandlers.find(handler);
if (it == m_keyboardHandlers.end())
{
- std::unique_ptr<CAddonInputHandling> addonInput(
- new CAddonInputHandling(m_manager, this, handler));
- RegisterKeyboardDriverHandler(addonInput.get(), bPromiscuous);
- m_keyboardHandlers[handler] = std::move(addonInput);
+ std::unique_ptr<KODI::KEYBOARD::IKeyboardDriverHandler> keyboardDriverHandler;
+
+ PeripheralAddonPtr addon = m_manager.GetAddonWithButtonMap(this);
+ if (addon)
+ {
+ std::unique_ptr<CAddonInputHandling> addonInput =
+ std::make_unique<CAddonInputHandling>(m_manager, this, std::move(addon), handler);
+ if (addonInput->Load())
+ keyboardDriverHandler = std::move(addonInput);
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "Failed to locate add-on for \"{}\"", m_strLocation);
+ }
+
+ if (keyboardDriverHandler)
+ {
+ RegisterKeyboardDriverHandler(keyboardDriverHandler.get(), bPromiscuous);
+ m_keyboardHandlers[handler] = std::move(keyboardDriverHandler);
+ }
}
}
@@ -635,10 +662,26 @@ void CPeripheral::RegisterMouseHandler(MOUSE::IMouseInputHandler* handler, bool
auto it = m_mouseHandlers.find(handler);
if (it == m_mouseHandlers.end())
{
- std::unique_ptr<CAddonInputHandling> addonInput(
- new CAddonInputHandling(m_manager, this, handler));
- RegisterMouseDriverHandler(addonInput.get(), bPromiscuous);
- m_mouseHandlers[handler] = std::move(addonInput);
+ std::unique_ptr<KODI::MOUSE::IMouseDriverHandler> mouseDriverHandler;
+
+ PeripheralAddonPtr addon = m_manager.GetAddonWithButtonMap(this);
+ if (addon)
+ {
+ std::unique_ptr<CAddonInputHandling> addonInput =
+ std::make_unique<CAddonInputHandling>(m_manager, this, std::move(addon), handler);
+ if (addonInput->Load())
+ mouseDriverHandler = std::move(addonInput);
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "Failed to locate add-on for \"{}\"", m_strLocation);
+ }
+
+ if (mouseDriverHandler)
+ {
+ RegisterMouseDriverHandler(mouseDriverHandler.get(), bPromiscuous);
+ m_mouseHandlers[handler] = std::move(mouseDriverHandler);
+ }
}
}
diff --git a/xbmc/peripherals/devices/PeripheralJoystick.cpp b/xbmc/peripherals/devices/PeripheralJoystick.cpp
index e2087a7bc7..bccad9174b 100644
--- a/xbmc/peripherals/devices/PeripheralJoystick.cpp
+++ b/xbmc/peripherals/devices/PeripheralJoystick.cpp
@@ -98,7 +98,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/activity/EventLoop.cpp b/xbmc/platform/android/activity/EventLoop.cpp
index 47ecdad846..a90dbbcb69 100644
--- a/xbmc/platform/android/activity/EventLoop.cpp
+++ b/xbmc/platform/android/activity/EventLoop.cpp
@@ -132,7 +132,9 @@ int32_t CEventLoop::processInput(AInputEvent* event)
int32_t source = AInputEvent_getSource(event);
// handle joystick input
- if (IS_FROM_SOURCE(source, AINPUT_SOURCE_GAMEPAD) || IS_FROM_SOURCE(source, AINPUT_SOURCE_JOYSTICK))
+ if (IS_FROM_SOURCE(source, AINPUT_SOURCE_GAMEPAD) ||
+ IS_FROM_SOURCE(source, AINPUT_SOURCE_JOYSTICK) ||
+ IS_FROM_SOURCE(source, AINPUT_SOURCE_KEYBOARD))
{
if (m_inputHandler->onJoyStickEvent(event))
return true;
diff --git a/xbmc/platform/android/peripherals/AndroidJoystickState.cpp b/xbmc/platform/android/peripherals/AndroidJoystickState.cpp
index c3e3cc57be..dcbd569c53 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,50 +24,121 @@
#include <android/input.h>
#include <androidjni/View.h>
+using namespace KODI;
using namespace PERIPHERALS;
-static std::string PrintAxisIds(const std::vector<int>& axisIds)
+namespace
{
- if (axisIds.empty())
- return "";
-
- if (axisIds.size() == 1)
- return std::to_string(axisIds.front());
-
- std::string strAxisIds;
- for (const auto& axisId : axisIds)
- {
- if (strAxisIds.empty())
- strAxisIds = "[";
- else
- strAxisIds += " | ";
-
- strAxisIds += std::to_string(axisId);
- }
- strAxisIds += "]";
-
- return strAxisIds;
-}
-
-static void MapAxisIds(int axisId, int primaryAxisId, int secondaryAxisId, std::vector<int>& axisIds)
+// Used to set the appearance of PlayStation controllers
+constexpr const char* CONTROLLER_ID_PLAYSTATION = "game.controller.ps.dualanalog";
+
+// clang-format off
+static const std::vector<int> ButtonKeycodes{
+ // add the usual suspects
+ AKEYCODE_HOME,
+ AKEYCODE_BACK,
+ AKEYCODE_DPAD_UP,
+ AKEYCODE_DPAD_DOWN,
+ AKEYCODE_DPAD_LEFT,
+ AKEYCODE_DPAD_RIGHT,
+ AKEYCODE_DPAD_CENTER,
+ AKEYCODE_MENU,
+ AKEYCODE_BUTTON_A,
+ AKEYCODE_BUTTON_B,
+ AKEYCODE_BUTTON_C,
+ AKEYCODE_BUTTON_X,
+ AKEYCODE_BUTTON_Y,
+ AKEYCODE_BUTTON_Z,
+ AKEYCODE_BUTTON_L1,
+ AKEYCODE_BUTTON_R1,
+ AKEYCODE_BUTTON_L2,
+ AKEYCODE_BUTTON_R2,
+ AKEYCODE_BUTTON_THUMBL,
+ AKEYCODE_BUTTON_THUMBR,
+ AKEYCODE_BUTTON_START,
+ AKEYCODE_BUTTON_SELECT,
+ AKEYCODE_BUTTON_MODE,
+ // add generic gamepad buttons for controllers that Android doesn't know
+ // how to map
+ AKEYCODE_BUTTON_1,
+ AKEYCODE_BUTTON_2,
+ AKEYCODE_BUTTON_3,
+ AKEYCODE_BUTTON_4,
+ AKEYCODE_BUTTON_5,
+ AKEYCODE_BUTTON_6,
+ AKEYCODE_BUTTON_7,
+ AKEYCODE_BUTTON_8,
+ AKEYCODE_BUTTON_9,
+ AKEYCODE_BUTTON_10,
+ AKEYCODE_BUTTON_11,
+ AKEYCODE_BUTTON_12,
+ AKEYCODE_BUTTON_13,
+ AKEYCODE_BUTTON_14,
+ AKEYCODE_BUTTON_15,
+ AKEYCODE_BUTTON_16,
+ // only add additional buttons at the end of the list
+};
+// clang-format on
+
+// clang-format off
+static const std::vector<int> AxisIDs{
+ AMOTION_EVENT_AXIS_HAT_X,
+ AMOTION_EVENT_AXIS_HAT_Y,
+ AMOTION_EVENT_AXIS_X,
+ AMOTION_EVENT_AXIS_Y,
+ AMOTION_EVENT_AXIS_Z,
+ AMOTION_EVENT_AXIS_RX,
+ AMOTION_EVENT_AXIS_RY,
+ AMOTION_EVENT_AXIS_RZ,
+ AMOTION_EVENT_AXIS_LTRIGGER,
+ AMOTION_EVENT_AXIS_RTRIGGER,
+ AMOTION_EVENT_AXIS_GAS,
+ AMOTION_EVENT_AXIS_BRAKE,
+ AMOTION_EVENT_AXIS_THROTTLE,
+ AMOTION_EVENT_AXIS_RUDDER,
+ AMOTION_EVENT_AXIS_WHEEL,
+ AMOTION_EVENT_AXIS_GENERIC_1,
+ AMOTION_EVENT_AXIS_GENERIC_2,
+ AMOTION_EVENT_AXIS_GENERIC_3,
+ AMOTION_EVENT_AXIS_GENERIC_4,
+ AMOTION_EVENT_AXIS_GENERIC_5,
+ AMOTION_EVENT_AXIS_GENERIC_6,
+ AMOTION_EVENT_AXIS_GENERIC_7,
+ AMOTION_EVENT_AXIS_GENERIC_8,
+ AMOTION_EVENT_AXIS_GENERIC_9,
+ AMOTION_EVENT_AXIS_GENERIC_10,
+ AMOTION_EVENT_AXIS_GENERIC_11,
+ AMOTION_EVENT_AXIS_GENERIC_12,
+ AMOTION_EVENT_AXIS_GENERIC_13,
+ AMOTION_EVENT_AXIS_GENERIC_14,
+ AMOTION_EVENT_AXIS_GENERIC_15,
+ AMOTION_EVENT_AXIS_GENERIC_16,
+};
+// clang-format on
+
+static void MapAxisIds(int axisId,
+ int primaryAxisId,
+ int secondaryAxisId,
+ std::vector<int>& axisIds)
{
if (axisId != primaryAxisId && axisId != secondaryAxisId)
return;
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);
}
+} // namespace
CAndroidJoystickState::CAndroidJoystickState(CAndroidJoystickState&& other) noexcept
: m_deviceId(other.m_deviceId),
@@ -97,40 +173,30 @@ bool CAndroidJoystickState::Initialize(const CJNIViewInputDevice& inputDevice)
!motionRange.isFromSource(CJNIViewInputDevice::SOURCE_GAMEPAD))
{
CLog::Log(LOGDEBUG,
- "CAndroidJoystickState: ignoring axis {} from source {} for input device \"{}\" "
+ "CAndroidJoystickState: axis {} has unexpected source {} for input device \"{}\" "
"with ID {}",
motionRange.getAxis(), motionRange.getSource(), deviceName, m_deviceId);
- continue;
}
int axisId = motionRange.getAxis();
- JoystickAxis axis {
- { axisId },
- motionRange.getFlat(),
- motionRange.getFuzz(),
- motionRange.getMin(),
- motionRange.getMax(),
- motionRange.getRange(),
- motionRange.getResolution()
- };
-
- // check if the axis ID belongs to a D-pad, analogue stick or trigger
- if (axisId == AMOTION_EVENT_AXIS_HAT_X || axisId == AMOTION_EVENT_AXIS_HAT_Y ||
- axisId == AMOTION_EVENT_AXIS_X || axisId == AMOTION_EVENT_AXIS_Y ||
- axisId == AMOTION_EVENT_AXIS_Z || axisId == AMOTION_EVENT_AXIS_RX ||
- axisId == AMOTION_EVENT_AXIS_RY || axisId == AMOTION_EVENT_AXIS_RZ ||
- axisId == AMOTION_EVENT_AXIS_LTRIGGER || axisId == AMOTION_EVENT_AXIS_RTRIGGER ||
- axisId == AMOTION_EVENT_AXIS_GAS || axisId == AMOTION_EVENT_AXIS_BRAKE ||
- axisId == AMOTION_EVENT_AXIS_THROTTLE || axisId == AMOTION_EVENT_AXIS_RUDDER || axisId == AMOTION_EVENT_AXIS_WHEEL)
+ JoystickAxis axis{{axisId},
+ motionRange.getFlat(),
+ motionRange.getFuzz(),
+ motionRange.getMin(),
+ motionRange.getMax(),
+ motionRange.getRange(),
+ motionRange.getResolution()};
+
+ // check if the axis ID belongs to a D-pad, analogue stick, trigger or
+ // generic axis
+ if (std::find(AxisIDs.begin(), AxisIDs.end(), axisId) != AxisIDs.end())
{
- // check if this axis is already known
+ CLog::Log(LOGDEBUG, "CAndroidJoystickState: axis found: {} ({})",
+ CAndroidJoystickTranslator::TranslateAxis(axisId), axisId);
+
+ // check if this axis is already known
if (ContainsAxis(axisId, m_axes))
- {
- CLog::Log(LOGWARNING,
- "CAndroidJoystickState: duplicate axis {} on input device \"{}\" with ID {}",
- PrintAxisIds(axis.ids), deviceName, m_deviceId);
continue;
- }
// map AMOTION_EVENT_AXIS_GAS to AMOTION_EVENT_AXIS_RTRIGGER and
// AMOTION_EVENT_AXIS_BRAKE to AMOTION_EVENT_AXIS_LTRIGGER
@@ -138,10 +204,7 @@ 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);
- CLog::Log(LOGDEBUG,
- "CAndroidJoystickState: axis {} on input device \"{}\" with ID {} detected",
- PrintAxisIds(axis.ids), deviceName, m_deviceId);
+ m_axes.emplace_back(std::move(axis));
}
else
CLog::Log(LOGWARNING,
@@ -149,30 +212,27 @@ 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} });
+ // check for presence of buttons
+ auto results = inputDevice.hasKeys(ButtonKeycodes);
+
+ if (results.size() != ButtonKeycodes.size())
+ {
+ CLog::Log(LOGERROR, "CAndroidJoystickState: failed to get key status for {} buttons",
+ ButtonKeycodes.size());
+ return false;
+ }
+
+ // log positive results and assign results to buttons
+ for (unsigned int i = 0; i < ButtonKeycodes.size(); ++i)
+ {
+ if (results[i])
+ {
+ const int buttonKeycode = ButtonKeycodes[i];
+ CLog::Log(LOGDEBUG, "CAndroidJoystickState: button found: {} ({})",
+ CAndroidJoystickTranslator::TranslateKeyCode(buttonKeycode), buttonKeycode);
+ m_buttons.emplace_back(JoystickAxis{{buttonKeycode}});
+ }
+ }
// check if there are no buttons or axes at all
if (GetButtonCount() == 0 && GetAxisCount() == 0)
@@ -198,6 +258,70 @@ void CAndroidJoystickState::Deinitialize(void)
m_digitalEvents.clear();
}
+bool CAndroidJoystickState::InitializeButtonMap(KODI::JOYSTICK::IButtonMap& buttonMap) const
+{
+ // We only map the default controller
+ if (buttonMap.ControllerID() != DEFAULT_CONTROLLER_ID)
+ return false;
+
+ bool success = false;
+
+ // Map buttons
+ for (auto it = ButtonKeycodes.begin(); it != ButtonKeycodes.end(); ++it)
+ {
+ const int buttonKeycode = *it;
+ 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 {}", CONTROLLER_ID_PLAYSTATION);
+ buttonMap.SetAppearance(CONTROLLER_ID_PLAYSTATION);
+ }
+
+ // Save the buttonmap
+ buttonMap.SaveButtonMap();
+ }
+
+ return success;
+}
+
bool CAndroidJoystickState::ProcessEvent(const AInputEvent* event)
{
int32_t type = AInputEvent_getType(event);
@@ -219,6 +343,25 @@ bool CAndroidJoystickState::ProcessEvent(const AInputEvent* event)
bool result = SetButtonValue(keycode, buttonState);
+ if (!result)
+ {
+ // Try shoehorning keys into buttons
+ switch (keycode)
+ {
+ case AKEYCODE_MENU:
+ result = SetButtonValue(AKEYCODE_BUTTON_START, buttonState);
+ break;
+ case AKEYCODE_BACK:
+ result = SetButtonValue(AKEYCODE_BUTTON_SELECT, buttonState);
+ break;
+ case AKEYCODE_HOME:
+ result = SetButtonValue(AKEYCODE_BUTTON_MODE, buttonState);
+ break;
+ default:
+ break;
+ }
+ }
+
return result;
}
@@ -235,7 +378,7 @@ bool CAndroidJoystickState::ProcessEvent(const AInputEvent* event)
// get all potential values
std::vector<float> values;
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());
@@ -274,9 +417,9 @@ void CAndroidJoystickState::GetButtonEvents(std::vector<kodi::addon::PeripheralE
// Only report a single event per button (avoids dropping rapid presses)
std::vector<kodi::addon::PeripheralEvent> repeatButtons;
- for (const auto &digitalEvent : m_digitalEvents)
+ for (const auto& digitalEvent : m_digitalEvents)
{
- auto HasButton = [&digitalEvent](const kodi::addon::PeripheralEvent &event)
+ auto HasButton = [&digitalEvent](const kodi::addon::PeripheralEvent& event)
{
if (event.Type() == PERIPHERAL_EVENT_TYPE_DRIVER_BUTTON)
return event.DriverIndex() == digitalEvent.DriverIndex();
@@ -301,7 +444,7 @@ void CAndroidJoystickState::GetAxisEvents(std::vector<kodi::addon::PeripheralEve
bool CAndroidJoystickState::SetButtonValue(int axisId, JOYSTICK_STATE_BUTTON buttonValue)
{
size_t buttonIndex = 0;
- if (!GetAxesIndex({ axisId }, m_buttons, buttonIndex) || buttonIndex >= GetButtonCount())
+ if (!GetAxesIndex({axisId}, m_buttons, buttonIndex) || buttonIndex >= GetButtonCount())
return false;
std::unique_lock<CCriticalSection> lock(m_eventMutex);
@@ -311,7 +454,8 @@ bool CAndroidJoystickState::SetButtonValue(int axisId, JOYSTICK_STATE_BUTTON but
return true;
}
-bool CAndroidJoystickState::SetAxisValue(const std::vector<int>& axisIds, JOYSTICK_STATE_AXIS axisValue)
+bool CAndroidJoystickState::SetAxisValue(const std::vector<int>& axisIds,
+ JOYSTICK_STATE_AXIS axisValue)
{
size_t axisIndex = 0;
if (!GetAxesIndex(axisIds, m_axes, axisIndex) || axisIndex >= GetAxisCount())
@@ -330,6 +474,145 @@ bool CAndroidJoystickState::SetAxisValue(const std::vector<int>& axisIds, JOYSTI
return true;
}
+bool CAndroidJoystickState::MapButton(KODI::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(KODI::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(KODI::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(KODI::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)
@@ -347,33 +630,35 @@ float CAndroidJoystickState::Scale(float value, float max, float scaledMax)
float CAndroidJoystickState::Deadzone(float value, float deadzone)
{
- if ((value > 0.0f && value < deadzone) ||
- (value < 0.0f && value > -deadzone))
+ if ((value > 0.0f && value < deadzone) || (value < 0.0f && value > -deadzone))
return 0.0f;
return value;
}
-CAndroidJoystickState::JoystickAxes::const_iterator CAndroidJoystickState::GetAxis(const std::vector<int>& axisIds, const JoystickAxes& axes)
+CAndroidJoystickState::JoystickAxes::const_iterator CAndroidJoystickState::GetAxis(
+ const std::vector<int>& axisIds, const JoystickAxes& axes)
{
return std::find_if(axes.cbegin(), axes.cend(),
- [&axisIds](const JoystickAxis& axis)
- {
- std::vector<int> matches(std::max(axisIds.size(), axis.ids.size()));
- const auto& matchesEnd = std::set_intersection(axisIds.begin(), axisIds.end(),
- axis.ids.begin(), axis.ids.end(),
- matches.begin());
- matches.resize(matchesEnd - matches.begin());
- return !matches.empty();
- });
+ [&axisIds](const JoystickAxis& axis)
+ {
+ std::vector<int> matches(std::max(axisIds.size(), axis.ids.size()));
+ const auto& matchesEnd =
+ std::set_intersection(axisIds.begin(), axisIds.end(), axis.ids.begin(),
+ axis.ids.end(), matches.begin());
+ matches.resize(matchesEnd - matches.begin());
+ return !matches.empty();
+ });
}
bool CAndroidJoystickState::ContainsAxis(int axisId, const JoystickAxes& axes)
{
- return GetAxis({ axisId }, axes) != axes.cend();
+ return GetAxis({axisId}, axes) != axes.cend();
}
-bool CAndroidJoystickState::GetAxesIndex(const std::vector<int>& axisIds, const JoystickAxes& axes, size_t& axesIndex)
+bool CAndroidJoystickState::GetAxesIndex(const std::vector<int>& axisIds,
+ const JoystickAxes& axes,
+ size_t& axesIndex)
{
auto axesIt = GetAxis(axisIds, axes);
if (axesIt == axes.end())
diff --git a/xbmc/platform/android/peripherals/AndroidJoystickState.h b/xbmc/platform/android/peripherals/AndroidJoystickState.h
index 07652d79e9..550222d6f7 100644
--- a/xbmc/platform/android/peripherals/AndroidJoystickState.h
+++ b/xbmc/platform/android/peripherals/AndroidJoystickState.h
@@ -18,78 +18,113 @@
struct AInputEvent;
class CJNIViewInputDevice;
+namespace KODI
+{
+namespace JOYSTICK
+{
+class IButtonMap;
+} // namespace JOYSTICK
+} // namespace KODI
+
namespace PERIPHERALS
{
- class CAndroidJoystickState
+class CAndroidJoystickState
+{
+public:
+ CAndroidJoystickState() = default;
+ CAndroidJoystickState(CAndroidJoystickState&& other) noexcept;
+ virtual ~CAndroidJoystickState();
+
+ int GetDeviceId() const { return m_deviceId; }
+
+ unsigned int GetButtonCount() const { return static_cast<unsigned int>(m_buttons.size()); }
+ unsigned int GetAxisCount() const { return static_cast<unsigned int>(m_axes.size()); }
+
+ /*!
+ * \brief Initialize the joystick object
+ *
+ * Joystick will be initialized before the first call to GetEvents().
+ */
+ bool Initialize(const CJNIViewInputDevice& inputDevice);
+
+ /*!
+ * \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();
+
+ /*!
+ * \brief Processes the given input event.
+ */
+ bool ProcessEvent(const AInputEvent* event);
+
+ /*!
+ * \brief Get events that have occurred since the last call to GetEvents()
+ */
+ void GetEvents(std::vector<kodi::addon::PeripheralEvent>& events);
+
+private:
+ bool SetButtonValue(int axisId, JOYSTICK_STATE_BUTTON buttonValue);
+ bool SetAxisValue(const std::vector<int>& axisIds, JOYSTICK_STATE_AXIS axisValue);
+
+ 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);
+
+ struct JoystickAxis
{
- public:
- CAndroidJoystickState() = default;
- CAndroidJoystickState(CAndroidJoystickState&& other) noexcept;
- virtual ~CAndroidJoystickState();
-
- int GetDeviceId() const { return m_deviceId; }
-
- unsigned int GetButtonCount() const { return static_cast<unsigned int>(m_buttons.size()); }
- 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().
- */
- bool Initialize(const CJNIViewInputDevice& inputDevice);
-
- /*!
- * Deinitialize the joystick object. GetEvents() will not be called after
- * deinitialization.
- */
- void Deinitialize();
-
- /*!
- * Processes the given input event.
- */
- bool ProcessEvent(const AInputEvent* event);
-
- /*!
- * Get events that have occurred since the last call to GetEvents()
- */
- void GetEvents(std::vector<kodi::addon::PeripheralEvent>& events);
-
- private:
- bool SetButtonValue(int axisId, JOYSTICK_STATE_BUTTON buttonValue);
- bool SetAxisValue(const std::vector<int>& axisIds, JOYSTICK_STATE_AXIS axisValue);
-
- void GetButtonEvents(std::vector<kodi::addon::PeripheralEvent>& events);
- void GetAxisEvents(std::vector<kodi::addon::PeripheralEvent>& events) 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);
-
- struct JoystickAxis
- {
- std::vector<int> ids;
- float flat = 0.0f;
- float fuzz = 0.0f;
- float min = 0.0f;
- float max = 0.0f;
- float range = 0.0f;
- float resolution = 0.0f;
- };
-
- using JoystickAxes = std::vector<JoystickAxis>;
-
- static JoystickAxes::const_iterator GetAxis(const std::vector<int>& axisIds, const JoystickAxes& axes);
- static bool ContainsAxis(int axisId, const JoystickAxes& axes);
- static bool GetAxesIndex(const std::vector<int>& axisIds, const JoystickAxes& axes, size_t& axesIndex);
-
- int m_deviceId = -1;
-
- JoystickAxes m_buttons;
- JoystickAxes m_axes;
-
- std::vector<JOYSTICK_STATE_AXIS> m_analogState;
-
- CCriticalSection m_eventMutex;
- std::vector<kodi::addon::PeripheralEvent> m_digitalEvents;
+ std::vector<int> ids;
+ float flat = 0.0f;
+ float fuzz = 0.0f;
+ float min = 0.0f;
+ float max = 0.0f;
+ float range = 0.0f;
+ float resolution = 0.0f;
};
-}
+
+ using JoystickAxes = std::vector<JoystickAxis>;
+
+ static JoystickAxes::const_iterator GetAxis(const std::vector<int>& axisIds,
+ const JoystickAxes& axes);
+ static bool ContainsAxis(int axisId, const JoystickAxes& axes);
+ static bool GetAxesIndex(const std::vector<int>& axisIds,
+ const JoystickAxes& axes,
+ size_t& axesIndex);
+
+ int m_deviceId = -1;
+
+ JoystickAxes m_buttons;
+ JoystickAxes m_axes;
+
+ std::vector<JOYSTICK_STATE_AXIS> m_analogState;
+
+ CCriticalSection m_eventMutex;
+ std::vector<kodi::addon::PeripheralEvent> m_digitalEvents;
+};
+} // namespace PERIPHERALS
diff --git a/xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp b/xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp
index 4be930710e..e39050a0c4 100644
--- a/xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp
+++ b/xbmc/platform/android/peripherals/AndroidJoystickTranslator.cpp
@@ -8,327 +8,740 @@
#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)
+const char* CAndroidJoystickTranslator::TranslateAxis(int axisId)
{
switch (axisId)
{
- case AMOTION_EVENT_AXIS_X: return "AMOTION_EVENT_AXIS_X";
- case AMOTION_EVENT_AXIS_Y: return "AMOTION_EVENT_AXIS_Y";
- case AMOTION_EVENT_AXIS_PRESSURE: return "AMOTION_EVENT_AXIS_PRESSURE";
- case AMOTION_EVENT_AXIS_SIZE: return "AMOTION_EVENT_AXIS_SIZE";
- case AMOTION_EVENT_AXIS_TOUCH_MAJOR: return "AMOTION_EVENT_AXIS_TOUCH_MAJOR";
- case AMOTION_EVENT_AXIS_TOUCH_MINOR: return "AMOTION_EVENT_AXIS_TOUCH_MINOR";
- case AMOTION_EVENT_AXIS_TOOL_MAJOR: return "AMOTION_EVENT_AXIS_TOOL_MAJOR";
- case AMOTION_EVENT_AXIS_TOOL_MINOR: return "AMOTION_EVENT_AXIS_TOOL_MINOR";
- case AMOTION_EVENT_AXIS_ORIENTATION: return "AMOTION_EVENT_AXIS_ORIENTATION";
- case AMOTION_EVENT_AXIS_VSCROLL: return "AMOTION_EVENT_AXIS_VSCROLL";
- case AMOTION_EVENT_AXIS_HSCROLL: return "AMOTION_EVENT_AXIS_HSCROLL";
- case AMOTION_EVENT_AXIS_Z: return "AMOTION_EVENT_AXIS_Z";
- case AMOTION_EVENT_AXIS_RX: return "AMOTION_EVENT_AXIS_RX";
- case AMOTION_EVENT_AXIS_RY: return "AMOTION_EVENT_AXIS_RY";
- case AMOTION_EVENT_AXIS_RZ: return "AMOTION_EVENT_AXIS_RZ";
- case AMOTION_EVENT_AXIS_HAT_X: return "AMOTION_EVENT_AXIS_HAT_X";
- case AMOTION_EVENT_AXIS_HAT_Y: return "AMOTION_EVENT_AXIS_HAT_Y";
- case AMOTION_EVENT_AXIS_LTRIGGER: return "AMOTION_EVENT_AXIS_LTRIGGER";
- case AMOTION_EVENT_AXIS_RTRIGGER: return "AMOTION_EVENT_AXIS_RTRIGGER";
- case AMOTION_EVENT_AXIS_THROTTLE: return "AMOTION_EVENT_AXIS_THROTTLE";
- case AMOTION_EVENT_AXIS_RUDDER: return "AMOTION_EVENT_AXIS_RUDDER";
- case AMOTION_EVENT_AXIS_WHEEL: return "AMOTION_EVENT_AXIS_WHEEL";
- case AMOTION_EVENT_AXIS_GAS: return "AMOTION_EVENT_AXIS_GAS";
- case AMOTION_EVENT_AXIS_BRAKE: return "AMOTION_EVENT_AXIS_BRAKE";
- case AMOTION_EVENT_AXIS_DISTANCE: return "AMOTION_EVENT_AXIS_DISTANCE";
- case AMOTION_EVENT_AXIS_TILT: return "AMOTION_EVENT_AXIS_TILT";
- case AMOTION_EVENT_AXIS_GENERIC_1: return "AMOTION_EVENT_AXIS_GENERIC_1";
- case AMOTION_EVENT_AXIS_GENERIC_2: return "AMOTION_EVENT_AXIS_GENERIC_2";
- case AMOTION_EVENT_AXIS_GENERIC_3: return "AMOTION_EVENT_AXIS_GENERIC_3";
- case AMOTION_EVENT_AXIS_GENERIC_4: return "AMOTION_EVENT_AXIS_GENERIC_4";
- case AMOTION_EVENT_AXIS_GENERIC_5: return "AMOTION_EVENT_AXIS_GENERIC_5";
- case AMOTION_EVENT_AXIS_GENERIC_6: return "AMOTION_EVENT_AXIS_GENERIC_6";
- case AMOTION_EVENT_AXIS_GENERIC_7: return "AMOTION_EVENT_AXIS_GENERIC_7";
- case AMOTION_EVENT_AXIS_GENERIC_8: return "AMOTION_EVENT_AXIS_GENERIC_8";
- case AMOTION_EVENT_AXIS_GENERIC_9: return "AMOTION_EVENT_AXIS_GENERIC_9";
- case AMOTION_EVENT_AXIS_GENERIC_10: return "AMOTION_EVENT_AXIS_GENERIC_10";
- case AMOTION_EVENT_AXIS_GENERIC_11: return "AMOTION_EVENT_AXIS_GENERIC_11";
- case AMOTION_EVENT_AXIS_GENERIC_12: return "AMOTION_EVENT_AXIS_GENERIC_12";
- case AMOTION_EVENT_AXIS_GENERIC_13: return "AMOTION_EVENT_AXIS_GENERIC_13";
- case AMOTION_EVENT_AXIS_GENERIC_14: return "AMOTION_EVENT_AXIS_GENERIC_14";
- case AMOTION_EVENT_AXIS_GENERIC_15: return "AMOTION_EVENT_AXIS_GENERIC_15";
- case AMOTION_EVENT_AXIS_GENERIC_16: return "AMOTION_EVENT_AXIS_GENERIC_16";
+ case AMOTION_EVENT_AXIS_X:
+ return "AMOTION_EVENT_AXIS_X";
+ case AMOTION_EVENT_AXIS_Y:
+ return "AMOTION_EVENT_AXIS_Y";
+ case AMOTION_EVENT_AXIS_PRESSURE:
+ return "AMOTION_EVENT_AXIS_PRESSURE";
+ case AMOTION_EVENT_AXIS_SIZE:
+ return "AMOTION_EVENT_AXIS_SIZE";
+ case AMOTION_EVENT_AXIS_TOUCH_MAJOR:
+ return "AMOTION_EVENT_AXIS_TOUCH_MAJOR";
+ case AMOTION_EVENT_AXIS_TOUCH_MINOR:
+ return "AMOTION_EVENT_AXIS_TOUCH_MINOR";
+ case AMOTION_EVENT_AXIS_TOOL_MAJOR:
+ return "AMOTION_EVENT_AXIS_TOOL_MAJOR";
+ case AMOTION_EVENT_AXIS_TOOL_MINOR:
+ return "AMOTION_EVENT_AXIS_TOOL_MINOR";
+ case AMOTION_EVENT_AXIS_ORIENTATION:
+ return "AMOTION_EVENT_AXIS_ORIENTATION";
+ case AMOTION_EVENT_AXIS_VSCROLL:
+ return "AMOTION_EVENT_AXIS_VSCROLL";
+ case AMOTION_EVENT_AXIS_HSCROLL:
+ return "AMOTION_EVENT_AXIS_HSCROLL";
+ case AMOTION_EVENT_AXIS_Z:
+ return "AMOTION_EVENT_AXIS_Z";
+ case AMOTION_EVENT_AXIS_RX:
+ return "AMOTION_EVENT_AXIS_RX";
+ case AMOTION_EVENT_AXIS_RY:
+ return "AMOTION_EVENT_AXIS_RY";
+ case AMOTION_EVENT_AXIS_RZ:
+ return "AMOTION_EVENT_AXIS_RZ";
+ case AMOTION_EVENT_AXIS_HAT_X:
+ return "AMOTION_EVENT_AXIS_HAT_X";
+ case AMOTION_EVENT_AXIS_HAT_Y:
+ return "AMOTION_EVENT_AXIS_HAT_Y";
+ case AMOTION_EVENT_AXIS_LTRIGGER:
+ return "AMOTION_EVENT_AXIS_LTRIGGER";
+ case AMOTION_EVENT_AXIS_RTRIGGER:
+ return "AMOTION_EVENT_AXIS_RTRIGGER";
+ case AMOTION_EVENT_AXIS_THROTTLE:
+ return "AMOTION_EVENT_AXIS_THROTTLE";
+ case AMOTION_EVENT_AXIS_RUDDER:
+ return "AMOTION_EVENT_AXIS_RUDDER";
+ case AMOTION_EVENT_AXIS_WHEEL:
+ return "AMOTION_EVENT_AXIS_WHEEL";
+ case AMOTION_EVENT_AXIS_GAS:
+ return "AMOTION_EVENT_AXIS_GAS";
+ case AMOTION_EVENT_AXIS_BRAKE:
+ return "AMOTION_EVENT_AXIS_BRAKE";
+ case AMOTION_EVENT_AXIS_DISTANCE:
+ return "AMOTION_EVENT_AXIS_DISTANCE";
+ case AMOTION_EVENT_AXIS_TILT:
+ return "AMOTION_EVENT_AXIS_TILT";
+ case AMOTION_EVENT_AXIS_GENERIC_1:
+ return "AMOTION_EVENT_AXIS_GENERIC_1";
+ case AMOTION_EVENT_AXIS_GENERIC_2:
+ return "AMOTION_EVENT_AXIS_GENERIC_2";
+ case AMOTION_EVENT_AXIS_GENERIC_3:
+ return "AMOTION_EVENT_AXIS_GENERIC_3";
+ case AMOTION_EVENT_AXIS_GENERIC_4:
+ return "AMOTION_EVENT_AXIS_GENERIC_4";
+ case AMOTION_EVENT_AXIS_GENERIC_5:
+ return "AMOTION_EVENT_AXIS_GENERIC_5";
+ case AMOTION_EVENT_AXIS_GENERIC_6:
+ return "AMOTION_EVENT_AXIS_GENERIC_6";
+ case AMOTION_EVENT_AXIS_GENERIC_7:
+ return "AMOTION_EVENT_AXIS_GENERIC_7";
+ case AMOTION_EVENT_AXIS_GENERIC_8:
+ return "AMOTION_EVENT_AXIS_GENERIC_8";
+ case AMOTION_EVENT_AXIS_GENERIC_9:
+ return "AMOTION_EVENT_AXIS_GENERIC_9";
+ case AMOTION_EVENT_AXIS_GENERIC_10:
+ return "AMOTION_EVENT_AXIS_GENERIC_10";
+ case AMOTION_EVENT_AXIS_GENERIC_11:
+ return "AMOTION_EVENT_AXIS_GENERIC_11";
+ case AMOTION_EVENT_AXIS_GENERIC_12:
+ return "AMOTION_EVENT_AXIS_GENERIC_12";
+ case AMOTION_EVENT_AXIS_GENERIC_13:
+ return "AMOTION_EVENT_AXIS_GENERIC_13";
+ case AMOTION_EVENT_AXIS_GENERIC_14:
+ return "AMOTION_EVENT_AXIS_GENERIC_14";
+ case AMOTION_EVENT_AXIS_GENERIC_15:
+ return "AMOTION_EVENT_AXIS_GENERIC_15";
+ case AMOTION_EVENT_AXIS_GENERIC_16:
+ return "AMOTION_EVENT_AXIS_GENERIC_16";
}
return "unknown";
}
-const char *CAndroidJoystickTranslator::TranslateKeyCode(int keyCode)
+const char* CAndroidJoystickTranslator::TranslateKeyCode(int keyCode)
{
switch (keyCode)
{
- case AKEYCODE_UNKNOWN: return "AKEYCODE_UNKNOWN";
- case AKEYCODE_SOFT_LEFT: return "AKEYCODE_SOFT_LEFT";
- case AKEYCODE_SOFT_RIGHT: return "AKEYCODE_SOFT_RIGHT";
- case AKEYCODE_HOME: return "AKEYCODE_HOME";
- case AKEYCODE_BACK: return "AKEYCODE_BACK";
- case AKEYCODE_CALL: return "AKEYCODE_CALL";
- case AKEYCODE_ENDCALL: return "AKEYCODE_ENDCALL";
- case AKEYCODE_0: return "AKEYCODE_0";
- case AKEYCODE_1: return "AKEYCODE_1";
- case AKEYCODE_2: return "AKEYCODE_2";
- case AKEYCODE_3: return "AKEYCODE_3";
- case AKEYCODE_4: return "AKEYCODE_4";
- case AKEYCODE_5: return "AKEYCODE_5";
- case AKEYCODE_6: return "AKEYCODE_6";
- case AKEYCODE_7: return "AKEYCODE_7";
- case AKEYCODE_8: return "AKEYCODE_8";
- case AKEYCODE_9: return "AKEYCODE_9";
- case AKEYCODE_STAR: return "AKEYCODE_STAR";
- case AKEYCODE_POUND: return "AKEYCODE_POUND";
- case AKEYCODE_DPAD_UP: return "AKEYCODE_DPAD_UP";
- case AKEYCODE_DPAD_DOWN: return "AKEYCODE_DPAD_DOWN";
- case AKEYCODE_DPAD_LEFT: return "AKEYCODE_DPAD_LEFT";
- case AKEYCODE_DPAD_RIGHT: return "AKEYCODE_DPAD_RIGHT";
- case AKEYCODE_DPAD_CENTER: return "AKEYCODE_DPAD_CENTER";
- case AKEYCODE_VOLUME_UP: return "AKEYCODE_VOLUME_UP";
- case AKEYCODE_VOLUME_DOWN: return "AKEYCODE_VOLUME_DOWN";
- case AKEYCODE_POWER: return "AKEYCODE_POWER";
- case AKEYCODE_CAMERA: return "AKEYCODE_CAMERA";
- case AKEYCODE_CLEAR: return "AKEYCODE_CLEAR";
- case AKEYCODE_A: return "AKEYCODE_A";
- case AKEYCODE_B: return "AKEYCODE_B";
- case AKEYCODE_C: return "AKEYCODE_C";
- case AKEYCODE_D: return "AKEYCODE_D";
- case AKEYCODE_E: return "AKEYCODE_E";
- case AKEYCODE_F: return "AKEYCODE_F";
- case AKEYCODE_G: return "AKEYCODE_G";
- case AKEYCODE_H: return "AKEYCODE_H";
- case AKEYCODE_I: return "AKEYCODE_I";
- case AKEYCODE_J: return "AKEYCODE_J";
- case AKEYCODE_K: return "AKEYCODE_K";
- case AKEYCODE_L: return "AKEYCODE_L";
- case AKEYCODE_M: return "AKEYCODE_M";
- case AKEYCODE_N: return "AKEYCODE_N";
- case AKEYCODE_O: return "AKEYCODE_O";
- case AKEYCODE_P: return "AKEYCODE_P";
- case AKEYCODE_Q: return "AKEYCODE_Q";
- case AKEYCODE_R: return "AKEYCODE_R";
- case AKEYCODE_S: return "AKEYCODE_S";
- case AKEYCODE_T: return "AKEYCODE_T";
- case AKEYCODE_U: return "AKEYCODE_U";
- case AKEYCODE_V: return "AKEYCODE_V";
- case AKEYCODE_W: return "AKEYCODE_W";
- case AKEYCODE_X: return "AKEYCODE_X";
- case AKEYCODE_Y: return "AKEYCODE_Y";
- case AKEYCODE_Z: return "AKEYCODE_Z";
- case AKEYCODE_COMMA: return "AKEYCODE_COMMA";
- case AKEYCODE_PERIOD: return "AKEYCODE_PERIOD";
- case AKEYCODE_ALT_LEFT: return "AKEYCODE_ALT_LEFT";
- case AKEYCODE_ALT_RIGHT: return "AKEYCODE_ALT_RIGHT";
- case AKEYCODE_SHIFT_LEFT: return "AKEYCODE_SHIFT_LEFT";
- case AKEYCODE_SHIFT_RIGHT: return "AKEYCODE_SHIFT_RIGHT";
- case AKEYCODE_TAB: return "AKEYCODE_TAB";
- case AKEYCODE_SPACE: return "AKEYCODE_SPACE";
- case AKEYCODE_SYM: return "AKEYCODE_SYM";
- case AKEYCODE_EXPLORER: return "AKEYCODE_EXPLORER";
- case AKEYCODE_ENVELOPE: return "AKEYCODE_ENVELOPE";
- case AKEYCODE_ENTER: return "AKEYCODE_ENTER";
- case AKEYCODE_DEL: return "AKEYCODE_DEL";
- case AKEYCODE_GRAVE: return "AKEYCODE_GRAVE";
- case AKEYCODE_MINUS: return "AKEYCODE_MINUS";
- case AKEYCODE_EQUALS: return "AKEYCODE_EQUALS";
- case AKEYCODE_LEFT_BRACKET: return "AKEYCODE_LEFT_BRACKET";
- case AKEYCODE_RIGHT_BRACKET: return "AKEYCODE_RIGHT_BRACKET";
- case AKEYCODE_BACKSLASH: return "AKEYCODE_BACKSLASH";
- case AKEYCODE_SEMICOLON: return "AKEYCODE_SEMICOLON";
- case AKEYCODE_APOSTROPHE: return "AKEYCODE_APOSTROPHE";
- case AKEYCODE_SLASH: return "AKEYCODE_SLASH";
- case AKEYCODE_AT: return "AKEYCODE_AT";
- case AKEYCODE_NUM: return "AKEYCODE_NUM";
- case AKEYCODE_HEADSETHOOK: return "AKEYCODE_HEADSETHOOK";
- case AKEYCODE_FOCUS: return "AKEYCODE_FOCUS";
- case AKEYCODE_PLUS: return "AKEYCODE_PLUS";
- case AKEYCODE_MENU: return "AKEYCODE_MENU";
- case AKEYCODE_NOTIFICATION: return "AKEYCODE_NOTIFICATION";
- case AKEYCODE_SEARCH: return "AKEYCODE_SEARCH";
- case AKEYCODE_MEDIA_PLAY_PAUSE: return "AKEYCODE_MEDIA_PLAY_PAUSE";
- case AKEYCODE_MEDIA_STOP: return "AKEYCODE_MEDIA_STOP";
- case AKEYCODE_MEDIA_NEXT: return "AKEYCODE_MEDIA_NEXT";
- case AKEYCODE_MEDIA_PREVIOUS: return "AKEYCODE_MEDIA_PREVIOUS";
- case AKEYCODE_MEDIA_REWIND: return "AKEYCODE_MEDIA_REWIND";
- case AKEYCODE_MEDIA_FAST_FORWARD: return "AKEYCODE_MEDIA_FAST_FORWARD";
- case AKEYCODE_MUTE: return "AKEYCODE_MUTE";
- case AKEYCODE_PAGE_UP: return "AKEYCODE_PAGE_UP";
- case AKEYCODE_PAGE_DOWN: return "AKEYCODE_PAGE_DOWN";
- case AKEYCODE_PICTSYMBOLS: return "AKEYCODE_PICTSYMBOLS";
- case AKEYCODE_SWITCH_CHARSET: return "AKEYCODE_SWITCH_CHARSET";
- case AKEYCODE_BUTTON_A: return "AKEYCODE_BUTTON_A";
- case AKEYCODE_BUTTON_B: return "AKEYCODE_BUTTON_B";
- case AKEYCODE_BUTTON_C: return "AKEYCODE_BUTTON_C";
- case AKEYCODE_BUTTON_X: return "AKEYCODE_BUTTON_X";
- case AKEYCODE_BUTTON_Y: return "AKEYCODE_BUTTON_Y";
- case AKEYCODE_BUTTON_Z: return "AKEYCODE_BUTTON_Z";
- case AKEYCODE_BUTTON_L1: return "AKEYCODE_BUTTON_L1";
- case AKEYCODE_BUTTON_R1: return "AKEYCODE_BUTTON_R1";
- case AKEYCODE_BUTTON_L2: return "AKEYCODE_BUTTON_L2";
- case AKEYCODE_BUTTON_R2: return "AKEYCODE_BUTTON_R2";
- case AKEYCODE_BUTTON_THUMBL: return "AKEYCODE_BUTTON_THUMBL";
- case AKEYCODE_BUTTON_THUMBR: return "AKEYCODE_BUTTON_THUMBR";
- case AKEYCODE_BUTTON_START: return "AKEYCODE_BUTTON_START";
- case AKEYCODE_BUTTON_SELECT: return "AKEYCODE_BUTTON_SELECT";
- case AKEYCODE_BUTTON_MODE: return "AKEYCODE_BUTTON_MODE";
- case AKEYCODE_ESCAPE: return "AKEYCODE_ESCAPE";
- case AKEYCODE_FORWARD_DEL: return "AKEYCODE_FORWARD_DEL";
- case AKEYCODE_CTRL_LEFT: return "AKEYCODE_CTRL_LEFT";
- case AKEYCODE_CTRL_RIGHT: return "AKEYCODE_CTRL_RIGHT";
- case AKEYCODE_CAPS_LOCK: return "AKEYCODE_CAPS_LOCK";
- case AKEYCODE_SCROLL_LOCK: return "AKEYCODE_SCROLL_LOCK";
- case AKEYCODE_META_LEFT: return "AKEYCODE_META_LEFT";
- case AKEYCODE_META_RIGHT: return "AKEYCODE_META_RIGHT";
- case AKEYCODE_FUNCTION: return "AKEYCODE_FUNCTION";
- case AKEYCODE_SYSRQ: return "AKEYCODE_SYSRQ";
- case AKEYCODE_BREAK: return "AKEYCODE_BREAK";
- case AKEYCODE_MOVE_HOME: return "AKEYCODE_MOVE_HOME";
- case AKEYCODE_MOVE_END: return "AKEYCODE_MOVE_END";
- case AKEYCODE_INSERT: return "AKEYCODE_INSERT";
- case AKEYCODE_FORWARD: return "AKEYCODE_FORWARD";
- case AKEYCODE_MEDIA_PLAY: return "AKEYCODE_MEDIA_PLAY";
- case AKEYCODE_MEDIA_PAUSE: return "AKEYCODE_MEDIA_PAUSE";
- case AKEYCODE_MEDIA_CLOSE: return "AKEYCODE_MEDIA_CLOSE";
- case AKEYCODE_MEDIA_EJECT: return "AKEYCODE_MEDIA_EJECT";
- case AKEYCODE_MEDIA_RECORD: return "AKEYCODE_MEDIA_RECORD";
- case AKEYCODE_F1: return "AKEYCODE_F1";
- case AKEYCODE_F2: return "AKEYCODE_F2";
- case AKEYCODE_F3: return "AKEYCODE_F3";
- case AKEYCODE_F4: return "AKEYCODE_F4";
- case AKEYCODE_F5: return "AKEYCODE_F5";
- case AKEYCODE_F6: return "AKEYCODE_F6";
- case AKEYCODE_F7: return "AKEYCODE_F7";
- case AKEYCODE_F8: return "AKEYCODE_F8";
- case AKEYCODE_F9: return "AKEYCODE_F9";
- case AKEYCODE_F10: return "AKEYCODE_F10";
- case AKEYCODE_F11: return "AKEYCODE_F11";
- case AKEYCODE_F12: return "AKEYCODE_F12";
- case AKEYCODE_NUM_LOCK: return "AKEYCODE_NUM_LOCK";
- case AKEYCODE_NUMPAD_0: return "AKEYCODE_NUMPAD_0";
- case AKEYCODE_NUMPAD_1: return "AKEYCODE_NUMPAD_1";
- case AKEYCODE_NUMPAD_2: return "AKEYCODE_NUMPAD_2";
- case AKEYCODE_NUMPAD_3: return "AKEYCODE_NUMPAD_3";
- case AKEYCODE_NUMPAD_4: return "AKEYCODE_NUMPAD_4";
- case AKEYCODE_NUMPAD_5: return "AKEYCODE_NUMPAD_5";
- case AKEYCODE_NUMPAD_6: return "AKEYCODE_NUMPAD_6";
- case AKEYCODE_NUMPAD_7: return "AKEYCODE_NUMPAD_7";
- case AKEYCODE_NUMPAD_8: return "AKEYCODE_NUMPAD_8";
- case AKEYCODE_NUMPAD_9: return "AKEYCODE_NUMPAD_9";
- case AKEYCODE_NUMPAD_DIVIDE: return "AKEYCODE_NUMPAD_DIVIDE";
- case AKEYCODE_NUMPAD_MULTIPLY: return "AKEYCODE_NUMPAD_MULTIPLY";
- case AKEYCODE_NUMPAD_SUBTRACT: return "AKEYCODE_NUMPAD_SUBTRACT";
- case AKEYCODE_NUMPAD_ADD: return "AKEYCODE_NUMPAD_ADD";
- case AKEYCODE_NUMPAD_DOT: return "AKEYCODE_NUMPAD_DOT";
- case AKEYCODE_NUMPAD_COMMA: return "AKEYCODE_NUMPAD_COMMA";
- case AKEYCODE_NUMPAD_ENTER: return "AKEYCODE_NUMPAD_ENTER";
- case AKEYCODE_NUMPAD_EQUALS: return "AKEYCODE_NUMPAD_EQUALS";
- case AKEYCODE_NUMPAD_LEFT_PAREN: return "AKEYCODE_NUMPAD_LEFT_PAREN";
- case AKEYCODE_NUMPAD_RIGHT_PAREN: return "AKEYCODE_NUMPAD_RIGHT_PAREN";
- case AKEYCODE_VOLUME_MUTE: return "AKEYCODE_VOLUME_MUTE";
- case AKEYCODE_INFO: return "AKEYCODE_INFO";
- case AKEYCODE_CHANNEL_UP: return "AKEYCODE_CHANNEL_UP";
- case AKEYCODE_CHANNEL_DOWN: return "AKEYCODE_CHANNEL_DOWN";
- case AKEYCODE_ZOOM_IN: return "AKEYCODE_ZOOM_IN";
- case AKEYCODE_ZOOM_OUT: return "AKEYCODE_ZOOM_OUT";
- case AKEYCODE_TV: return "AKEYCODE_TV";
- case AKEYCODE_WINDOW: return "AKEYCODE_WINDOW";
- case AKEYCODE_GUIDE: return "AKEYCODE_GUIDE";
- case AKEYCODE_DVR: return "AKEYCODE_DVR";
- case AKEYCODE_BOOKMARK: return "AKEYCODE_BOOKMARK";
- case AKEYCODE_CAPTIONS: return "AKEYCODE_CAPTIONS";
- case AKEYCODE_SETTINGS: return "AKEYCODE_SETTINGS";
- case AKEYCODE_TV_POWER: return "AKEYCODE_TV_POWER";
- case AKEYCODE_TV_INPUT: return "AKEYCODE_TV_INPUT";
- case AKEYCODE_STB_POWER: return "AKEYCODE_STB_POWER";
- case AKEYCODE_STB_INPUT: return "AKEYCODE_STB_INPUT";
- case AKEYCODE_AVR_POWER: return "AKEYCODE_AVR_POWER";
- case AKEYCODE_AVR_INPUT: return "AKEYCODE_AVR_INPUT";
- case AKEYCODE_PROG_RED: return "AKEYCODE_PROG_RED";
- case AKEYCODE_PROG_GREEN: return "AKEYCODE_PROG_GREEN";
- case AKEYCODE_PROG_YELLOW: return "AKEYCODE_PROG_YELLOW";
- case AKEYCODE_PROG_BLUE: return "AKEYCODE_PROG_BLUE";
- case AKEYCODE_APP_SWITCH: return "AKEYCODE_APP_SWITCH";
- case AKEYCODE_BUTTON_1: return "AKEYCODE_BUTTON_1";
- case AKEYCODE_BUTTON_2: return "AKEYCODE_BUTTON_2";
- case AKEYCODE_BUTTON_3: return "AKEYCODE_BUTTON_3";
- case AKEYCODE_BUTTON_4: return "AKEYCODE_BUTTON_4";
- case AKEYCODE_BUTTON_5: return "AKEYCODE_BUTTON_5";
- case AKEYCODE_BUTTON_6: return "AKEYCODE_BUTTON_6";
- case AKEYCODE_BUTTON_7: return "AKEYCODE_BUTTON_7";
- case AKEYCODE_BUTTON_8: return "AKEYCODE_BUTTON_8";
- case AKEYCODE_BUTTON_9: return "AKEYCODE_BUTTON_9";
- case AKEYCODE_BUTTON_10: return "AKEYCODE_BUTTON_10";
- case AKEYCODE_BUTTON_11: return "AKEYCODE_BUTTON_11";
- case AKEYCODE_BUTTON_12: return "AKEYCODE_BUTTON_12";
- case AKEYCODE_BUTTON_13: return "AKEYCODE_BUTTON_13";
- case AKEYCODE_BUTTON_14: return "AKEYCODE_BUTTON_14";
- case AKEYCODE_BUTTON_15: return "AKEYCODE_BUTTON_15";
- case AKEYCODE_BUTTON_16: return "AKEYCODE_BUTTON_16";
- case AKEYCODE_LANGUAGE_SWITCH: return "AKEYCODE_LANGUAGE_SWITCH";
- case AKEYCODE_MANNER_MODE: return "AKEYCODE_MANNER_MODE";
- case AKEYCODE_3D_MODE: return "AKEYCODE_3D_MODE";
- case AKEYCODE_CONTACTS: return "AKEYCODE_CONTACTS";
- case AKEYCODE_CALENDAR: return "AKEYCODE_CALENDAR";
- case AKEYCODE_MUSIC: return "AKEYCODE_MUSIC";
- case AKEYCODE_CALCULATOR: return "AKEYCODE_CALCULATOR";
- case AKEYCODE_ZENKAKU_HANKAKU: return "AKEYCODE_ZENKAKU_HANKAKU";
- case AKEYCODE_EISU: return "AKEYCODE_EISU";
- case AKEYCODE_MUHENKAN: return "AKEYCODE_MUHENKAN";
- case AKEYCODE_HENKAN: return "AKEYCODE_HENKAN";
- case AKEYCODE_KATAKANA_HIRAGANA: return "AKEYCODE_KATAKANA_HIRAGANA";
- case AKEYCODE_YEN: return "AKEYCODE_YEN";
- case AKEYCODE_RO: return "AKEYCODE_RO";
- case AKEYCODE_KANA: return "AKEYCODE_KANA";
- case AKEYCODE_ASSIST: return "AKEYCODE_ASSIST";
- case AKEYCODE_BRIGHTNESS_DOWN: return "AKEYCODE_BRIGHTNESS_DOWN";
- case AKEYCODE_BRIGHTNESS_UP: return "AKEYCODE_BRIGHTNESS_UP";
- case AKEYCODE_MEDIA_AUDIO_TRACK: return "AKEYCODE_MEDIA_AUDIO_TRACK";
- case AKEYCODE_SLEEP: return "AKEYCODE_SLEEP";
- case AKEYCODE_WAKEUP: return "AKEYCODE_WAKEUP";
- case AKEYCODE_PAIRING: return "AKEYCODE_PAIRING";
- case AKEYCODE_MEDIA_TOP_MENU: return "AKEYCODE_MEDIA_TOP_MENU";
- case AKEYCODE_11: return "AKEYCODE_11";
- case AKEYCODE_12: return "AKEYCODE_12";
- case AKEYCODE_LAST_CHANNEL: return "AKEYCODE_LAST_CHANNEL";
- case AKEYCODE_TV_DATA_SERVICE: return "AKEYCODE_TV_DATA_SERVICE";
- case AKEYCODE_VOICE_ASSIST: return "AKEYCODE_VOICE_ASSIST";
- case AKEYCODE_TV_RADIO_SERVICE: return "AKEYCODE_TV_RADIO_SERVICE";
- case AKEYCODE_TV_TELETEXT: return "AKEYCODE_TV_TELETEXT";
- case AKEYCODE_TV_NUMBER_ENTRY: return "AKEYCODE_TV_NUMBER_ENTRY";
- case AKEYCODE_TV_TERRESTRIAL_ANALOG: return "AKEYCODE_TV_TERRESTRIAL_ANALOG";
- case AKEYCODE_TV_TERRESTRIAL_DIGITAL: return "AKEYCODE_TV_TERRESTRIAL_DIGITAL";
- case AKEYCODE_TV_SATELLITE: return "AKEYCODE_TV_SATELLITE";
- case AKEYCODE_TV_SATELLITE_BS: return "AKEYCODE_TV_SATELLITE_BS";
- case AKEYCODE_TV_SATELLITE_CS: return "AKEYCODE_TV_SATELLITE_CS";
- case AKEYCODE_TV_SATELLITE_SERVICE: return "AKEYCODE_TV_SATELLITE_SERVICE";
- case AKEYCODE_TV_NETWORK: return "AKEYCODE_TV_NETWORK";
- case AKEYCODE_TV_ANTENNA_CABLE: return "AKEYCODE_TV_ANTENNA_CABLE";
- case AKEYCODE_TV_INPUT_HDMI_1: return "AKEYCODE_TV_INPUT_HDMI_1";
- case AKEYCODE_TV_INPUT_HDMI_2: return "AKEYCODE_TV_INPUT_HDMI_2";
- case AKEYCODE_TV_INPUT_HDMI_3: return "AKEYCODE_TV_INPUT_HDMI_3";
- case AKEYCODE_TV_INPUT_HDMI_4: return "AKEYCODE_TV_INPUT_HDMI_4";
- case AKEYCODE_TV_INPUT_COMPOSITE_1: return "AKEYCODE_TV_INPUT_COMPOSITE_1";
- case AKEYCODE_TV_INPUT_COMPOSITE_2: return "AKEYCODE_TV_INPUT_COMPOSITE_2";
- case AKEYCODE_TV_INPUT_COMPONENT_1: return "AKEYCODE_TV_INPUT_COMPONENT_1";
- case AKEYCODE_TV_INPUT_COMPONENT_2: return "AKEYCODE_TV_INPUT_COMPONENT_2";
- case AKEYCODE_TV_INPUT_VGA_1: return "AKEYCODE_TV_INPUT_VGA_1";
- case AKEYCODE_TV_AUDIO_DESCRIPTION: return "AKEYCODE_TV_AUDIO_DESCRIPTION";
- case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: return "AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP";
- case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: return "AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN";
- case AKEYCODE_TV_ZOOM_MODE: return "AKEYCODE_TV_ZOOM_MODE";
- case AKEYCODE_TV_CONTENTS_MENU: return "AKEYCODE_TV_CONTENTS_MENU";
- case AKEYCODE_TV_MEDIA_CONTEXT_MENU: return "AKEYCODE_TV_MEDIA_CONTEXT_MENU";
- case AKEYCODE_TV_TIMER_PROGRAMMING: return "AKEYCODE_TV_TIMER_PROGRAMMING";
- case AKEYCODE_HELP: return "AKEYCODE_HELP";
+ case AKEYCODE_UNKNOWN:
+ return "AKEYCODE_UNKNOWN";
+ case AKEYCODE_SOFT_LEFT:
+ return "AKEYCODE_SOFT_LEFT";
+ case AKEYCODE_SOFT_RIGHT:
+ return "AKEYCODE_SOFT_RIGHT";
+ case AKEYCODE_HOME:
+ return "AKEYCODE_HOME";
+ case AKEYCODE_BACK:
+ return "AKEYCODE_BACK";
+ case AKEYCODE_CALL:
+ return "AKEYCODE_CALL";
+ case AKEYCODE_ENDCALL:
+ return "AKEYCODE_ENDCALL";
+ case AKEYCODE_0:
+ return "AKEYCODE_0";
+ case AKEYCODE_1:
+ return "AKEYCODE_1";
+ case AKEYCODE_2:
+ return "AKEYCODE_2";
+ case AKEYCODE_3:
+ return "AKEYCODE_3";
+ case AKEYCODE_4:
+ return "AKEYCODE_4";
+ case AKEYCODE_5:
+ return "AKEYCODE_5";
+ case AKEYCODE_6:
+ return "AKEYCODE_6";
+ case AKEYCODE_7:
+ return "AKEYCODE_7";
+ case AKEYCODE_8:
+ return "AKEYCODE_8";
+ case AKEYCODE_9:
+ return "AKEYCODE_9";
+ case AKEYCODE_STAR:
+ return "AKEYCODE_STAR";
+ case AKEYCODE_POUND:
+ return "AKEYCODE_POUND";
+ case AKEYCODE_DPAD_UP:
+ return "AKEYCODE_DPAD_UP";
+ case AKEYCODE_DPAD_DOWN:
+ return "AKEYCODE_DPAD_DOWN";
+ case AKEYCODE_DPAD_LEFT:
+ return "AKEYCODE_DPAD_LEFT";
+ case AKEYCODE_DPAD_RIGHT:
+ return "AKEYCODE_DPAD_RIGHT";
+ case AKEYCODE_DPAD_CENTER:
+ return "AKEYCODE_DPAD_CENTER";
+ case AKEYCODE_VOLUME_UP:
+ return "AKEYCODE_VOLUME_UP";
+ case AKEYCODE_VOLUME_DOWN:
+ return "AKEYCODE_VOLUME_DOWN";
+ case AKEYCODE_POWER:
+ return "AKEYCODE_POWER";
+ case AKEYCODE_CAMERA:
+ return "AKEYCODE_CAMERA";
+ case AKEYCODE_CLEAR:
+ return "AKEYCODE_CLEAR";
+ case AKEYCODE_A:
+ return "AKEYCODE_A";
+ case AKEYCODE_B:
+ return "AKEYCODE_B";
+ case AKEYCODE_C:
+ return "AKEYCODE_C";
+ case AKEYCODE_D:
+ return "AKEYCODE_D";
+ case AKEYCODE_E:
+ return "AKEYCODE_E";
+ case AKEYCODE_F:
+ return "AKEYCODE_F";
+ case AKEYCODE_G:
+ return "AKEYCODE_G";
+ case AKEYCODE_H:
+ return "AKEYCODE_H";
+ case AKEYCODE_I:
+ return "AKEYCODE_I";
+ case AKEYCODE_J:
+ return "AKEYCODE_J";
+ case AKEYCODE_K:
+ return "AKEYCODE_K";
+ case AKEYCODE_L:
+ return "AKEYCODE_L";
+ case AKEYCODE_M:
+ return "AKEYCODE_M";
+ case AKEYCODE_N:
+ return "AKEYCODE_N";
+ case AKEYCODE_O:
+ return "AKEYCODE_O";
+ case AKEYCODE_P:
+ return "AKEYCODE_P";
+ case AKEYCODE_Q:
+ return "AKEYCODE_Q";
+ case AKEYCODE_R:
+ return "AKEYCODE_R";
+ case AKEYCODE_S:
+ return "AKEYCODE_S";
+ case AKEYCODE_T:
+ return "AKEYCODE_T";
+ case AKEYCODE_U:
+ return "AKEYCODE_U";
+ case AKEYCODE_V:
+ return "AKEYCODE_V";
+ case AKEYCODE_W:
+ return "AKEYCODE_W";
+ case AKEYCODE_X:
+ return "AKEYCODE_X";
+ case AKEYCODE_Y:
+ return "AKEYCODE_Y";
+ case AKEYCODE_Z:
+ return "AKEYCODE_Z";
+ case AKEYCODE_COMMA:
+ return "AKEYCODE_COMMA";
+ case AKEYCODE_PERIOD:
+ return "AKEYCODE_PERIOD";
+ case AKEYCODE_ALT_LEFT:
+ return "AKEYCODE_ALT_LEFT";
+ case AKEYCODE_ALT_RIGHT:
+ return "AKEYCODE_ALT_RIGHT";
+ case AKEYCODE_SHIFT_LEFT:
+ return "AKEYCODE_SHIFT_LEFT";
+ case AKEYCODE_SHIFT_RIGHT:
+ return "AKEYCODE_SHIFT_RIGHT";
+ case AKEYCODE_TAB:
+ return "AKEYCODE_TAB";
+ case AKEYCODE_SPACE:
+ return "AKEYCODE_SPACE";
+ case AKEYCODE_SYM:
+ return "AKEYCODE_SYM";
+ case AKEYCODE_EXPLORER:
+ return "AKEYCODE_EXPLORER";
+ case AKEYCODE_ENVELOPE:
+ return "AKEYCODE_ENVELOPE";
+ case AKEYCODE_ENTER:
+ return "AKEYCODE_ENTER";
+ case AKEYCODE_DEL:
+ return "AKEYCODE_DEL";
+ case AKEYCODE_GRAVE:
+ return "AKEYCODE_GRAVE";
+ case AKEYCODE_MINUS:
+ return "AKEYCODE_MINUS";
+ case AKEYCODE_EQUALS:
+ return "AKEYCODE_EQUALS";
+ case AKEYCODE_LEFT_BRACKET:
+ return "AKEYCODE_LEFT_BRACKET";
+ case AKEYCODE_RIGHT_BRACKET:
+ return "AKEYCODE_RIGHT_BRACKET";
+ case AKEYCODE_BACKSLASH:
+ return "AKEYCODE_BACKSLASH";
+ case AKEYCODE_SEMICOLON:
+ return "AKEYCODE_SEMICOLON";
+ case AKEYCODE_APOSTROPHE:
+ return "AKEYCODE_APOSTROPHE";
+ case AKEYCODE_SLASH:
+ return "AKEYCODE_SLASH";
+ case AKEYCODE_AT:
+ return "AKEYCODE_AT";
+ case AKEYCODE_NUM:
+ return "AKEYCODE_NUM";
+ case AKEYCODE_HEADSETHOOK:
+ return "AKEYCODE_HEADSETHOOK";
+ case AKEYCODE_FOCUS:
+ return "AKEYCODE_FOCUS";
+ case AKEYCODE_PLUS:
+ return "AKEYCODE_PLUS";
+ case AKEYCODE_MENU:
+ return "AKEYCODE_MENU";
+ case AKEYCODE_NOTIFICATION:
+ return "AKEYCODE_NOTIFICATION";
+ case AKEYCODE_SEARCH:
+ return "AKEYCODE_SEARCH";
+ case AKEYCODE_MEDIA_PLAY_PAUSE:
+ return "AKEYCODE_MEDIA_PLAY_PAUSE";
+ case AKEYCODE_MEDIA_STOP:
+ return "AKEYCODE_MEDIA_STOP";
+ case AKEYCODE_MEDIA_NEXT:
+ return "AKEYCODE_MEDIA_NEXT";
+ case AKEYCODE_MEDIA_PREVIOUS:
+ return "AKEYCODE_MEDIA_PREVIOUS";
+ case AKEYCODE_MEDIA_REWIND:
+ return "AKEYCODE_MEDIA_REWIND";
+ case AKEYCODE_MEDIA_FAST_FORWARD:
+ return "AKEYCODE_MEDIA_FAST_FORWARD";
+ case AKEYCODE_MUTE:
+ return "AKEYCODE_MUTE";
+ case AKEYCODE_PAGE_UP:
+ return "AKEYCODE_PAGE_UP";
+ case AKEYCODE_PAGE_DOWN:
+ return "AKEYCODE_PAGE_DOWN";
+ case AKEYCODE_PICTSYMBOLS:
+ return "AKEYCODE_PICTSYMBOLS";
+ case AKEYCODE_SWITCH_CHARSET:
+ return "AKEYCODE_SWITCH_CHARSET";
+ case AKEYCODE_BUTTON_A:
+ return "AKEYCODE_BUTTON_A";
+ case AKEYCODE_BUTTON_B:
+ return "AKEYCODE_BUTTON_B";
+ case AKEYCODE_BUTTON_C:
+ return "AKEYCODE_BUTTON_C";
+ case AKEYCODE_BUTTON_X:
+ return "AKEYCODE_BUTTON_X";
+ case AKEYCODE_BUTTON_Y:
+ return "AKEYCODE_BUTTON_Y";
+ case AKEYCODE_BUTTON_Z:
+ return "AKEYCODE_BUTTON_Z";
+ case AKEYCODE_BUTTON_L1:
+ return "AKEYCODE_BUTTON_L1";
+ case AKEYCODE_BUTTON_R1:
+ return "AKEYCODE_BUTTON_R1";
+ case AKEYCODE_BUTTON_L2:
+ return "AKEYCODE_BUTTON_L2";
+ case AKEYCODE_BUTTON_R2:
+ return "AKEYCODE_BUTTON_R2";
+ case AKEYCODE_BUTTON_THUMBL:
+ return "AKEYCODE_BUTTON_THUMBL";
+ case AKEYCODE_BUTTON_THUMBR:
+ return "AKEYCODE_BUTTON_THUMBR";
+ case AKEYCODE_BUTTON_START:
+ return "AKEYCODE_BUTTON_START";
+ case AKEYCODE_BUTTON_SELECT:
+ return "AKEYCODE_BUTTON_SELECT";
+ case AKEYCODE_BUTTON_MODE:
+ return "AKEYCODE_BUTTON_MODE";
+ case AKEYCODE_ESCAPE:
+ return "AKEYCODE_ESCAPE";
+ case AKEYCODE_FORWARD_DEL:
+ return "AKEYCODE_FORWARD_DEL";
+ case AKEYCODE_CTRL_LEFT:
+ return "AKEYCODE_CTRL_LEFT";
+ case AKEYCODE_CTRL_RIGHT:
+ return "AKEYCODE_CTRL_RIGHT";
+ case AKEYCODE_CAPS_LOCK:
+ return "AKEYCODE_CAPS_LOCK";
+ case AKEYCODE_SCROLL_LOCK:
+ return "AKEYCODE_SCROLL_LOCK";
+ case AKEYCODE_META_LEFT:
+ return "AKEYCODE_META_LEFT";
+ case AKEYCODE_META_RIGHT:
+ return "AKEYCODE_META_RIGHT";
+ case AKEYCODE_FUNCTION:
+ return "AKEYCODE_FUNCTION";
+ case AKEYCODE_SYSRQ:
+ return "AKEYCODE_SYSRQ";
+ case AKEYCODE_BREAK:
+ return "AKEYCODE_BREAK";
+ case AKEYCODE_MOVE_HOME:
+ return "AKEYCODE_MOVE_HOME";
+ case AKEYCODE_MOVE_END:
+ return "AKEYCODE_MOVE_END";
+ case AKEYCODE_INSERT:
+ return "AKEYCODE_INSERT";
+ case AKEYCODE_FORWARD:
+ return "AKEYCODE_FORWARD";
+ case AKEYCODE_MEDIA_PLAY:
+ return "AKEYCODE_MEDIA_PLAY";
+ case AKEYCODE_MEDIA_PAUSE:
+ return "AKEYCODE_MEDIA_PAUSE";
+ case AKEYCODE_MEDIA_CLOSE:
+ return "AKEYCODE_MEDIA_CLOSE";
+ case AKEYCODE_MEDIA_EJECT:
+ return "AKEYCODE_MEDIA_EJECT";
+ case AKEYCODE_MEDIA_RECORD:
+ return "AKEYCODE_MEDIA_RECORD";
+ case AKEYCODE_F1:
+ return "AKEYCODE_F1";
+ case AKEYCODE_F2:
+ return "AKEYCODE_F2";
+ case AKEYCODE_F3:
+ return "AKEYCODE_F3";
+ case AKEYCODE_F4:
+ return "AKEYCODE_F4";
+ case AKEYCODE_F5:
+ return "AKEYCODE_F5";
+ case AKEYCODE_F6:
+ return "AKEYCODE_F6";
+ case AKEYCODE_F7:
+ return "AKEYCODE_F7";
+ case AKEYCODE_F8:
+ return "AKEYCODE_F8";
+ case AKEYCODE_F9:
+ return "AKEYCODE_F9";
+ case AKEYCODE_F10:
+ return "AKEYCODE_F10";
+ case AKEYCODE_F11:
+ return "AKEYCODE_F11";
+ case AKEYCODE_F12:
+ return "AKEYCODE_F12";
+ case AKEYCODE_NUM_LOCK:
+ return "AKEYCODE_NUM_LOCK";
+ case AKEYCODE_NUMPAD_0:
+ return "AKEYCODE_NUMPAD_0";
+ case AKEYCODE_NUMPAD_1:
+ return "AKEYCODE_NUMPAD_1";
+ case AKEYCODE_NUMPAD_2:
+ return "AKEYCODE_NUMPAD_2";
+ case AKEYCODE_NUMPAD_3:
+ return "AKEYCODE_NUMPAD_3";
+ case AKEYCODE_NUMPAD_4:
+ return "AKEYCODE_NUMPAD_4";
+ case AKEYCODE_NUMPAD_5:
+ return "AKEYCODE_NUMPAD_5";
+ case AKEYCODE_NUMPAD_6:
+ return "AKEYCODE_NUMPAD_6";
+ case AKEYCODE_NUMPAD_7:
+ return "AKEYCODE_NUMPAD_7";
+ case AKEYCODE_NUMPAD_8:
+ return "AKEYCODE_NUMPAD_8";
+ case AKEYCODE_NUMPAD_9:
+ return "AKEYCODE_NUMPAD_9";
+ case AKEYCODE_NUMPAD_DIVIDE:
+ return "AKEYCODE_NUMPAD_DIVIDE";
+ case AKEYCODE_NUMPAD_MULTIPLY:
+ return "AKEYCODE_NUMPAD_MULTIPLY";
+ case AKEYCODE_NUMPAD_SUBTRACT:
+ return "AKEYCODE_NUMPAD_SUBTRACT";
+ case AKEYCODE_NUMPAD_ADD:
+ return "AKEYCODE_NUMPAD_ADD";
+ case AKEYCODE_NUMPAD_DOT:
+ return "AKEYCODE_NUMPAD_DOT";
+ case AKEYCODE_NUMPAD_COMMA:
+ return "AKEYCODE_NUMPAD_COMMA";
+ case AKEYCODE_NUMPAD_ENTER:
+ return "AKEYCODE_NUMPAD_ENTER";
+ case AKEYCODE_NUMPAD_EQUALS:
+ return "AKEYCODE_NUMPAD_EQUALS";
+ case AKEYCODE_NUMPAD_LEFT_PAREN:
+ return "AKEYCODE_NUMPAD_LEFT_PAREN";
+ case AKEYCODE_NUMPAD_RIGHT_PAREN:
+ return "AKEYCODE_NUMPAD_RIGHT_PAREN";
+ case AKEYCODE_VOLUME_MUTE:
+ return "AKEYCODE_VOLUME_MUTE";
+ case AKEYCODE_INFO:
+ return "AKEYCODE_INFO";
+ case AKEYCODE_CHANNEL_UP:
+ return "AKEYCODE_CHANNEL_UP";
+ case AKEYCODE_CHANNEL_DOWN:
+ return "AKEYCODE_CHANNEL_DOWN";
+ case AKEYCODE_ZOOM_IN:
+ return "AKEYCODE_ZOOM_IN";
+ case AKEYCODE_ZOOM_OUT:
+ return "AKEYCODE_ZOOM_OUT";
+ case AKEYCODE_TV:
+ return "AKEYCODE_TV";
+ case AKEYCODE_WINDOW:
+ return "AKEYCODE_WINDOW";
+ case AKEYCODE_GUIDE:
+ return "AKEYCODE_GUIDE";
+ case AKEYCODE_DVR:
+ return "AKEYCODE_DVR";
+ case AKEYCODE_BOOKMARK:
+ return "AKEYCODE_BOOKMARK";
+ case AKEYCODE_CAPTIONS:
+ return "AKEYCODE_CAPTIONS";
+ case AKEYCODE_SETTINGS:
+ return "AKEYCODE_SETTINGS";
+ case AKEYCODE_TV_POWER:
+ return "AKEYCODE_TV_POWER";
+ case AKEYCODE_TV_INPUT:
+ return "AKEYCODE_TV_INPUT";
+ case AKEYCODE_STB_POWER:
+ return "AKEYCODE_STB_POWER";
+ case AKEYCODE_STB_INPUT:
+ return "AKEYCODE_STB_INPUT";
+ case AKEYCODE_AVR_POWER:
+ return "AKEYCODE_AVR_POWER";
+ case AKEYCODE_AVR_INPUT:
+ return "AKEYCODE_AVR_INPUT";
+ case AKEYCODE_PROG_RED:
+ return "AKEYCODE_PROG_RED";
+ case AKEYCODE_PROG_GREEN:
+ return "AKEYCODE_PROG_GREEN";
+ case AKEYCODE_PROG_YELLOW:
+ return "AKEYCODE_PROG_YELLOW";
+ case AKEYCODE_PROG_BLUE:
+ return "AKEYCODE_PROG_BLUE";
+ case AKEYCODE_APP_SWITCH:
+ return "AKEYCODE_APP_SWITCH";
+ case AKEYCODE_BUTTON_1:
+ return "AKEYCODE_BUTTON_1";
+ case AKEYCODE_BUTTON_2:
+ return "AKEYCODE_BUTTON_2";
+ case AKEYCODE_BUTTON_3:
+ return "AKEYCODE_BUTTON_3";
+ case AKEYCODE_BUTTON_4:
+ return "AKEYCODE_BUTTON_4";
+ case AKEYCODE_BUTTON_5:
+ return "AKEYCODE_BUTTON_5";
+ case AKEYCODE_BUTTON_6:
+ return "AKEYCODE_BUTTON_6";
+ case AKEYCODE_BUTTON_7:
+ return "AKEYCODE_BUTTON_7";
+ case AKEYCODE_BUTTON_8:
+ return "AKEYCODE_BUTTON_8";
+ case AKEYCODE_BUTTON_9:
+ return "AKEYCODE_BUTTON_9";
+ case AKEYCODE_BUTTON_10:
+ return "AKEYCODE_BUTTON_10";
+ case AKEYCODE_BUTTON_11:
+ return "AKEYCODE_BUTTON_11";
+ case AKEYCODE_BUTTON_12:
+ return "AKEYCODE_BUTTON_12";
+ case AKEYCODE_BUTTON_13:
+ return "AKEYCODE_BUTTON_13";
+ case AKEYCODE_BUTTON_14:
+ return "AKEYCODE_BUTTON_14";
+ case AKEYCODE_BUTTON_15:
+ return "AKEYCODE_BUTTON_15";
+ case AKEYCODE_BUTTON_16:
+ return "AKEYCODE_BUTTON_16";
+ case AKEYCODE_LANGUAGE_SWITCH:
+ return "AKEYCODE_LANGUAGE_SWITCH";
+ case AKEYCODE_MANNER_MODE:
+ return "AKEYCODE_MANNER_MODE";
+ case AKEYCODE_3D_MODE:
+ return "AKEYCODE_3D_MODE";
+ case AKEYCODE_CONTACTS:
+ return "AKEYCODE_CONTACTS";
+ case AKEYCODE_CALENDAR:
+ return "AKEYCODE_CALENDAR";
+ case AKEYCODE_MUSIC:
+ return "AKEYCODE_MUSIC";
+ case AKEYCODE_CALCULATOR:
+ return "AKEYCODE_CALCULATOR";
+ case AKEYCODE_ZENKAKU_HANKAKU:
+ return "AKEYCODE_ZENKAKU_HANKAKU";
+ case AKEYCODE_EISU:
+ return "AKEYCODE_EISU";
+ case AKEYCODE_MUHENKAN:
+ return "AKEYCODE_MUHENKAN";
+ case AKEYCODE_HENKAN:
+ return "AKEYCODE_HENKAN";
+ case AKEYCODE_KATAKANA_HIRAGANA:
+ return "AKEYCODE_KATAKANA_HIRAGANA";
+ case AKEYCODE_YEN:
+ return "AKEYCODE_YEN";
+ case AKEYCODE_RO:
+ return "AKEYCODE_RO";
+ case AKEYCODE_KANA:
+ return "AKEYCODE_KANA";
+ case AKEYCODE_ASSIST:
+ return "AKEYCODE_ASSIST";
+ case AKEYCODE_BRIGHTNESS_DOWN:
+ return "AKEYCODE_BRIGHTNESS_DOWN";
+ case AKEYCODE_BRIGHTNESS_UP:
+ return "AKEYCODE_BRIGHTNESS_UP";
+ case AKEYCODE_MEDIA_AUDIO_TRACK:
+ return "AKEYCODE_MEDIA_AUDIO_TRACK";
+ case AKEYCODE_SLEEP:
+ return "AKEYCODE_SLEEP";
+ case AKEYCODE_WAKEUP:
+ return "AKEYCODE_WAKEUP";
+ case AKEYCODE_PAIRING:
+ return "AKEYCODE_PAIRING";
+ case AKEYCODE_MEDIA_TOP_MENU:
+ return "AKEYCODE_MEDIA_TOP_MENU";
+ case AKEYCODE_11:
+ return "AKEYCODE_11";
+ case AKEYCODE_12:
+ return "AKEYCODE_12";
+ case AKEYCODE_LAST_CHANNEL:
+ return "AKEYCODE_LAST_CHANNEL";
+ case AKEYCODE_TV_DATA_SERVICE:
+ return "AKEYCODE_TV_DATA_SERVICE";
+ case AKEYCODE_VOICE_ASSIST:
+ return "AKEYCODE_VOICE_ASSIST";
+ case AKEYCODE_TV_RADIO_SERVICE:
+ return "AKEYCODE_TV_RADIO_SERVICE";
+ case AKEYCODE_TV_TELETEXT:
+ return "AKEYCODE_TV_TELETEXT";
+ case AKEYCODE_TV_NUMBER_ENTRY:
+ return "AKEYCODE_TV_NUMBER_ENTRY";
+ case AKEYCODE_TV_TERRESTRIAL_ANALOG:
+ return "AKEYCODE_TV_TERRESTRIAL_ANALOG";
+ case AKEYCODE_TV_TERRESTRIAL_DIGITAL:
+ return "AKEYCODE_TV_TERRESTRIAL_DIGITAL";
+ case AKEYCODE_TV_SATELLITE:
+ return "AKEYCODE_TV_SATELLITE";
+ case AKEYCODE_TV_SATELLITE_BS:
+ return "AKEYCODE_TV_SATELLITE_BS";
+ case AKEYCODE_TV_SATELLITE_CS:
+ return "AKEYCODE_TV_SATELLITE_CS";
+ case AKEYCODE_TV_SATELLITE_SERVICE:
+ return "AKEYCODE_TV_SATELLITE_SERVICE";
+ case AKEYCODE_TV_NETWORK:
+ return "AKEYCODE_TV_NETWORK";
+ case AKEYCODE_TV_ANTENNA_CABLE:
+ return "AKEYCODE_TV_ANTENNA_CABLE";
+ case AKEYCODE_TV_INPUT_HDMI_1:
+ return "AKEYCODE_TV_INPUT_HDMI_1";
+ case AKEYCODE_TV_INPUT_HDMI_2:
+ return "AKEYCODE_TV_INPUT_HDMI_2";
+ case AKEYCODE_TV_INPUT_HDMI_3:
+ return "AKEYCODE_TV_INPUT_HDMI_3";
+ case AKEYCODE_TV_INPUT_HDMI_4:
+ return "AKEYCODE_TV_INPUT_HDMI_4";
+ case AKEYCODE_TV_INPUT_COMPOSITE_1:
+ return "AKEYCODE_TV_INPUT_COMPOSITE_1";
+ case AKEYCODE_TV_INPUT_COMPOSITE_2:
+ return "AKEYCODE_TV_INPUT_COMPOSITE_2";
+ case AKEYCODE_TV_INPUT_COMPONENT_1:
+ return "AKEYCODE_TV_INPUT_COMPONENT_1";
+ case AKEYCODE_TV_INPUT_COMPONENT_2:
+ return "AKEYCODE_TV_INPUT_COMPONENT_2";
+ case AKEYCODE_TV_INPUT_VGA_1:
+ return "AKEYCODE_TV_INPUT_VGA_1";
+ case AKEYCODE_TV_AUDIO_DESCRIPTION:
+ return "AKEYCODE_TV_AUDIO_DESCRIPTION";
+ case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
+ return "AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP";
+ case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
+ return "AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN";
+ case AKEYCODE_TV_ZOOM_MODE:
+ return "AKEYCODE_TV_ZOOM_MODE";
+ case AKEYCODE_TV_CONTENTS_MENU:
+ return "AKEYCODE_TV_CONTENTS_MENU";
+ case AKEYCODE_TV_MEDIA_CONTEXT_MENU:
+ return "AKEYCODE_TV_MEDIA_CONTEXT_MENU";
+ case AKEYCODE_TV_TIMER_PROGRAMMING:
+ return "AKEYCODE_TV_TIMER_PROGRAMMING";
+ case AKEYCODE_HELP:
+ return "AKEYCODE_HELP";
+ case AKEYCODE_NAVIGATE_PREVIOUS:
+ return "AKEYCODE_NAVIGATE_PREVIOUS";
+ case AKEYCODE_NAVIGATE_NEXT:
+ return "AKEYCODE_NAVIGATE_NEXT";
+ case AKEYCODE_NAVIGATE_IN:
+ return "AKEYCODE_NAVIGATE_IN";
+ case AKEYCODE_NAVIGATE_OUT:
+ return "AKEYCODE_NAVIGATE_OUT";
+ case AKEYCODE_STEM_PRIMARY:
+ return "AKEYCODE_STEM_PRIMARY";
+ case AKEYCODE_STEM_1:
+ return "AKEYCODE_STEM_1";
+ case AKEYCODE_STEM_2:
+ return "AKEYCODE_STEM_2";
+ case AKEYCODE_STEM_3:
+ return "AKEYCODE_STEM_3";
+ case AKEYCODE_DPAD_UP_LEFT:
+ return "AKEYCODE_DPAD_UP_LEFT";
+ case AKEYCODE_DPAD_DOWN_LEFT:
+ return "AKEYCODE_DPAD_DOWN_LEFT";
+ case AKEYCODE_DPAD_UP_RIGHT:
+ return "AKEYCODE_DPAD_UP_RIGHT";
+ case AKEYCODE_DPAD_DOWN_RIGHT:
+ return "AKEYCODE_DPAD_DOWN_RIGHT";
+ case AKEYCODE_MEDIA_SKIP_FORWARD:
+ return "AKEYCODE_MEDIA_SKIP_FORWARD";
+ case AKEYCODE_MEDIA_SKIP_BACKWARD:
+ return "AKEYCODE_MEDIA_SKIP_BACKWARD";
+ case AKEYCODE_MEDIA_STEP_FORWARD:
+ return "AKEYCODE_MEDIA_STEP_FORWARD";
+ case AKEYCODE_MEDIA_STEP_BACKWARD:
+ return "AKEYCODE_MEDIA_STEP_BACKWARD";
+ case AKEYCODE_SOFT_SLEEP:
+ return "AKEYCODE_SOFT_SLEEP";
+ case AKEYCODE_CUT:
+ return "AKEYCODE_CUT";
+ case AKEYCODE_COPY:
+ return "AKEYCODE_COPY";
+ case AKEYCODE_PASTE:
+ return "AKEYCODE_PASTE";
+ case AKEYCODE_SYSTEM_NAVIGATION_UP:
+ return "AKEYCODE_SYSTEM_NAVIGATION_UP";
+ case AKEYCODE_SYSTEM_NAVIGATION_DOWN:
+ return "AKEYCODE_SYSTEM_NAVIGATION_DOWN";
+ case AKEYCODE_SYSTEM_NAVIGATION_LEFT:
+ return "AKEYCODE_SYSTEM_NAVIGATION_LEFT";
+ case AKEYCODE_SYSTEM_NAVIGATION_RIGHT:
+ return "AKEYCODE_SYSTEM_NAVIGATION_RIGHT";
+ case AKEYCODE_ALL_APPS:
+ return "AKEYCODE_ALL_APPS";
+ case AKEYCODE_REFRESH:
+ return "AKEYCODE_REFRESH";
+ case AKEYCODE_THUMBS_UP:
+ return "AKEYCODE_THUMBS_UP";
+ case AKEYCODE_THUMBS_DOWN:
+ return "AKEYCODE_THUMBS_DOWN";
+ case AKEYCODE_PROFILE_SWITCH:
+ return "AKEYCODE_PROFILE_SWITCH";
+ default:
+ break;
}
return "unknown";
}
+
+const char* CAndroidJoystickTranslator::TranslateJoystickButton(int buttonKeycode)
+{
+ switch (buttonKeycode)
+ {
+ case AKEYCODE_BUTTON_A:
+ 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 cc622ed166..8681de0c12 100644
--- a/xbmc/platform/android/peripherals/AndroidJoystickTranslator.h
+++ b/xbmc/platform/android/peripherals/AndroidJoystickTranslator.h
@@ -10,25 +10,34 @@
namespace PERIPHERALS
{
- 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
- */
- static const char *TranslateAxis(int axisId);
+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
+ */
+ 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
+ */
+ static const char* TranslateKeyCode(int keyCode);
- /*!
- * \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 8a72cc0acf..3f269472ec 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>
@@ -28,15 +29,15 @@
using namespace KODI;
using namespace PERIPHERALS;
-#define JOYSTICK_PROVIDER_ANDROID "android"
+#define JOYSTICK_PROVIDER_ANDROID "android"
// Set this to the final key code in android/keycodes.h
-const unsigned int KEY_CODE_FINAL = AKEYCODE_HELP;
+const unsigned int KEY_CODE_FINAL = AKEYCODE_PROFILE_SWITCH;
static const std::string DeviceLocationPrefix = "android/inputdevice/";
-CPeripheralBusAndroid::CPeripheralBusAndroid(CPeripherals& manager) :
- CPeripheralBus("PeripBusAndroid", manager, PERIPHERAL_BUS_ANDROID)
+CPeripheralBusAndroid::CPeripheralBusAndroid(CPeripherals& manager)
+ : CPeripheralBus("PeripBusAndroid", manager, PERIPHERAL_BUS_ANDROID)
{
// we don't need polling as we get notified through the IInputDeviceCallbacks interface
m_bNeedsPolling = false;
@@ -90,7 +91,7 @@ bool CPeripheralBusAndroid::InitializeProperties(CPeripheral& peripheral)
CPeripheralJoystick& joystick = static_cast<CPeripheralJoystick&>(peripheral);
if (device.getControllerNumber() > 0)
- joystick.SetRequestedPort(device.getControllerNumber() - 1);
+ joystick.SetRequestedPort(device.getControllerNumber() - 1);
joystick.SetProvider(JOYSTICK_PROVIDER_ANDROID);
CLog::Log(LOGDEBUG, "CPeripheralBusAndroid: Initializing device {} \"{}\"", deviceId,
@@ -120,6 +121,50 @@ bool CPeripheralBusAndroid::InitializeProperties(CPeripheral& peripheral)
return true;
}
+bool CPeripheralBusAndroid::InitializeButtonMap(const CPeripheral& peripheral,
+ KODI::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();
@@ -180,7 +225,8 @@ void CPeripheralBusAndroid::OnInputDeviceAdded(int deviceId)
std::unique_lock<CCriticalSection> lock(m_critSectionResults);
// add the device to the cached result list
const auto& it = std::find_if(m_scanResults.m_results.cbegin(), m_scanResults.m_results.cend(),
- [&deviceLocation](const PeripheralScanResult& scanResult) { return scanResult.m_strLocation == deviceLocation; });
+ [&deviceLocation](const PeripheralScanResult& scanResult)
+ { return scanResult.m_strLocation == deviceLocation; });
if (it != m_scanResults.m_results.cend())
{
@@ -207,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);
@@ -221,7 +267,8 @@ void CPeripheralBusAndroid::OnInputDeviceChanged(int deviceId)
{
std::unique_lock<CCriticalSection> lock(m_critSectionResults);
// change the device in the cached result list
- for (auto result = m_scanResults.m_results.begin(); result != m_scanResults.m_results.end(); ++result)
+ for (auto result = m_scanResults.m_results.begin(); result != m_scanResults.m_results.end();
+ ++result)
{
if (result->m_strLocation == deviceLocation)
{
@@ -262,7 +309,8 @@ void CPeripheralBusAndroid::OnInputDeviceRemoved(int deviceId)
{
std::unique_lock<CCriticalSection> lock(m_critSectionResults);
// remove the device from the cached result list
- for (auto result = m_scanResults.m_results.begin(); result != m_scanResults.m_results.end(); ++result)
+ for (auto result = m_scanResults.m_results.begin(); result != m_scanResults.m_results.end();
+ ++result)
{
if (result->m_strLocation == deviceLocation)
{
@@ -310,7 +358,7 @@ bool CPeripheralBusAndroid::OnInputDeviceEvent(const AInputEvent* event)
return joystickState->second.ProcessEvent(event);
}
-bool CPeripheralBusAndroid::PerformDeviceScan(PeripheralScanResults &results)
+bool CPeripheralBusAndroid::PerformDeviceScan(PeripheralScanResults& results)
{
std::unique_lock<CCriticalSection> lock(m_critSectionResults);
results = m_scanResults;
@@ -342,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;
@@ -355,8 +403,7 @@ std::string CPeripheralBusAndroid::GetDeviceLocation(int deviceId)
bool CPeripheralBusAndroid::GetDeviceId(const std::string& deviceLocation, int& deviceId)
{
- if (deviceLocation.empty() ||
- !StringUtils::StartsWith(deviceLocation, DeviceLocationPrefix) ||
+ if (deviceLocation.empty() || !StringUtils::StartsWith(deviceLocation, DeviceLocationPrefix) ||
deviceLocation.size() <= DeviceLocationPrefix.size())
return false;
@@ -368,7 +415,8 @@ bool CPeripheralBusAndroid::GetDeviceId(const std::string& deviceLocation, int&
return true;
}
-bool CPeripheralBusAndroid::ConvertToPeripheralScanResult(const CJNIViewInputDevice& inputDevice, PeripheralScanResult& peripheralScanResult)
+bool CPeripheralBusAndroid::ConvertToPeripheralScanResult(
+ const CJNIViewInputDevice& inputDevice, PeripheralScanResult& peripheralScanResult)
{
if (inputDevice.isVirtual())
{
@@ -376,10 +424,62 @@ bool CPeripheralBusAndroid::ConvertToPeripheralScanResult(const CJNIViewInputDev
return false;
}
- if (!inputDevice.supportsSource(CJNIViewInputDevice::SOURCE_JOYSTICK) && !inputDevice.supportsSource(CJNIViewInputDevice::SOURCE_GAMEPAD))
+ if (!inputDevice.supportsSource(CJNIViewInputDevice::SOURCE_JOYSTICK) &&
+ !inputDevice.supportsSource(CJNIViewInputDevice::SOURCE_GAMEPAD))
{
- CLog::Log(LOGDEBUG, "CPeripheralBusAndroid: ignoring non-joystick device");
- return false;
+ // Observed an anomylous PS4 controller with only SOURCE_MOUSE
+ if (!inputDevice.supportsSource(CJNIViewInputDevice::SOURCE_MOUSE))
+ {
+ CLog::Log(LOGDEBUG, "CPeripheralBusAndroid: ignoring non-joystick device");
+ return false;
+ }
+
+ // Make sure the anomylous controller has buttons
+ // clang-format off
+ std::vector<int> buttons{
+ AKEYCODE_BUTTON_A,
+ AKEYCODE_BUTTON_B,
+ AKEYCODE_BUTTON_C,
+ AKEYCODE_BUTTON_X,
+ AKEYCODE_BUTTON_Y,
+ AKEYCODE_BUTTON_Z,
+ AKEYCODE_BUTTON_L1,
+ AKEYCODE_BUTTON_R1,
+ AKEYCODE_BUTTON_L2,
+ AKEYCODE_BUTTON_R2,
+ AKEYCODE_BUTTON_THUMBL,
+ AKEYCODE_BUTTON_THUMBR,
+ AKEYCODE_BUTTON_START,
+ AKEYCODE_BUTTON_SELECT,
+ AKEYCODE_BUTTON_MODE,
+ AKEYCODE_BUTTON_1,
+ AKEYCODE_BUTTON_2,
+ AKEYCODE_BUTTON_3,
+ AKEYCODE_BUTTON_4,
+ AKEYCODE_BUTTON_5,
+ AKEYCODE_BUTTON_6,
+ AKEYCODE_BUTTON_7,
+ AKEYCODE_BUTTON_8,
+ AKEYCODE_BUTTON_9,
+ AKEYCODE_BUTTON_10,
+ AKEYCODE_BUTTON_11,
+ AKEYCODE_BUTTON_12,
+ AKEYCODE_BUTTON_13,
+ AKEYCODE_BUTTON_14,
+ AKEYCODE_BUTTON_15,
+ AKEYCODE_BUTTON_16,
+ };
+ // clang-format on
+
+ auto result = inputDevice.hasKeys(buttons);
+
+ if (std::find(result.begin(), result.end(), true) == result.end())
+ {
+ CLog::Log(LOGDEBUG, "CPeripheralBusAndroid: ignoring non-joystick device with mouse source");
+ return false;
+ }
+
+ CLog::Log(LOGDEBUG, "CPeripheralBusAndroid: adding non-joystick device with mouse source");
}
peripheralScanResult.m_type = PERIPHERAL_JOYSTICK;
@@ -395,7 +495,7 @@ bool CPeripheralBusAndroid::ConvertToPeripheralScanResult(const CJNIViewInputDev
return true;
}
-void CPeripheralBusAndroid::LogInputDevice(const CJNIViewInputDevice &device)
+void CPeripheralBusAndroid::LogInputDevice(const CJNIViewInputDevice& device)
{
// Log device properties
CLog::Log(LOGDEBUG, " Name: \"{}\"", device.getName());
@@ -413,7 +513,7 @@ void CPeripheralBusAndroid::LogInputDevice(const CJNIViewInputDevice &device)
// Log device sources
CLog::Log(LOGDEBUG, " Source flags: {:#08x}", device.getSources());
- for (const auto &source : GetInputSources())
+ for (const auto& source : GetInputSources())
{
if (device.supportsSource(source.first))
CLog::Log(LOGDEBUG, " Has source: {} ({:#08x})", source.second, source.first);
@@ -458,26 +558,25 @@ void CPeripheralBusAndroid::LogInputDevice(const CJNIViewInputDevice &device)
std::vector<std::pair<int, const char*>> CPeripheralBusAndroid::GetInputSources()
{
std::vector<std::pair<int, const char*>> sources = {
- { CJNIViewInputDevice::SOURCE_DPAD, "SOURCE_DPAD" },
- { CJNIViewInputDevice::SOURCE_GAMEPAD, "SOURCE_GAMEPAD" },
- { CJNIViewInputDevice::SOURCE_HDMI, "SOURCE_HDMI" },
- { CJNIViewInputDevice::SOURCE_JOYSTICK, "SOURCE_JOYSTICK" },
- { CJNIViewInputDevice::SOURCE_KEYBOARD, "SOURCE_KEYBOARD" },
- { CJNIViewInputDevice::SOURCE_MOUSE, "SOURCE_MOUSE" },
- { CJNIViewInputDevice::SOURCE_MOUSE_RELATIVE, "SOURCE_MOUSE_RELATIVE" },
- { CJNIViewInputDevice::SOURCE_ROTARY_ENCODER, "SOURCE_ROTARY_ENCODER" },
- { CJNIViewInputDevice::SOURCE_STYLUS, "SOURCE_STYLUS" },
- { CJNIViewInputDevice::SOURCE_TOUCHPAD, "SOURCE_TOUCHPAD" },
- { CJNIViewInputDevice::SOURCE_TOUCHSCREEN, "SOURCE_TOUCHSCREEN" },
- { CJNIViewInputDevice::SOURCE_TOUCH_NAVIGATION, "SOURCE_TOUCH_NAVIGATION" },
- { CJNIViewInputDevice::SOURCE_TRACKBALL, "SOURCE_TRACKBALL" },
+ {CJNIViewInputDevice::SOURCE_DPAD, "SOURCE_DPAD"},
+ {CJNIViewInputDevice::SOURCE_GAMEPAD, "SOURCE_GAMEPAD"},
+ {CJNIViewInputDevice::SOURCE_HDMI, "SOURCE_HDMI"},
+ {CJNIViewInputDevice::SOURCE_JOYSTICK, "SOURCE_JOYSTICK"},
+ {CJNIViewInputDevice::SOURCE_KEYBOARD, "SOURCE_KEYBOARD"},
+ {CJNIViewInputDevice::SOURCE_MOUSE, "SOURCE_MOUSE"},
+ {CJNIViewInputDevice::SOURCE_MOUSE_RELATIVE, "SOURCE_MOUSE_RELATIVE"},
+ {CJNIViewInputDevice::SOURCE_ROTARY_ENCODER, "SOURCE_ROTARY_ENCODER"},
+ {CJNIViewInputDevice::SOURCE_STYLUS, "SOURCE_STYLUS"},
+ {CJNIViewInputDevice::SOURCE_TOUCHPAD, "SOURCE_TOUCHPAD"},
+ {CJNIViewInputDevice::SOURCE_TOUCHSCREEN, "SOURCE_TOUCHSCREEN"},
+ {CJNIViewInputDevice::SOURCE_TOUCH_NAVIGATION, "SOURCE_TOUCH_NAVIGATION"},
+ {CJNIViewInputDevice::SOURCE_TRACKBALL, "SOURCE_TRACKBALL"},
};
sources.erase(std::remove_if(sources.begin(), sources.end(),
- [](const std::pair<int, const char*> &source)
- {
- return source.first == 0;
- }), sources.end());
+ [](const std::pair<int, const char*>& source)
+ { return source.first == 0; }),
+ sources.end());
return sources;
}
diff --git a/xbmc/platform/android/peripherals/PeripheralBusAndroid.h b/xbmc/platform/android/peripherals/PeripheralBusAndroid.h
index 439d741344..5ee9480970 100644
--- a/xbmc/platform/android/peripherals/PeripheralBusAndroid.h
+++ b/xbmc/platform/android/peripherals/PeripheralBusAndroid.h
@@ -25,46 +25,49 @@ class CJNIViewInputDevice;
namespace PERIPHERALS
{
- class CPeripheralBusAndroid : public CPeripheralBus,
- public IInputDeviceCallbacks,
- public IInputDeviceEventHandler
- {
- public:
- explicit CPeripheralBusAndroid(CPeripherals& manager);
- ~CPeripheralBusAndroid() override;
+class CPeripheralBusAndroid : public CPeripheralBus,
+ public IInputDeviceCallbacks,
+ public IInputDeviceEventHandler
+{
+public:
+ explicit CPeripheralBusAndroid(CPeripherals& manager);
+ ~CPeripheralBusAndroid() override;
- // specialisation of CPeripheralBus
- bool InitializeProperties(CPeripheral& peripheral) override;
- void Initialise(void) override;
- void ProcessEvents() override;
+ // 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;
- // implementations of IInputDeviceCallbacks
- void OnInputDeviceAdded(int deviceId) override;
- void OnInputDeviceChanged(int deviceId) override;
- void OnInputDeviceRemoved(int deviceId) override;
+ // implementations of IInputDeviceCallbacks
+ void OnInputDeviceAdded(int deviceId) override;
+ void OnInputDeviceChanged(int deviceId) override;
+ void OnInputDeviceRemoved(int deviceId) override;
- // implementation of IInputDeviceEventHandler
- bool OnInputDeviceEvent(const AInputEvent* event) override;
+ // implementation of IInputDeviceEventHandler
+ bool OnInputDeviceEvent(const AInputEvent* event) override;
- protected:
- // implementation of CPeripheralBus
- bool PerformDeviceScan(PeripheralScanResults &results) override;
+protected:
+ // implementation of CPeripheralBus
+ bool PerformDeviceScan(PeripheralScanResults& results) override;
- private:
- static PeripheralScanResults GetInputDevices();
+private:
+ static PeripheralScanResults GetInputDevices();
- static std::string GetDeviceLocation(int deviceId);
- static bool GetDeviceId(const std::string& deviceLocation, int& deviceId);
+ static std::string GetDeviceLocation(int deviceId);
+ static bool GetDeviceId(const std::string& deviceLocation, int& deviceId);
- static bool ConvertToPeripheralScanResult(const CJNIViewInputDevice& inputDevice, PeripheralScanResult& peripheralScanResult);
+ static bool ConvertToPeripheralScanResult(const CJNIViewInputDevice& inputDevice,
+ PeripheralScanResult& peripheralScanResult);
- static void LogInputDevice(const CJNIViewInputDevice &device);
- static std::vector<std::pair<int, const char*>> GetInputSources();
+ static void LogInputDevice(const CJNIViewInputDevice& device);
+ static std::vector<std::pair<int, const char*>> GetInputSources();
- mutable std::map<int, CAndroidJoystickState> m_joystickStates;
- PeripheralScanResults m_scanResults;
- CCriticalSection m_critSectionStates;
- CCriticalSection m_critSectionResults;
- };
- using PeripheralBusAndroidPtr = std::shared_ptr<CPeripheralBusAndroid>;
-}
+ mutable std::map<int, CAndroidJoystickState> m_joystickStates;
+ PeripheralScanResults m_scanResults;
+ CCriticalSection m_critSectionStates;
+ CCriticalSection m_critSectionResults;
+};
+using PeripheralBusAndroidPtr = std::shared_ptr<CPeripheralBusAndroid>;
+} // namespace PERIPHERALS