Skip to content

Commit

Permalink
Merge pull request xbmc#24604 from garbear/android-joysticks
Browse files Browse the repository at this point in the history
Android joystick fixes
  • Loading branch information
garbear authored Feb 2, 2024
2 parents 9b1bf09 + 95ca75a commit f7d0ef9
Show file tree
Hide file tree
Showing 27 changed files with 946 additions and 172 deletions.
8 changes: 6 additions & 2 deletions xbmc/games/controllers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
set(SOURCES Controller.cpp
ControllerLayout.cpp
ControllerManager.cpp
ControllerTranslator.cpp)
ControllerTranslator.cpp
DefaultController.cpp
)

set(HEADERS Controller.h
ControllerDefinitions.h
ControllerIDs.h
ControllerLayout.h
ControllerManager.h
ControllerTranslator.h
ControllerTypes.h)
ControllerTypes.h
DefaultController.h
)

core_add_library(games_controller)
34 changes: 34 additions & 0 deletions xbmc/games/controllers/DefaultController.cpp
Original file line number Diff line number Diff line change
@@ -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";
50 changes: 50 additions & 0 deletions xbmc/games/controllers/DefaultController.h
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions xbmc/games/controllers/windows/GUIConfigurationWizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,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())
{
Expand Down
70 changes: 70 additions & 0 deletions xbmc/input/joysticks/DriverPrimitive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include "DriverPrimitive.h"

#include "input/keyboard/KeyboardTranslator.h"
#include "utils/StringUtils.h"

#include <utility>

using namespace KODI;
Expand Down Expand Up @@ -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 {}",
KEYBOARD::CKeyboardTranslator::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 "";
}
7 changes: 7 additions & 0 deletions xbmc/input/joysticks/DriverPrimitive.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ class CDriverPrimitive
*/
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;
Expand Down
21 changes: 11 additions & 10 deletions xbmc/input/joysticks/JoystickEasterEgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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,
},
},
{
Expand Down
41 changes: 22 additions & 19 deletions xbmc/input/joysticks/generic/ButtonMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,31 +451,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;
Expand Down
6 changes: 4 additions & 2 deletions xbmc/input/keyboard/KeyboardStat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "KeyboardStat.h"

#include "ServiceBroker.h"
#include "input/keyboard/KeyboardTranslator.h"
#include "input/keyboard/KeyboardTypes.h"
#include "input/keyboard/XBMC_keytable.h"
#include "input/keyboard/XBMC_vkeys.h"
Expand Down Expand Up @@ -91,8 +92,9 @@ CKey CKeyboardStat::TranslateKey(XBMC_keysym& keysym) const
lockingModifiers |= CKey::MODIFIER_SCROLLLOCK;

CLog::Log(LOGDEBUG,
"Keyboard: scancode: {:#02x}, sym: {:#04x}, unicode: {:#04x}, modifier: 0x{:x}",
keysym.scancode, keysym.sym, keysym.unicode, keysym.mod);
"Keyboard: scancode: {:#02x}, sym: {:#04x} ({}), unicode: {:#04x}, modifier: 0x{:x}",
keysym.scancode, keysym.sym, CKeyboardTranslator::TranslateKeycode(keysym.sym),
keysym.unicode, keysym.mod);

// The keysym.unicode is usually valid, even if it is zero. A zero
// unicode just means this is a non-printing keypress. The ascii and
Expand Down
2 changes: 1 addition & 1 deletion xbmc/input/keyboard/KeyboardTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,5 +457,5 @@ const char* CKeyboardTranslator::TranslateKeycode(XBMCKey keycode)
break;
}

return "";
return "unknown";
}
2 changes: 1 addition & 1 deletion xbmc/peripherals/Peripherals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ void CPeripherals::ResetButtonMaps(const std::string& controllerId)
PeripheralAddonPtr addon;
if (addonBus->GetAddonWithButtonMap(peripheral.get(), addon))
{
CAddonButtonMap buttonMap(peripheral.get(), addon, controllerId);
CAddonButtonMap buttonMap(peripheral.get(), addon, controllerId, *this);
buttonMap.Reset();
}
}
Expand Down
29 changes: 27 additions & 2 deletions xbmc/peripherals/addons/AddonButtonMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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);
Expand Down Expand Up @@ -59,6 +61,29 @@ bool CAddonButtonMap::Load(void)
bSuccess |= addon->GetIgnoredPrimitives(m_device, ignoredPrimitives);
}

if (features.empty())
{
// Check if we can initialize a buttonmap from the peripheral bus
PeripheralBusPtr peripheralBus = m_manager.GetBusByType(m_device->GetBusType());
if (peripheralBus)
{
CLog::Log(LOGDEBUG,
"Buttonmap not found for {}, attempting to initialize from peripheral bus",
m_device->Location());
if (peripheralBus->InitializeButtonMap(*m_device, *this))
{
bSuccess = true;

if (auto addon = m_addon.lock())
{
addon->GetAppearance(m_device, controllerAppearance);
addon->GetFeatures(m_device, m_strControllerId, features);
addon->GetIgnoredPrimitives(m_device, ignoredPrimitives);
}
}
}
}

// GetFeatures() was changed to always return false if no features were
// retrieved. Check here, just in case its contract is changed or violated in
// the future.
Expand Down
Loading

0 comments on commit f7d0ef9

Please sign in to comment.