fix(input): dedup de mandos, auto-assign per ordre i cycles sense col·lisió

This commit is contained in:
JailDesigner committed 2026-04-24 18:06:24 +02:00
1 parent e5b8d7731b
commit 996ff0053e
4 files changed
+111 -20

No files matched your search

+36
View File
@@ -79,6 +79,17 @@ auto GamepadManager::uniqueName(const std::string& base) const -> std::string {
}
void GamepadManager::addGamepad(SDL_JoystickID jid, bool notify) {
// Dedup per `instance_id`: SDL encua un SDL_EVENT_GAMEPAD_ADDED per
// cada mando ja connectat quan s'inicialitza el subsistema, a més
// dels que ja hem obert a `init()`. Sense aquesta guarda, el mateix
// mando s'afegiria dues vegades (silenciós + notificat amb sufix
// "#2") i qualsevol referència via `getPrimary`/`entries_` seria
// ambigua.
const bool ALREADY_KNOWN = std::ranges::any_of(
entries_,
[jid](const Entry& e) { return e.instance_id == jid; });
if (ALREADY_KNOWN) { return; }
installWebStandardMapping(jid);
if (!SDL_IsGamepad(jid)) { return; }
SDL_Gamepad* pad = SDL_OpenGamepad(jid);
@@ -257,3 +268,28 @@ void GamepadManager::unassignFromPlayer(int player_id) {
if (player_id < 0 || player_id >= MAX_PLAYERS) { return; }
assignments_[static_cast<std::size_t>(player_id)] = Assignment{};
}
auto GamepadManager::autoAssignFreeSlots() -> std::vector<AutoAssigned> {
std::vector<AutoAssigned> assigned;
for (int pid = 0; pid < MAX_PLAYERS; ++pid) {
auto& slot = assignments_[static_cast<std::size_t>(pid)];
if (slot.pad != nullptr) { continue; }
// Primer mando que cap altre slot no haja reclamat. Així respectem
// qualsevol assignació persistida que ja haja vinculat un pad
// concret i no el reassignem a un jugador diferent.
for (const auto& e : entries_) {
const bool TAKEN = std::ranges::any_of(
assignments_,
[&](const Assignment& other) { return other.pad == e.pad; });
if (TAKEN) { continue; }
slot.pad = e.pad;
slot.name = e.pretty_name;
slot.path = e.path;
assigned.push_back(AutoAssigned{.player_id = pid, .name = e.pretty_name, .path = e.path});
std::cout << "GamepadManager: auto-assigned " << e.pretty_name
<< " → P" << (pid + 1) << '\n';
break;
}
}
return assigned;
}
+13
View File
@@ -80,6 +80,19 @@ class GamepadManager {
// Esborra l'assignació (per si l'usuari trie "Cap" al menú).
void unassignFromPlayer(int player_id);
// Per a cada slot buit, hi vincula el primer mando connectat que no
// estigui reclamat per un altre slot. Equivalent al patró de
// `coffee_crisis_arcade_edition`: les assignacions persistides tenen
// prioritat; els slots que queden buits després s'emplenen per
// ordre. Retorna la llista de parells (player_id, name, path) que
// s'han vinculat, per a que Options pugui persistir-los.
struct AutoAssigned {
int player_id;
std::string name;
std::string path;
};
auto autoAssignFreeSlots() -> std::vector<AutoAssigned>;
private:
struct Entry {
SDL_Gamepad* pad{nullptr};