#include "core/input/key_config.hpp" #include #include #include #include "core/resources/resource_helper.hpp" #include "external/fkyaml_node.hpp" namespace KeyConfig { namespace { std::vector entries_; std::unordered_map index_; std::string overrides_path_; auto findIndex(const std::string& id) -> size_t { auto it = index_.find(id); if (it == index_.end()) return SIZE_MAX; return it->second; } void loadDefaults(const std::string& defaults_resource_path) { auto buf = ResourceHelper::loadFile(defaults_resource_path); if (buf.empty()) { std::cerr << "KeyConfig: no s'ha pogut llegir " << defaults_resource_path << '\n'; return; } std::string content(buf.begin(), buf.end()); try { auto yaml = fkyaml::node::deserialize(content); if (!yaml.contains("keys")) return; for (const auto& node : yaml["keys"]) { KeyEntry entry; entry.id = node["id"].get_value(); entry.code = node["code"].get_value(); if (node.contains("desc")) { entry.desc = node["desc"].get_value(); } SDL_Scancode sc = SDL_GetScancodeFromName(entry.code.c_str()); if (sc == SDL_SCANCODE_UNKNOWN) { std::cerr << "KeyConfig: scancode desconegut '" << entry.code << "' per '" << entry.id << "'\n"; } entry.scancode = sc; entry.default_scancode = sc; index_[entry.id] = entries_.size(); entries_.push_back(std::move(entry)); } std::cout << "KeyConfig: " << entries_.size() << " tecles carregades de " << defaults_resource_path << '\n'; } catch (const fkyaml::exception& e) { std::cerr << "KeyConfig: error parsejant YAML: " << e.what() << '\n'; } } void applyOverrides(const std::string& disk_path) { std::ifstream file(disk_path); if (!file.good()) return; std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); file.close(); try { auto yaml = fkyaml::node::deserialize(content); if (!yaml.contains("overrides")) return; int applied = 0; for (const auto& kv : yaml["overrides"].as_map()) { auto id = kv.first.get_value(); auto code = kv.second.get_value(); auto idx = findIndex(id); if (idx == SIZE_MAX) { std::cerr << "KeyConfig: override per id desconegut '" << id << "'\n"; continue; } SDL_Scancode sc = SDL_GetScancodeFromName(code.c_str()); if (sc == SDL_SCANCODE_UNKNOWN) { std::cerr << "KeyConfig: override amb scancode invàlid '" << code << "' per '" << id << "'\n"; continue; } entries_[idx].scancode = sc; entries_[idx].code = code; applied++; } if (applied > 0) { std::cout << "KeyConfig: aplicats " << applied << " overrides de " << disk_path << '\n'; } } catch (const fkyaml::exception& e) { std::cerr << "KeyConfig: error parsejant overrides: " << e.what() << '\n'; } } } // namespace void init(const std::string& defaults_resource_path, const std::string& user_overrides_disk_path) { entries_.clear(); index_.clear(); overrides_path_ = user_overrides_disk_path; loadDefaults(defaults_resource_path); if (!overrides_path_.empty()) { applyOverrides(overrides_path_); } } void destroy() { entries_.clear(); index_.clear(); overrides_path_.clear(); } auto scancode(const std::string& id) -> SDL_Scancode { auto idx = findIndex(id); if (idx == SIZE_MAX) return SDL_SCANCODE_UNKNOWN; return entries_[idx].scancode; } auto scancodePtr(const std::string& id) -> SDL_Scancode* { auto idx = findIndex(id); if (idx == SIZE_MAX) return nullptr; return &entries_[idx].scancode; } void setScancode(const std::string& id, SDL_Scancode sc) { auto idx = findIndex(id); if (idx == SIZE_MAX) return; entries_[idx].scancode = sc; const char* name = SDL_GetScancodeName(sc); entries_[idx].code = (name != nullptr) ? name : ""; } auto isGuiKey(SDL_Scancode sc) -> bool { if (sc == SDL_SCANCODE_UNKNOWN) return false; for (const auto& e : entries_) { if (e.scancode == sc) return true; } return false; } auto entries() -> const std::vector& { return entries_; } auto saveOverrides() -> bool { if (overrides_path_.empty()) return false; // Recull només les entrades remapeades. std::vector changed; for (const auto& e : entries_) { if (e.scancode != e.default_scancode) changed.push_back(&e); } std::ofstream file(overrides_path_); if (!file.is_open()) { std::cerr << "KeyConfig: no es pot escriure " << overrides_path_ << '\n'; return false; } file << "# AEE - Overrides de tecles d'UI\n"; file << "# Auto-generat. Només llista les tecles modificades respecte\n"; file << "# els valors per defecte de data/input/keys.yaml.\n"; file << "\n"; if (changed.empty()) { file << "overrides: {}\n"; } else { file << "overrides:\n"; for (const auto* e : changed) { file << " " << e->id << ": \"" << e->code << "\"\n"; } } return true; } } // namespace KeyConfig