#pragma once #include #include #include #include // Gestor global de gamepads. Descobreix els mandos presents a `init()` // sense emetre notificacions (el jugador ja els té posats al llançar el // joc). Durant el runtime, `handleEvent()` processa els events de hot-plug // i emet notificacions visibles via `Notification::notify`. // // El polling real de botons i eixos NO es fa a través d'aquesta classe: // els consumidors obtenen el `SDL_Gamepad*` primari (o l'enèsim per a // multi-jugador futur) i el passen a `InputState::getGamepadButton/Axis`, // que ho filtra pel flag de bloqueig de la UI (mateixa estratègia que // amb el teclat). class GamepadManager { public: static auto get() -> GamepadManager&; GamepadManager(const GamepadManager&) = delete; GamepadManager(GamepadManager&&) = delete; auto operator=(const GamepadManager&) -> GamepadManager& = delete; auto operator=(GamepadManager&&) -> GamepadManager& = delete; // Inicialitza el subsistema SDL de gamepad, intenta carregar un // `gamecontrollerdb.txt` opcional i obri silenciosament tots els // mandos ja connectats. Cridat una sola vegada des de Director. void init(); // Tanca tots els gamepads oberts i treu el subsistema SDL. Cridat // des de `~Director` abans de `SDL_Quit` per evitar handles orfes. void shutdown(); // Processa SDL_EVENT_GAMEPAD_ADDED i SDL_EVENT_GAMEPAD_REMOVED // emesos durant el runtime. Emet notificacions " connectat" o // " desconnectat". El Director decideix quins events li arriben // via `processGamepadEvents()`. void handleEvent(const SDL_Event& ev); // Primary = primer gamepad al vector. `nullptr` si no n'hi ha cap. // Ús típic: Player 1 i navegació del ServiceMenu. [[nodiscard]] auto getPrimary() const -> SDL_Gamepad*; [[nodiscard]] auto getCount() const -> std::size_t; // Retorna el mand del jugador `idx`-èsim (0-indexed) o `nullptr` si // encara no hi ha prou mandos connectats. Reservat per a multi-jugador. [[nodiscard]] auto getByPlayerIndex(std::size_t idx) const -> SDL_Gamepad*; private: struct Entry { SDL_Gamepad* pad{nullptr}; SDL_JoystickID instance_id{0}; std::string pretty_name; }; GamepadManager() = default; ~GamepadManager() = default; // Retalla `raw` al primer '(' o '[' i elimina espais finals per a // llevar metadata verbosa ("Retroid Controller (vendor: 1001) ..."). // Fallback "Gamepad" si queda buit. No limita l'amplada final — el // Notifier multilinia ja gestiona noms llargs. [[nodiscard]] static auto prettyName(const char* raw) -> std::string; // Si `base` ja existeix al vector, afegeix " #2", " #3", ... fins que // trobi un nom lliure. Així dos mandos idèntics es distingeixen a les // notificacions. [[nodiscard]] auto uniqueName(const std::string& base) const -> std::string; void addGamepad(SDL_JoystickID jid, bool notify); void removeGamepad(SDL_JoystickID jid); std::vector entries_; bool initialized_{false}; };