Files
projecte_2026/source/core/input/key_config.cpp

127 lines
4.8 KiB
C++

#include "core/input/key_config.hpp"
#include <iostream> // Para cerr
#include <string> // Para string
#include <utility> // Para move
#include <vector> // 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<std::string>();
if (scope_node.contains("keys")) {
for (const auto& key_node : scope_node["keys"]) {
KeyEntry entry;
entry.id = key_node["id"].get_value<std::string>();
entry.display_key = key_node["key"].get_value<std::string>();
entry.desc = key_node["desc"].get_value<std::string>();
// Convertir el nombre SDL a keycode
if (key_node.contains("code")) {
auto code = key_node["code"].get_value<std::string>();
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<std::string>();
}
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<KeyConfigScope>& {
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];
}