input: Added basic input mapping system from platform backend to engine
authorLukas Krickl <lukas@krickl.dev>
Sun, 1 Mar 2026 15:04:29 +0000 (16:04 +0100)
committerLukas Krickl <lukas@krickl.dev>
Sun, 1 Mar 2026 15:04:29 +0000 (16:04 +0100)
This allows a generic action struct to keep the user input state.
The platform is currently in charge of setting the button states based
on scan codes and modifier keys.
A history of previous states is kept to allow detection of keys being
just pressed or held.
Added mouse cursor postion.

src/i_input.c
src/i_input.h
src/lrts.c
src/p_platform.h
src/p_r_sdl/p_window.c

index 24d0ecd8ba55658b496e7eed1e938fe7589fa50e..903d97be1f791700b6dac4e72159fa0a13a71880 100644 (file)
@@ -1,7 +1,91 @@
 #include "i_input.h"
 
-struct i_cursor i_cursor;
-struct i_keyboard i_keyboard;
+/* TODO: change api so that this calls the platform backend
+ * with specific actions that are expected */
+
+struct i_input_map i_input_map;
 
 void i_input_init(void) {
+       p_input_set_default_map();
+
+
+       /* TODO read key map from config file */
+}
+
+struct i_input_map_ent* i_input_find_ent(u16 scan_code, lrts_bool mod_shift, 
+               lrts_bool mod_alt, lrts_bool mod_ctrl, lrts_bool mod_super) {
+       u32 i = 0;
+       struct i_input_map_ent *ent = LRTS_NULL;
+       for (i = 0; i < I_INPUT_ACTION_LEN; i++) {
+               ent = &i_input_map.inputs[i];
+
+               if (ent->scan_code == scan_code 
+                               && ent->mod_shift == mod_shift
+                               && ent->mod_alt == mod_alt
+                               && ent->mod_ctrl == mod_ctrl
+                               && ent->mod_super == mod_super) {
+                       return ent;
+               }
+       }
+
+       return LRTS_NULL;
+}
+
+void i_input_set(u16 scan_code, lrts_bool mod_shift, lrts_bool mod_alt, lrts_bool mod_ctrl, lrts_bool mod_super) {
+       struct i_input_map_ent *ent = i_input_find_ent(scan_code, mod_shift, mod_alt, mod_ctrl, mod_super);
+       if (ent == LRTS_NULL) {
+               return;
+       }
+       ent->held = 1;
+}
+
+void i_input_unset(u16 scan_code, lrts_bool mod_shift, lrts_bool mod_alt, lrts_bool mod_ctrl, lrts_bool mod_super) {
+       struct i_input_map_ent *ent = i_input_find_ent(scan_code, mod_shift, mod_alt, mod_ctrl, mod_super);
+       if (ent == LRTS_NULL) {
+               return;
+       }
+       ent->held = 0;
+}
+
+void i_input_update(void) {
+       u32 i = 0;
+       /* move all pressed events over one position */ 
+       for (i = 0; i < I_INPUT_ACTION_LEN; i++) {
+               i_input_map.inputs[i].pressed <<= 1;
+               i_input_map.inputs[i].pressed |= i_input_map.inputs[i].held;
+       }
+}
+
+void i_input_cursor_set(i32 x, i32 y) {
+       i_input_map.cursor_x = x;
+       i_input_map.cursor_y = y;
+}
+
+void i_input_cursor_click_set(void) {
+       i_input_map.inputs[I_INPUT_ACTION_CURSOR_CLICK].held = 1;
+}
+
+void i_input_cursor_drag_set(void) {
+       i_input_map.inputs[I_INPUT_ACTION_CURSOR_DRAG].held = 1;
+}
+
+void i_input_cursor_action_set(void) {
+       i_input_map.inputs[I_INPUT_ACTION_CURSOR_ACTION].held = 1;
+}
+
+void i_input_cursor_click_unset(void) {
+       i_input_map.inputs[I_INPUT_ACTION_CURSOR_CLICK].held = 0;
+}
+
+void i_input_cursor_drag_unset(void) {
+       i_input_map.inputs[I_INPUT_ACTION_CURSOR_DRAG].held = 0;
+}
+
+void i_input_cursor_action_unset(void) {
+       i_input_map.inputs[I_INPUT_ACTION_CURSOR_ACTION].held = 0;
+}
+
+void i_input_poll(void) {
+       p_poll_events();
+       i_input_update();
 }
index 9c166acfcbac0fe74a093f7a56ce04cfa4fff0f4..b9a120480e1aad43afdb4d4f1c71dfa796af7392 100644 (file)
@@ -9,67 +9,92 @@
  * be translated to action commands. 
  */
 
