From 44c14047f46262fd15574d51de85ee9dd5afad03 Mon Sep 17 00:00:00 2001 From: Periicles Date: Wed, 17 Jun 2026 13:37:49 +0200 Subject: [PATCH] feat(input): track keyboard state from events instead of polling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sfKeyboard_isKeyPressed polls the OS directly, which on macOS returns false unless the app has the "Input Monitoring" permission — so movement, attack, interact and Escape silently did nothing on a fresh machine. Add an input module that maintains a per-key pressed state from the window's KeyPressed/KeyReleased events (and clears it on focus loss), and replace every sfKeyboard_isKeyPressed call with is_key_held(). The event loops (2D, raycasting and the intro dialog) now feed input_handle_event, and Escape is handled purely from the event. This only needs window focus, so the game is playable everywhere without any system permission. Build warning-free, full Banana scan back to 0, 20/20 tests pass under ASan/UBSan. --- Makefile | 1 + include/game.h | 1 + include/input.h | 16 +++++++++++ src/input.c | 44 +++++++++++++++++++++++++++++++ src/utils/display/dialog.c | 2 ++ src/utils/display/npc.c | 3 ++- src/utils/display/perso.c | 17 ++++++------ src/utils/events/index.c | 4 ++- src/utils/events/inventory.c | 3 ++- src/utils/events/zoom.c | 3 ++- src/utils/mobs/manage_mobs.c | 3 ++- src/utils/raycasting/move.c | 19 ++++++------- src/utils/raycasting/raycasting.c | 6 ++++- 13 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 include/input.h create mode 100644 src/input.c diff --git a/Makefile b/Makefile index b5217f1..2db855c 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ SRC = src/main.c \ src/change_map.c \ src/flags.c \ src/menu.c \ + src/input.c \ $(addprefix src/utils/create/, \ $(addsuffix .c, \ raycasting \ diff --git a/include/game.h b/include/game.h index a3a9baa..b4ad549 100644 --- a/include/game.h +++ b/include/game.h @@ -54,6 +54,7 @@ typedef struct game_s { end_t *loose; bool is_finished; int nb_mob_killed; + bool keystate[sfKeyCount]; } game_t; bool is_error(const char **env); diff --git a/include/input.h b/include/input.h new file mode 100644 index 0000000..571b4bc --- /dev/null +++ b/include/input.h @@ -0,0 +1,16 @@ +/* +** EPITECH PROJECT, 2023 +** rpg +** File description: +** input +*/ + +#ifndef INPUT_H_ + #define INPUT_H_ + + #include "game.h" + +void input_handle_event(game_t *game); +bool is_key_held(game_t *game, sfKeyCode key); + +#endif /* !INPUT_H_ */ diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..17b4eec --- /dev/null +++ b/src/input.c @@ -0,0 +1,44 @@ +/* +** EPITECH PROJECT, 2023 +** rpg +** File description: +** input +*/ + +/* +** Event-driven keyboard state. sfKeyboard_isKeyPressed polls the OS and, on +** macOS, returns false without the "Input Monitoring" permission. Tracking the +** key state from KeyPressed/KeyReleased events instead only needs window focus, +** so the game plays anywhere. +*/ + +#include "game.h" +#include "input.h" + +static void clear_keystate(game_t *game) +{ + int i = 0; + + for (i = 0; i < sfKeyCount; i++) + game->keystate[i] = false; +} + +void input_handle_event(game_t *game) +{ + sfEvent *event = &game->window->event; + + if (event->type == sfEvtFocusLost) + clear_keystate(game); + if (event->type != sfEvtKeyPressed && event->type != sfEvtKeyReleased) + return; + if (event->key.code < 0 || event->key.code >= sfKeyCount) + return; + game->keystate[event->key.code] = event->type == sfEvtKeyPressed; +} + +bool is_key_held(game_t *game, sfKeyCode key) +{ + if (key < 0 || key >= sfKeyCount) + return false; + return game->keystate[key]; +} diff --git a/src/utils/display/dialog.c b/src/utils/display/dialog.c index afbd272..bb48c64 100644 --- a/src/utils/display/dialog.c +++ b/src/utils/display/dialog.c @@ -8,6 +8,7 @@ #include "game.h" #include "display.h" #include "menu.h" +#include "input.h" static int poll_dialog(game_t *game) { @@ -15,6 +16,7 @@ static int poll_dialog(game_t *game) while (sfRenderWindow_pollEvent(game->window->window, &game->window->event)) { + input_handle_event(game); if (game->window->event.type == sfEvtClosed) sfRenderWindow_close(game->window->window); if (game->window->event.type == sfEvtKeyPressed) diff --git a/src/utils/display/npc.c b/src/utils/display/npc.c index fa0f81a..270aee7 100644 --- a/src/utils/display/npc.c +++ b/src/utils/display/npc.c @@ -6,6 +6,7 @@ */ #include +#include "input.h" #include "game.h" #include "display.h" @@ -31,7 +32,7 @@ static void get_distance(game_t *game, int i, const sfVector2f *second_pos) game->npc[i]->distance_to_player = sqrt(pow(dx, 2) + pow(dy, 2)); if (game->npc[i]->distance_to_player < 100 - && sfKeyboard_isKeyPressed(game->keys->interact)) + && is_key_held(game, game->keys->interact)) try_interact(game, i); } diff --git a/src/utils/display/perso.c b/src/utils/display/perso.c index 0dacac1..138db4b 100644 --- a/src/utils/display/perso.c +++ b/src/utils/display/perso.c @@ -7,6 +7,7 @@ #include #include "menu.h" +#include "input.h" #include "game.h" #include "collisions.h" @@ -26,14 +27,14 @@ static void move_player_vertical(game_t *game) sfVector2f pos = perso->pos; sfVector2f dim = {45, 50}; - if (sfKeyboard_isKeyPressed(game->keys->left) - || sfKeyboard_isKeyPressed(game->keys->right)) + if (is_key_held(game, game->keys->left) + || is_key_held(game, game->keys->right)) speed = 2.8; - if (sfKeyboard_isKeyPressed(game->keys->up) + if (is_key_held(game, game->keys->up) && is_colliding(game, &(sfVector2f){pos.x, pos.y - 4}, &dim) == 0) { perso->pos.y -= speed; set_perso_move(perso, 18, 1); - } else if (sfKeyboard_isKeyPressed(game->keys->down) + } else if (is_key_held(game, game->keys->down) && is_colliding(game, &(sfVector2f){pos.x, pos.y + 4}, &dim) == 0) { perso->pos.y += speed; set_perso_move(perso, 0, 2); @@ -47,14 +48,14 @@ static void move_player_horizontal(game_t *game) sfVector2f pos = perso->pos; sfVector2f dim = {45, 50}; - if (sfKeyboard_isKeyPressed(game->keys->up) - || sfKeyboard_isKeyPressed(game->keys->down)) + if (is_key_held(game, game->keys->up) + || is_key_held(game, game->keys->down)) speed = 2.8; - if (sfKeyboard_isKeyPressed(game->keys->left) + if (is_key_held(game, game->keys->left) && is_colliding(game, &(sfVector2f){pos.x - 4, pos.y}, &dim) == 0) { perso->pos.x -= speed; set_perso_move(perso, 36, 3); - } else if (sfKeyboard_isKeyPressed(game->keys->right) + } else if (is_key_held(game, game->keys->right) && is_colliding(game, &(sfVector2f){pos.x + 4, pos.y}, &dim) == 0) { perso->pos.x += speed; set_perso_move(perso, 54, 4); diff --git a/src/utils/events/index.c b/src/utils/events/index.c index 04eafc6..6d4bbd6 100644 --- a/src/utils/events/index.c +++ b/src/utils/events/index.c @@ -9,6 +9,7 @@ #include "game.h" #include "events.h" +#include "input.h" static void go_to_raycasting(game_t *game) { @@ -31,10 +32,11 @@ void events_window(game_t *game) go_to_raycasting(game); while (sfRenderWindow_pollEvent(game->window->window, &game->window->event)) { + input_handle_event(game); if (game->window->event.type == sfEvtClosed) exit_start_all(game); if (game->window->event.type == sfEvtKeyPressed - && sfKeyboard_isKeyPressed(sfKeyEscape)) + && game->window->event.key.code == sfKeyEscape) event_menu(game); zoom(game); change_item(game); diff --git a/src/utils/events/inventory.c b/src/utils/events/inventory.c index 306f696..a50e61b 100644 --- a/src/utils/events/inventory.c +++ b/src/utils/events/inventory.c @@ -6,6 +6,7 @@ */ #include "game.h" +#include "input.h" static void change_item_by_key(game_t *game) { @@ -25,7 +26,7 @@ static void change_item_by_key(game_t *game) void change_item(game_t *game) { if (game->window->event.type == sfEvtMouseWheelScrolled && - sfKeyboard_isKeyPressed(sfKeyLControl) == false) { + is_key_held(game, sfKeyLControl) == false) { if (game->window->event.mouseWheelScroll.delta > 0) { game->inventory->item_selected--; } diff --git a/src/utils/events/zoom.c b/src/utils/events/zoom.c index 5771a5c..3c2e7b3 100644 --- a/src/utils/events/zoom.c +++ b/src/utils/events/zoom.c @@ -7,12 +7,13 @@ #include "game.h" #include "events.h" +#include "input.h" void zoom(game_t *game) { sfVector2f pos = {0}; - if (!sfKeyboard_isKeyPressed(sfKeyLControl) + if (!is_key_held(game, sfKeyLControl) || game->window->event.type != sfEvtMouseWheelScrolled) return; pos = sfView_getSize(game->window->view); diff --git a/src/utils/mobs/manage_mobs.c b/src/utils/mobs/manage_mobs.c index b07cbd0..1acb9d5 100644 --- a/src/utils/mobs/manage_mobs.c +++ b/src/utils/mobs/manage_mobs.c @@ -6,6 +6,7 @@ */ #include +#include "input.h" #include "game.h" #include "mobs_functions.h" @@ -55,7 +56,7 @@ static void reward_kill(game_t *game, mobs_t *mob) static void win_perso(game_t *game, mobs_t *mob) { - if (sfKeyboard_isKeyPressed(game->keys->attack) + if (is_key_held(game, game->keys->attack) && mob->distance_to_player < 50) { if (mob->combat->life > 0) { mob->combat->life -= 10; diff --git a/src/utils/raycasting/move.c b/src/utils/raycasting/move.c index 638035a..bba41f9 100644 --- a/src/utils/raycasting/move.c +++ b/src/utils/raycasting/move.c @@ -6,6 +6,7 @@ */ #include +#include "input.h" #include "game.h" #include "raycasting_functions.h" @@ -35,12 +36,12 @@ static void player_move_left_right(game_t *game) raycasting_player_t *p = game->raycasting->player; sfVector2f d = get_dir(game); - if (sfKeyboard_isKeyPressed(sfKeyQ) + if (is_key_held(game, sfKeyQ) && is_colliding(game, p->position.x - d.y, p->position.y - d.x) == 0) { p->position.x -= d.y; p->position.y -= d.x; } - if (sfKeyboard_isKeyPressed(sfKeyD) + if (is_key_held(game, sfKeyD) && is_colliding(game, p->position.x + d.y, p->position.y + d.x) == 0) { p->position.x += d.y; p->position.y += d.x; @@ -52,12 +53,12 @@ static void player_move_forward_backward(game_t *game) raycasting_player_t *p = game->raycasting->player; sfVector2f d = get_dir(game); - if (sfKeyboard_isKeyPressed(sfKeyZ) + if (is_key_held(game, sfKeyZ) && is_colliding(game, p->position.x + d.x, p->position.y - d.y) == 0) { p->position.x += d.x; p->position.y -= d.y; } - if (sfKeyboard_isKeyPressed(sfKeyS) + if (is_key_held(game, sfKeyS) && is_colliding(game, p->position.x - d.x, p->position.y + d.y) == 0) { p->position.x -= d.x; p->position.y += d.y; @@ -68,13 +69,13 @@ static void player_rotate(game_t *game) { raycasting_t *r = game->raycasting; - if (sfKeyboard_isKeyPressed(sfKeyLeft)) + if (is_key_held(game, sfKeyLeft)) r->player->direction += r->sensitivity; - if (sfKeyboard_isKeyPressed(sfKeyRight)) + if (is_key_held(game, sfKeyRight)) r->player->direction -= r->sensitivity; - if (sfKeyboard_isKeyPressed(sfKeyUp)) + if (is_key_held(game, sfKeyUp)) r->player->pitch += r->sensitivity * 5; - if (sfKeyboard_isKeyPressed(sfKeyDown)) + if (is_key_held(game, sfKeyDown)) r->player->pitch -= r->sensitivity * 5; } @@ -83,7 +84,7 @@ void move_raycasting_player(game_t *game) player_rotate(game); player_move_forward_backward(game); player_move_left_right(game); - if (sfKeyboard_isKeyPressed(sfKeyE)) { + if (is_key_held(game, sfKeyE)) { game->is_raycasting = false; game->raycasting->player->position = (sfVector2f){500, 500}; } diff --git a/src/utils/raycasting/raycasting.c b/src/utils/raycasting/raycasting.c index d7bb40c..e18cffa 100644 --- a/src/utils/raycasting/raycasting.c +++ b/src/utils/raycasting/raycasting.c @@ -9,6 +9,7 @@ #include "game.h" #include "raycasting_functions.h" +#include "input.h" static void draw_entity(game_t *game, entity_t *entity) { @@ -73,9 +74,12 @@ int raycasting(game_t *game) { int i = 0; - while (sfRenderWindow_pollEvent(game->window->window, &game->window->event)) + while (sfRenderWindow_pollEvent(game->window->window, + &game->window->event)) { + input_handle_event(game); if (game->window->event.type == sfEvtClosed) exit_start_all(game); + } sfRenderWindow_clear(game->window->window, sfBlack); move_raycasting_player(game); for (i = 0; i < game->raycasting->nb_rays; i++)