#include "core/input/key_config.hpp" #include #include #include #include #include "core/resources/resource_helper.hpp" #include "external/fkyaml_node.hpp" namespace KeyConfig { namespace { std::vector key_entries; std::unordered_map index_table; std::string overrides_path; auto findIndex(const std::string& id) -> size_t { auto it = index_table.find(id); if (it == index_table.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_table[entry.id] = key_entries.size(); key_entries.push_back(std::move(entry)); } std::cout << "KeyConfig: " << key_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; } key_entries[idx].scancode = sc; key_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) { key_entries.clear(); index_table.clear(); overrides_path = user_overrides_disk_path; loadDefaults(defaults_resource_path); if (!overrides_path.empty()) { applyOverrides(overrides_path); } } void destroy() { key_entries.clear(); index_table.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 key_entries[idx].scancode; } auto scancodePtr(const std::string& id) -> SDL_Scancode* { auto idx = findIndex(id); if (idx == SIZE_MAX) { return nullptr; } return &key_entries[idx].scancode; } void setScancode(const std::string& id, SDL_Scancode sc) { auto idx = findIndex(id); if (idx == SIZE_MAX) { return; } key_entries[idx].scancode = sc; const char* name = SDL_GetScancodeName(sc); key_entries[idx].code = (name != nullptr) ? name : ""; } auto isGuiKey(SDL_Scancode sc) -> bool { if (sc == SDL_SCANCODE_UNKNOWN) { return false; } return std::ranges::any_of(key_entries, [sc](const auto& e) { return e.scancode == sc; }); } auto entries() -> const std::vector& { return key_entries; } auto saveOverrides() -> bool { if (overrides_path.empty()) { return false; } // Recull només les entrades remapeades. std::vector changed; for (const auto& e : key_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