239 lines
8.1 KiB
C
239 lines
8.1 KiB
C
/*
|
|
* Pruebas sin pantalla de la lógica de entrada: máquina de estados de
|
|
* teclado/ratón, cola de eventos y consultas públicas. Usa cabeceras internas.
|
|
*/
|
|
#include "check.h"
|
|
|
|
#include <fnix/fnix.h>
|
|
|
|
#include "core/window_internal.h"
|
|
#include "input/input_internal.h"
|
|
|
|
#include <string.h>
|
|
|
|
static FnixEvent key_event(FnixEventType type, FnixKey key)
|
|
{
|
|
FnixEvent e;
|
|
memset(&e, 0, sizeof e);
|
|
e.type = type;
|
|
e.key = key;
|
|
return e;
|
|
}
|
|
|
|
static FnixEvent mouse_event(FnixEventType type, FnixMouseButton button, int x, int y)
|
|
{
|
|
FnixEvent e;
|
|
memset(&e, 0, sizeof e);
|
|
e.type = type;
|
|
e.button = button;
|
|
e.x = x;
|
|
e.y = y;
|
|
return e;
|
|
}
|
|
|
|
static void test_key_lifecycle(void)
|
|
{
|
|
FnixInputState s;
|
|
memset(&s, 0, sizeof s);
|
|
|
|
FnixEvent down = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_A);
|
|
fnix_input_apply_event(&s, &down);
|
|
CHECK(s.key_down[FNIX_KEY_A] && s.key_pressed[FNIX_KEY_A]);
|
|
CHECK(!down.repeat);
|
|
|
|
/* Autorepeat: el sistema repite KEY_DOWN sin KEY_UP. */
|
|
FnixEvent again = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_A);
|
|
fnix_input_apply_event(&s, &again);
|
|
CHECK(again.repeat);
|
|
CHECK(s.key_down[FNIX_KEY_A]);
|
|
|
|
fnix_input_begin_frame(&s);
|
|
CHECK(s.key_down[FNIX_KEY_A]);
|
|
CHECK(!s.key_pressed[FNIX_KEY_A]);
|
|
|
|
/* Una repetición en un fotograma posterior tampoco vuelve a "pressed". */
|
|
FnixEvent repeat2 = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_A);
|
|
fnix_input_apply_event(&s, &repeat2);
|
|
CHECK(!s.key_pressed[FNIX_KEY_A]);
|
|
|
|
FnixEvent up = key_event(FNIX_EVENT_KEY_UP, FNIX_KEY_A);
|
|
fnix_input_apply_event(&s, &up);
|
|
CHECK(!s.key_down[FNIX_KEY_A] && s.key_released[FNIX_KEY_A]);
|
|
|
|
fnix_input_begin_frame(&s);
|
|
CHECK(!s.key_released[FNIX_KEY_A]);
|
|
|
|
/* Pulsar y soltar dentro del mismo fotograma no se pierde. */
|
|
FnixEvent quick_down = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_B);
|
|
FnixEvent quick_up = key_event(FNIX_EVENT_KEY_UP, FNIX_KEY_B);
|
|
fnix_input_apply_event(&s, &quick_down);
|
|
fnix_input_apply_event(&s, &quick_up);
|
|
CHECK(s.key_pressed[FNIX_KEY_B] && s.key_released[FNIX_KEY_B]);
|
|
CHECK(!s.key_down[FNIX_KEY_B]);
|
|
|
|
/* Soltar una tecla que no estaba pulsada no genera "released". */
|
|
FnixEvent stray_up = key_event(FNIX_EVENT_KEY_UP, FNIX_KEY_C);
|
|
fnix_input_apply_event(&s, &stray_up);
|
|
CHECK(!s.key_released[FNIX_KEY_C]);
|
|
|
|
/* Teclas inválidas se ignoran sin escribir fuera del arreglo. */
|
|
FnixEvent bad1 = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_UNKNOWN);
|
|
FnixEvent bad2 = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_COUNT);
|
|
FnixEvent bad3 = key_event(FNIX_EVENT_KEY_DOWN, (FnixKey)-5);
|
|
fnix_input_apply_event(&s, &bad1);
|
|
fnix_input_apply_event(&s, &bad2);
|
|
fnix_input_apply_event(&s, &bad3);
|
|
}
|
|
|
|
static void test_mouse(void)
|
|
{
|
|
FnixInputState s;
|
|
memset(&s, 0, sizeof s);
|
|
|
|
FnixEvent move = mouse_event(FNIX_EVENT_MOUSE_MOVE, FNIX_MOUSE_LEFT, 12, 34);
|
|
fnix_input_apply_event(&s, &move);
|
|
CHECK(s.mouse_x == 12 && s.mouse_y == 34);
|
|
|
|
FnixEvent down = mouse_event(FNIX_EVENT_MOUSE_BUTTON_DOWN, FNIX_MOUSE_RIGHT, 50, 60);
|
|
fnix_input_apply_event(&s, &down);
|
|
CHECK(s.mouse_down[FNIX_MOUSE_RIGHT] && s.mouse_pressed[FNIX_MOUSE_RIGHT]);
|
|
CHECK(!s.mouse_down[FNIX_MOUSE_LEFT]);
|
|
CHECK(s.mouse_x == 50 && s.mouse_y == 60);
|
|
|
|
fnix_input_begin_frame(&s);
|
|
CHECK(s.mouse_down[FNIX_MOUSE_RIGHT] && !s.mouse_pressed[FNIX_MOUSE_RIGHT]);
|
|
|
|
FnixEvent up = mouse_event(FNIX_EVENT_MOUSE_BUTTON_UP, FNIX_MOUSE_RIGHT, 51, 61);
|
|
fnix_input_apply_event(&s, &up);
|
|
CHECK(!s.mouse_down[FNIX_MOUSE_RIGHT] && s.mouse_released[FNIX_MOUSE_RIGHT]);
|
|
|
|
/* Rueda: se acumula dentro del fotograma y se borra al empezar el siguiente. */
|
|
fnix_input_begin_frame(&s);
|
|
FnixEvent w1 = mouse_event(FNIX_EVENT_MOUSE_WHEEL, FNIX_MOUSE_LEFT, 0, 0);
|
|
FnixEvent w2 = w1;
|
|
FnixEvent w3 = w1;
|
|
w1.wheel = 1;
|
|
w2.wheel = 1;
|
|
w3.wheel = -1;
|
|
fnix_input_apply_event(&s, &w1);
|
|
fnix_input_apply_event(&s, &w2);
|
|
fnix_input_apply_event(&s, &w3);
|
|
CHECK(s.wheel == 1);
|
|
fnix_input_begin_frame(&s);
|
|
CHECK(s.wheel == 0);
|
|
|
|
/* Botón inválido: no escribe fuera del arreglo. */
|
|
FnixEvent bad = mouse_event(FNIX_EVENT_MOUSE_BUTTON_DOWN, (FnixMouseButton)99, 0, 0);
|
|
fnix_input_apply_event(&s, &bad);
|
|
}
|
|
|
|
static void test_focus_lost(void)
|
|
{
|
|
FnixInputState s;
|
|
memset(&s, 0, sizeof s);
|
|
|
|
FnixEvent k = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_W);
|
|
FnixEvent m = mouse_event(FNIX_EVENT_MOUSE_BUTTON_DOWN, FNIX_MOUSE_LEFT, 1, 1);
|
|
fnix_input_apply_event(&s, &k);
|
|
fnix_input_apply_event(&s, &m);
|
|
fnix_input_begin_frame(&s);
|
|
CHECK(s.key_down[FNIX_KEY_W] && s.mouse_down[FNIX_MOUSE_LEFT]);
|
|
|
|
FnixEvent lost;
|
|
memset(&lost, 0, sizeof lost);
|
|
lost.type = FNIX_EVENT_FOCUS_LOST;
|
|
fnix_input_apply_event(&s, &lost);
|
|
CHECK(!s.key_down[FNIX_KEY_W] && s.key_released[FNIX_KEY_W]);
|
|
CHECK(!s.mouse_down[FNIX_MOUSE_LEFT] && s.mouse_released[FNIX_MOUSE_LEFT]);
|
|
}
|
|
|
|
static void test_event_queue(void)
|
|
{
|
|
static FnixEventQueue q; /* es grande: fuera de la pila */
|
|
memset(&q, 0, sizeof q);
|
|
FnixEvent out;
|
|
|
|
CHECK(!fnix_event_queue_pop(&q, &out));
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
FnixEvent e = mouse_event(FNIX_EVENT_MOUSE_MOVE, FNIX_MOUSE_LEFT, i, 0);
|
|
fnix_event_queue_push(&q, &e);
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
CHECK(fnix_event_queue_pop(&q, &out) && out.x == i);
|
|
}
|
|
CHECK(!fnix_event_queue_pop(&q, &out));
|
|
|
|
/* Desbordamiento: se conservan los FNIX_EVENT_QUEUE_CAPACITY más recientes. */
|
|
const int total = FNIX_EVENT_QUEUE_CAPACITY + 44;
|
|
for (int i = 0; i < total; i++) {
|
|
FnixEvent e = mouse_event(FNIX_EVENT_MOUSE_MOVE, FNIX_MOUSE_LEFT, i, 0);
|
|
fnix_event_queue_push(&q, &e);
|
|
}
|
|
CHECK(q.count == FNIX_EVENT_QUEUE_CAPACITY);
|
|
for (int i = total - FNIX_EVENT_QUEUE_CAPACITY; i < total; i++) {
|
|
CHECK(fnix_event_queue_pop(&q, &out) && out.x == i);
|
|
}
|
|
CHECK(!fnix_event_queue_pop(&q, &out));
|
|
}
|
|
|
|
static void test_public_queries(void)
|
|
{
|
|
/* Una ventana "falsa" (sin plataforma) basta para probar la API pública. */
|
|
static FnixWindow w;
|
|
memset(&w, 0, sizeof w);
|
|
|
|
FnixEvent down = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_SPACE);
|
|
fnix_window_dispatch_event(&w, &down);
|
|
CHECK(fnix_key_down(&w, FNIX_KEY_SPACE));
|
|
CHECK(fnix_key_pressed(&w, FNIX_KEY_SPACE));
|
|
CHECK(!fnix_key_released(&w, FNIX_KEY_SPACE));
|
|
CHECK(!fnix_key_down(&w, FNIX_KEY_A));
|
|
|
|
FnixEvent click = mouse_event(FNIX_EVENT_MOUSE_BUTTON_DOWN, FNIX_MOUSE_MIDDLE, 7, 9);
|
|
fnix_window_dispatch_event(&w, &click);
|
|
CHECK(fnix_mouse_down(&w, FNIX_MOUSE_MIDDLE));
|
|
CHECK(fnix_mouse_pressed(&w, FNIX_MOUSE_MIDDLE));
|
|
CHECK(fnix_mouse_x(&w) == 7 && fnix_mouse_y(&w) == 9);
|
|
|
|
/* Los eventos quedaron en la cola, en orden. */
|
|
FnixEvent e;
|
|
CHECK(fnix_window_poll_event(&w, &e) && e.type == FNIX_EVENT_KEY_DOWN &&
|
|
e.key == FNIX_KEY_SPACE);
|
|
CHECK(fnix_window_poll_event(&w, &e) && e.type == FNIX_EVENT_MOUSE_BUTTON_DOWN);
|
|
CHECK(!fnix_window_poll_event(&w, &e));
|
|
CHECK(!fnix_window_poll_event(&w, NULL));
|
|
|
|
/* El cierre marca la ventana. */
|
|
CHECK(!fnix_window_should_close(&w));
|
|
FnixEvent close_event;
|
|
memset(&close_event, 0, sizeof close_event);
|
|
close_event.type = FNIX_EVENT_WINDOW_CLOSE;
|
|
fnix_window_dispatch_event(&w, &close_event);
|
|
CHECK(fnix_window_should_close(&w));
|
|
|
|
/* Argumentos inválidos: nunca fallan, devuelven falso/0. */
|
|
CHECK(!fnix_key_down(NULL, FNIX_KEY_A));
|
|
CHECK(!fnix_key_pressed(NULL, FNIX_KEY_A));
|
|
CHECK(!fnix_key_released(NULL, FNIX_KEY_A));
|
|
CHECK(!fnix_key_down(&w, FNIX_KEY_UNKNOWN));
|
|
CHECK(!fnix_key_down(&w, FNIX_KEY_COUNT));
|
|
CHECK(!fnix_key_down(&w, (FnixKey)-1));
|
|
CHECK(!fnix_mouse_down(NULL, FNIX_MOUSE_LEFT));
|
|
CHECK(!fnix_mouse_down(&w, FNIX_MOUSE_BUTTON_COUNT));
|
|
CHECK(!fnix_mouse_pressed(&w, (FnixMouseButton)-1));
|
|
CHECK(!fnix_mouse_released(NULL, FNIX_MOUSE_LEFT));
|
|
CHECK(fnix_mouse_x(NULL) == 0 && fnix_mouse_y(NULL) == 0);
|
|
CHECK(fnix_mouse_wheel(NULL) == 0);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
test_key_lifecycle();
|
|
test_mouse();
|
|
test_focus_lost();
|
|
test_event_queue();
|
|
test_public_queries();
|
|
return CHECK_REPORT("test_input");
|
|
}
|