Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Fix generic controllers in UI #25177

Merged
merged 1 commit into from
Jun 27, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 82 additions & 45 deletions xbmc/platform/android/peripherals/AndroidJoystickState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,33 +55,63 @@ static const std::vector<int> ButtonKeycodes{
AKEYCODE_DPAD_DOWN,
AKEYCODE_DPAD_LEFT,
AKEYCODE_DPAD_CENTER,
// 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
} // namespace

static std::string PrintAxisIds(const std::vector<int>& axisIds)
{
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;
}
// 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,
Expand All @@ -105,6 +135,7 @@ static void MapAxisIds(int axisId,
else if (axisId == secondaryAxisId)
axisIds.insert(axisIds.begin(), primaryAxisId);
}
} // namespace

CAndroidJoystickState::CAndroidJoystickState(CAndroidJoystickState&& other) noexcept
: m_deviceId(other.m_deviceId),
Expand Down Expand Up @@ -139,10 +170,9 @@ 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();
Expand All @@ -154,24 +184,16 @@ bool CAndroidJoystickState::Initialize(const CJNIViewInputDevice& inputDevice)
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)
// 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())
{
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
Expand All @@ -180,19 +202,34 @@ bool CAndroidJoystickState::Initialize(const CJNIViewInputDevice& inputDevice)
MapAxisIds(axisId, AMOTION_EVENT_AXIS_RTRIGGER, AMOTION_EVENT_AXIS_GAS, axis.ids);

m_axes.emplace_back(std::move(axis));
CLog::Log(LOGDEBUG,
"CAndroidJoystickState: axis {} on input device \"{}\" with ID {} detected",
PrintAxisIds(m_axes.back().ids), deviceName, m_deviceId);
}
else
CLog::Log(LOGWARNING,
"CAndroidJoystickState: ignoring unknown axis {} on input device \"{}\" with ID {}",
axisId, deviceName, m_deviceId);
}

// map buttons
for (int buttonKeycode : ButtonKeycodes)
m_buttons.emplace_back(JoystickAxis{{buttonKeycode}});
// 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)
Expand Down