2026-04-20 07:43:11 +00:00
|
|
|
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
|
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
#include "gamepaddevice.h"
|
|
|
|
|
|
|
|
|
|
#include <SDL3/SDL_gamepad.h>
|
|
|
|
|
#include <SDL3/SDL_power.h>
|
|
|
|
|
#include <SDL3/SDL_properties.h>
|
|
|
|
|
|
2026-04-20 12:09:33 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
|
2026-04-20 07:43:11 +00:00
|
|
|
GamepadDevice::GamepadDevice(SDL_Gamepad *pad, int id, QObject *parent)
|
|
|
|
|
: QObject(parent)
|
|
|
|
|
, m_pad(pad)
|
|
|
|
|
, m_id(id)
|
|
|
|
|
{
|
|
|
|
|
refreshBattery();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GamepadDevice::~GamepadDevice()
|
|
|
|
|
{
|
|
|
|
|
if (m_pad) {
|
|
|
|
|
SDL_CloseGamepad(m_pad);
|
|
|
|
|
m_pad = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GamepadDevice::deviceId() const
|
|
|
|
|
{
|
|
|
|
|
return m_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GamepadDevice::name() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
const char *n = SDL_GetGamepadName(m_pad);
|
|
|
|
|
return n ? QString::fromUtf8(n) : QString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GamepadDevice::type() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return QStringLiteral("unknown");
|
|
|
|
|
}
|
|
|
|
|
switch (SDL_GetGamepadType(m_pad)) {
|
|
|
|
|
case SDL_GAMEPAD_TYPE_XBOX360:
|
|
|
|
|
case SDL_GAMEPAD_TYPE_XBOXONE:
|
|
|
|
|
return QStringLiteral("xbox");
|
|
|
|
|
case SDL_GAMEPAD_TYPE_PS3:
|
|
|
|
|
case SDL_GAMEPAD_TYPE_PS4:
|
|
|
|
|
case SDL_GAMEPAD_TYPE_PS5:
|
|
|
|
|
return QStringLiteral("playstation");
|
|
|
|
|
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO:
|
|
|
|
|
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT:
|
|
|
|
|
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT:
|
|
|
|
|
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
|
|
|
|
|
return QStringLiteral("nintendo");
|
|
|
|
|
default:
|
|
|
|
|
return QStringLiteral("generic");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GamepadDevice::batteryPercent() const
|
|
|
|
|
{
|
|
|
|
|
return m_batteryPercent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GamepadDevice::hasRumble() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
SDL_PropertiesID props = SDL_GetGamepadProperties(m_pad);
|
|
|
|
|
return SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GamepadDevice::hasLED() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
SDL_PropertiesID props = SDL_GetGamepadProperties(m_pad);
|
|
|
|
|
return SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_RGB_LED_BOOLEAN, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GamepadDevice::playerIndex() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return SDL_GetGamepadPlayerIndex(m_pad);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GamepadDevice::setPlayerIndex(int index)
|
|
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-04-20 12:09:33 +00:00
|
|
|
if (SDL_SetGamepadPlayerIndex(m_pad, index)) {
|
|
|
|
|
Q_EMIT playerIndexChanged();
|
|
|
|
|
}
|
2026-04-20 07:43:11 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-20 12:09:33 +00:00
|
|
|
bool GamepadDevice::rumble(int lowIntensity, int highIntensity, int durationMs)
|
2026-04-20 07:43:11 +00:00
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-04-20 12:09:33 +00:00
|
|
|
auto lo = static_cast<uint16_t>(std::clamp(lowIntensity, 0, 65535));
|
|
|
|
|
auto hi = static_cast<uint16_t>(std::clamp(highIntensity, 0, 65535));
|
|
|
|
|
auto dur = static_cast<uint32_t>(std::clamp(durationMs, 0, durationMs));
|
|
|
|
|
return SDL_RumbleGamepad(m_pad, lo, hi, dur);
|
2026-04-20 07:43:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GamepadDevice::setLED(int r, int g, int b)
|
|
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-04-20 12:09:33 +00:00
|
|
|
auto cr = static_cast<uint8_t>(std::clamp(r, 0, 255));
|
|
|
|
|
auto cg = static_cast<uint8_t>(std::clamp(g, 0, 255));
|
|
|
|
|
auto cb = static_cast<uint8_t>(std::clamp(b, 0, 255));
|
|
|
|
|
return SDL_SetGamepadLED(m_pad, cr, cg, cb);
|
2026-04-20 07:43:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SDL_Gamepad *GamepadDevice::sdlGamepad() const
|
|
|
|
|
{
|
|
|
|
|
return m_pad;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GamepadDevice::refreshBattery()
|
|
|
|
|
{
|
|
|
|
|
if (!m_pad) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int pct = -1;
|
|
|
|
|
SDL_GetGamepadPowerInfo(m_pad, &pct);
|
|
|
|
|
if (pct != m_batteryPercent) {
|
|
|
|
|
m_batteryPercent = pct;
|
|
|
|
|
Q_EMIT batteryPercentChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|