// SPDX-FileCopyrightText: 2026 Marco Allegretti // SPDX-License-Identifier: EUPL-1.2 #include "gamepaddevice.h" #include #include #include #include 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; } if (SDL_SetGamepadPlayerIndex(m_pad, index)) { Q_EMIT playerIndexChanged(); } } bool GamepadDevice::rumble(int lowIntensity, int highIntensity, int durationMs) { if (!m_pad) { return false; } auto lo = static_cast(std::clamp(lowIntensity, 0, 65535)); auto hi = static_cast(std::clamp(highIntensity, 0, 65535)); auto dur = static_cast(std::clamp(durationMs, 0, durationMs)); return SDL_RumbleGamepad(m_pad, lo, hi, dur); } bool GamepadDevice::setLED(int r, int g, int b) { if (!m_pad) { return false; } auto cr = static_cast(std::clamp(r, 0, 255)); auto cg = static_cast(std::clamp(g, 0, 255)); auto cb = static_cast(std::clamp(b, 0, 255)); return SDL_SetGamepadLED(m_pad, cr, cg, cb); } 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(); } }