#include "core/jail/jinput.hpp" #include #include #include "core/system/director.hpp" namespace { // keystates és actualitzat per SDL internament. Des del joc només fem lectures. const bool* keystates = nullptr; // Buffer dels últims 5 caràcters tecle. Emmagatzemem caràcters ASCII // lowercase (traduïts des de SDL_Scancode) per a poder comparar directament // amb les cadenes dels cheats ("reviu", "alone", "obert"). Uint8 cheat[5] = {0, 0, 0, 0, 0}; bool key_pressed = false; // Temps restant en mil·lisegons durant el qual JI_KeyPressed/JI_AnyKey // retornen false. Utilitzat per a evitar que pulsacions fortuïtes // saltin cinemàtiques al començament. float wait_ms = 0.0F; // Per a calcular el delta entre crides a JI_Update sense que els callers // hagen de passar-lo explícitament. Es reinicia a la primera crida. Uint64 last_update_tick = 0; bool input_blocked = false; Uint8 virtual_keystates[JI_VSRC_COUNT][SDL_SCANCODE_COUNT] = {{0}}; auto scancode_to_ascii(Uint8 scancode) -> Uint8 { if (scancode >= SDL_SCANCODE_A && scancode <= SDL_SCANCODE_Z) { return static_cast('a' + (scancode - SDL_SCANCODE_A)); } return 0; } } // namespace void JI_DisableKeyboard(Uint32 time) { wait_ms = static_cast(time); } void JI_SetInputBlocked(bool blocked) { input_blocked = blocked; } void JI_SetVirtualKey(int scancode, int source, bool pressed) { if (scancode < 0 || scancode >= SDL_SCANCODE_COUNT) { return; } if (source < 0 || source >= JI_VSRC_COUNT) { return; } virtual_keystates[source][scancode] = pressed ? 1 : 0; } void JI_moveCheats(Uint8 scancode) { cheat[0] = cheat[1]; cheat[1] = cheat[2]; cheat[2] = cheat[3]; cheat[3] = cheat[4]; cheat[4] = scancode_to_ascii(scancode); } void JI_Update() { // El director ha processat tots els events. Ací només refresquem // el snapshot del teclat i consumim el flag de tecla polsada. if (keystates == nullptr) { keystates = SDL_GetKeyboardState(nullptr); } const Uint64 now = SDL_GetTicks(); if (last_update_tick == 0) { last_update_tick = now; } const auto delta_ms = static_cast(now - last_update_tick); last_update_tick = now; if (wait_ms > 0.0F) { wait_ms -= delta_ms; wait_ms = std::max(wait_ms, 0.0F); } // Consumim el flag de "alguna tecla no-GUI polsada" del director key_pressed = Director::get()->consumeKeyPressed(); } auto JI_KeyPressed(int key) -> bool { if (wait_ms > 0.0F || keystates == nullptr) { return false; } // Input bloquejat (p.ex. menú flotant obert) if (input_blocked) { return false; } // ESC bloquejada pel Director (primera pulsació mostra notificació) if (key == SDL_SCANCODE_ESCAPE && Director::get()->isEscBlocked()) { return false; } if (key < 0 || key >= SDL_SCANCODE_COUNT) { return false; } if (static_cast(keystates[key]) != 0) { return true; } for (auto& virtual_keystate : virtual_keystates) { if (virtual_keystate[key] != 0) { return true; } } return false; } auto JI_CheatActivated(const char* cheat_code) -> bool { const size_t len = std::strlen(cheat_code); if (len > sizeof(cheat)) { return false; } // Compara contra els últims `len` caràcters del buffer. El buffer té // mida fixa 5 i acumula sempre el darrer tecle a la posició 4. const size_t offset = sizeof(cheat) - len; for (size_t i = 0; i < len; i++) { if (cheat[offset + i] != static_cast(cheat_code[i])) { return false; } } return true; } auto JI_AnyKey() -> bool { return wait_ms > 0.0F ? false : key_pressed; }