-#define I_CURSOR_BUTTONS 3
-#define I_KEYBOARD_KEYS 128
-
-enum i_button_state {
-       I_BUTTON_RELEASE = 0,
-       I_BUTTON_JUST_PRESSED = 1,
-       I_BUTTON_HELD = 2
+/* describes all possible input actions */
+enum i_input_actions {
+       I_INPUT_ACTION_CAMERA_UP,
+       I_INPUT_ACTION_CAMERA_DOWN,
+       I_INPUT_ACTION_CAMERA_LEFT,
+       I_INPUT_ACTION_CAMERA_RIGHT,
+       
+       /* left click on target */
+       I_INPUT_ACTION_CURSOR_CLICK,
+       /* primary action when right clicking */
+       I_INPUT_ACTION_CURSOR_ACTION,
+       
+       /* middle mouse drag */
+       I_INPUT_ACTION_CURSOR_DRAG,
+       
+       /* not a real entry just the length of the action list */
+       I_INPUT_ACTION_LEN
 };
 
-
-/* describes the current cursor state */
-struct i_cursor {
-       struct u_vec2 pos;
-
-       enum i_button_state buttons[I_CURSOR_BUTTONS];
+/* input entry */
+struct i_input_map_ent {
+       /* this is a platform specific button
+        * code to this input action
+        */
+       u16 scan_code;
+
+       /* possible modifiers for the input map entry */
+       lrts_bool mod_shift;
+       lrts_bool mod_alt;
+       lrts_bool mod_ctrl;
+       lrts_bool mod_super;
+       
+       /* bit field for pressed state
+        * every frame this is shifted over by 1 bit
+        * the most recent state is in the rightmost bit
+        */
+       u16 pressed;
+       u16 held;
 };
 
-enum i_arrow_keys {
-       I_ARROW_UP = 0,
-       I_ARROW_DOWN,
-       I_ARROW_LEFT,
-       I_ARROW_RIGHT,
-       I_ARROW_LEN
+/* map of all input actions to scanscodes */
+struct i_input_map {
+       struct i_input_map_ent inputs[I_INPUT_ACTION_LEN];
+       
+       /* screen position of cursor */
+       i32 cursor_x;
+       i32 cursor_y;
 };
 
-#define I_FKEYS_LEN 12
+extern struct i_input_map i_input_map;
 
-struct i_keyboard {
-       enum i_button_state esc;
-       enum i_button_state shift;
-       enum i_button_state ctrl;
-       enum i_button_state alt;
-       enum i_button_state super;
-       enum i_button_state enter;
-       enum i_button_state space;
-       enum i_button_state backspace;
 
-       enum i_button_state arrow[I_ARROW_LEN];
+void i_input_init(void);
 
-       enum i_button_state del;
-       enum i_button_state home;
-       enum i_button_state end;
-       enum i_button_state pgup;
-       enum i_button_state pgdown;
-       enum i_button_state insert;
+/* sets an input to held
+ * the scancode and modifiers have to match
+ * if no event map is present the event is dropped
+ * This should be called by the platforms event polling function 
+ * to pass events as inputs to the engine
+ * should be called by p_poll_events
+ */
+void i_input_set(u16 scan_code, lrts_bool mod_shift, lrts_bool mod_alt, lrts_bool mod_ctrl, lrts_bool mod_super);
 
-       enum i_button_state tab;
+/* unsets held state
+ */
+void i_input_unset(u16 scan_code, lrts_bool mod_shift, lrts_bool mod_alt, lrts_bool mod_ctrl, lrts_bool mod_super);
 
-       enum i_button_state print;
-       enum i_button_state pause;
+/* updates input history by shifting pressed bitfield over by 1 and oring it with the held state */
+void i_input_update(void);
 
-       enum i_button_state fkey[I_FKEYS_LEN];
+/* sets cursor positon 
+ * should be called by p_poll_events
+ */
+void i_input_cursor_set(i32 x, i32 y);
 
-       /* ascii table for all other keys */
-       enum i_button_state keys[I_KEYBOARD_KEYS];
-};
+void i_input_cursor_click_set(void);
+void i_input_cursor_drag_set(void);
+void i_input_cursor_action_set(void);
 
-/* primary IO devices */
-extern struct i_cursor i_cursor;
-extern struct i_keyboard i_keyboard;
+void i_input_cursor_click_unset(void);
+void i_input_cursor_drag_unset(void);
+void i_input_cursor_action_unset(void);
 
-void i_input_init(void);
+/* polls input from system backend 
+ * and translates the input to commands 
+ */
+void i_input_poll(void);
 
 #endif
index aebc6e3740ce0e3c1159738c5afe94bd88f5b22e..9a7f5ec5b90e3be409af1e0a2657d2e2e2c0a2a4 100644 (file)
@@ -106,7 +106,7 @@ int lrts_main(int argc, char **argv) {
        p_render_init_framebuffer();
 
        while (!lrts_cfg()->exit) {
-               p_poll_events();
+               i_input_poll();
                t_sim_update();
                r_render_frame();
        }
index dd50baade74bcefe9c651200e2bbd0ba9b3e0133..2817e0f846b010aded82fe2d48bde88112aba92d 100644 (file)
@@ -62,7 +62,17 @@ void p_delay(u64 time);
 /**
  * polls input events 
  * should be called once a frame
+ *
+ * should call: 
+ * i_input_cursor_set
+ * i_input_set
  */
 int p_poll_events();
 
+/**
+ * Allow the platform to set up a default
+ * keymap
+ */ 
+void p_input_set_default_map();
+
 #endif
index 249e54ad20c692c6c4f7b08649098498e93b577d..ecc1d2bcf072f780e6c254eede93d898275f261c 100644 (file)
@@ -1,15 +1,66 @@
 SDL_Window *p_main_window;
 
 #include "../u_defs.h"
+#include "../i_input.h"
 
 SDL_Surface *r_target;
 
+void p_input_set_default_map() {
+       i_input_map.inputs[I_INPUT_ACTION_CAMERA_UP].scan_code = SDL_SCANCODE_UP;
+       i_input_map.inputs[I_INPUT_ACTION_CAMERA_DOWN].scan_code = SDL_SCANCODE_DOWN;
+       i_input_map.inputs[I_INPUT_ACTION_CAMERA_LEFT].scan_code = SDL_SCANCODE_LEFT;
+       i_input_map.inputs[I_INPUT_ACTION_CAMERA_RIGHT].scan_code = SDL_SCANCODE_RIGHT;
+}
+
 int p_poll_events() {
        SDL_Event e;
+       float x, y;
+
        while (SDL_PollEvent(&e)) {
-               if (e.type == SDL_EVENT_QUIT) {
-                       lrts_cfg()->exit = LRTS_TRUE;
+               switch (e.type) {
+                       case SDL_EVENT_QUIT:
+                               lrts_cfg()->exit = LRTS_TRUE;
+                               break;
+                       case SDL_EVENT_KEY_DOWN:
+                               i_input_set(e.key.scancode, 
+                                               (e.key.mod & (SDL_KMOD_LSHIFT | SDL_KMOD_RSHIFT)) != 0,
+                                               (e.key.mod & (SDL_KMOD_LALT | SDL_KMOD_RALT)) != 0,
+                                               (e.key.mod & (SDL_KMOD_LCTRL | SDL_KMOD_RCTRL)) != 0,
+                                               (e.key.mod & (SDL_KMOD_LGUI | SDL_KMOD_RGUI)) != 0
+                               );
+                               break;
+                       case SDL_EVENT_KEY_UP:
+                               i_input_unset(e.key.scancode, 
+                                               (e.key.mod & (SDL_KMOD_LSHIFT | SDL_KMOD_RSHIFT)) != 0,
+                                               (e.key.mod & (SDL_KMOD_LALT | SDL_KMOD_RALT)) != 0,
+                                               (e.key.mod & (SDL_KMOD_LCTRL | SDL_KMOD_RCTRL)) != 0,
+                                               (e.key.mod & (SDL_KMOD_LGUI | SDL_KMOD_RGUI)) != 0
+                               );
+                               break;
+                       case SDL_EVENT_MOUSE_BUTTON_DOWN:
+                               if (e.button.button == SDL_BUTTON_LEFT) {
+                                       i_input_cursor_click_set();
+                               } else if (e.button.button == SDL_BUTTON_MIDDLE) {
+                                       i_input_cursor_drag_set();
+                               } else if (e.button.button == SDL_BUTTON_RIGHT) {
+                                       i_input_cursor_action_set();
+                               }
+                               break;
+                       case SDL_EVENT_MOUSE_BUTTON_UP:
+                               if (e.button.button == SDL_BUTTON_LEFT) {
+                                       i_input_cursor_click_unset();
+                               } else if (e.button.button == SDL_BUTTON_MIDDLE) {
+                                       i_input_cursor_drag_unset();
+                               } else if (e.button.button == SDL_BUTTON_RIGHT) {
+                                       i_input_cursor_action_unset();
+                               }
+                               break;
                }
+
        }
+       
+       SDL_GetMouseState(&x, &y);
+       i_input_cursor_set(x, y);
+
        return 0;
 }