#include "core/input/key_config.hpp" #include // Para cerr #include // Para string #include // Para move #include // Para vector #include "core/input/input.hpp" // Para Input #include "core/input/input_types.hpp" // Para STRING_TO_ACTION #include "core/resources/resource_helper.hpp" // Para Resource::Helper #include "external/fkyaml_node.hpp" // Para fkyaml::node // ── Singleton ──────────────────────────────────────────────────────────────── KeyConfig* KeyConfig::instance_ = nullptr; void KeyConfig::init(const std::string& yaml_path) { instance_ = new KeyConfig(); instance_->load(yaml_path); } void KeyConfig::destroy() { delete instance_; instance_ = nullptr; } auto KeyConfig::get() -> KeyConfig* { return instance_; } // ── Carga del YAML ────────────────────────────────────────────────────────── void KeyConfig::load(const std::string& yaml_path) { auto file_data = Resource::Helper::loadFile(yaml_path); if (file_data.empty()) { std::cerr << "KeyConfig: Unable to load " << yaml_path << '\n'; return; } std::string yaml_content(file_data.begin(), file_data.end()); fkyaml::node yaml; try { yaml = fkyaml::node::deserialize(yaml_content); } catch (const fkyaml::exception& e) { std::cerr << "KeyConfig: YAML parse error: " << e.what() << '\n'; return; } if (!yaml.contains("scopes")) { return; } for (const auto& scope_node : yaml["scopes"]) { KeyConfigScope scope; scope.name = scope_node["name"].get_value(); if (scope_node.contains("keys")) { for (const auto& key_node : scope_node["keys"]) { KeyEntry entry; entry.id = key_node["id"].get_value(); entry.display_key = key_node["key"].get_value(); entry.desc = key_node["desc"].get_value(); // Convertir el nombre SDL a keycode if (key_node.contains("code")) { auto code = key_node["code"].get_value(); entry.keycode = SDL_GetKeyFromName(code.c_str()); if (entry.keycode == SDLK_UNKNOWN) { std::cerr << "KeyConfig: Unknown key name '" << code << "' for " << scope.name << "." << entry.id << '\n'; } } // InputAction opcional (para scope GLOBAL) if (key_node.contains("action")) { entry.action = key_node["action"].get_value(); } scope.index[entry.id] = scope.entries.size(); scope.entries.push_back(std::move(entry)); } } scope_index_[scope.name] = scopes_.size(); scopes_.push_back(std::move(scope)); } std::cout << "KeyConfig: Loaded " << scopes_.size() << " scopes from " << yaml_path << '\n'; } // ── Consultas ─────────────────────────────────────────────────────────────── auto KeyConfig::key(const std::string& scope, const std::string& id) const -> SDL_Keycode { const auto* s = getScope(scope); if (s == nullptr) { return SDLK_UNKNOWN; } auto it = s->index.find(id); if (it == s->index.end()) { return SDLK_UNKNOWN; } return s->entries[it->second].keycode; } void KeyConfig::applyGlobalBindings() const { const auto* global = getScope("GLOBAL"); if (global == nullptr) { return; } for (const auto& entry : global->entries) { if (entry.action.empty() || entry.keycode == SDLK_UNKNOWN) { continue; } auto it = STRING_TO_ACTION.find(entry.action); if (it == STRING_TO_ACTION.end()) { std::cerr << "KeyConfig: Unknown action '" << entry.action << "' for " << entry.id << '\n'; continue; } // Convertir keycode a scancode para el sistema de Input SDL_Scancode scancode = SDL_GetScancodeFromKey(entry.keycode, nullptr); if (scancode != SDL_SCANCODE_UNKNOWN) { Input::get()->bindKey(it->second, scancode); } } } auto KeyConfig::getScopes() const -> const std::vector& { return scopes_; } auto KeyConfig::getScope(const std::string& name) const -> const KeyConfigScope* { auto it = scope_index_.find(name); if (it == scope_index_.end()) { return nullptr; } return &scopes_[it->second]; }