diff options
author | Garrett Brown <themagnificentmrb@gmail.com> | 2024-02-04 02:30:22 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-04 02:30:22 -0800 |
commit | a24fb814d87da91508141da9f89df7f190f11428 (patch) | |
tree | dd82112c897f25c7260b37267ff7da65d112365e | |
parent | f1caa0dc88bf290bdb348e3bab26f0c43e75296b (diff) | |
parent | 33cd322a114e8cd782e710697f3c14645641471b (diff) |
Merge pull request #24625 from garbear/backport-android-joysticks
[Backport] Android joystick fixes
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 |