Files
aee/source/core/jail/jinput.cpp

113 lines
3.5 KiB
C++

#include "core/jail/jinput.hpp"
#include <cstring>
#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}};
Uint8 scancode_to_ascii(Uint8 scancode) {
if (scancode >= SDL_SCANCODE_A && scancode <= SDL_SCANCODE_Z) {
return static_cast<Uint8>('a' + (scancode - SDL_SCANCODE_A));
}
return 0;
}
} // namespace
void JI_DisableKeyboard(Uint32 time) {
wait_ms = static_cast<float>(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(NULL);
}
const Uint64 now = SDL_GetTicks();
if (last_update_tick == 0) last_update_tick = now;
const float delta_ms = static_cast<float>(now - last_update_tick);
last_update_tick = now;
if (wait_ms > 0.0f) {
wait_ms -= delta_ms;
if (wait_ms < 0.0f) wait_ms = 0.0f;
}
// Consumim el flag de "alguna tecla no-GUI polsada" del director
key_pressed = Director::get()->consumeKeyPressed();
}
bool JI_KeyPressed(int key) {
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 (keystates[key] != 0) return true;
for (int src = 0; src < JI_VSRC_COUNT; src++) {
if (virtual_keystates[src][key] != 0) return true;
}
return false;
}
bool JI_CheatActivated(const char* cheat_code) {
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<Uint8>(cheat_code[i])) return false;
}
return true;
}
bool JI_AnyKey() {
return wait_ms > 0.0f ? false : key_pressed;
}