input system rework

This commit is contained in:
veclavtalica
2025-02-04 07:32:25 +03:00
parent 4efe80bb5a
commit 02b5ac4cc3
27 changed files with 293 additions and 786 deletions

View File

@ -1,7 +1,6 @@
#include "twn_input_c.h"
#include "twn_util.h"
#include "twn_util_c.h"
#include "twn_control.h"
#include "twn_engine_context_c.h"
#include "twn_input.h"
@ -11,14 +10,131 @@
#include <stdbool.h>
struct ScancodeHashItem { char *const key; SDL_Scancode value; };
static struct ScancodeHashItem *control_to_scancode;
struct MouseButtonHashItem { char *const key; uint8_t value; };
static struct MouseButtonHashItem *control_to_mouse_mask;
/* prepares translation maps for controls */
static void init_control_maps(void) {
if (control_to_scancode)
return;
/* these correspond to SDL_events.h definition, restricted to what deemed useful */
shput(control_to_scancode, "A", 4);
shput(control_to_scancode, "B", 5);
shput(control_to_scancode, "C", 6);
shput(control_to_scancode, "D", 7);
shput(control_to_scancode, "E", 8);
shput(control_to_scancode, "F", 9);
shput(control_to_scancode, "G", 10);
shput(control_to_scancode, "H", 11);
shput(control_to_scancode, "I", 12);
shput(control_to_scancode, "J", 13);
shput(control_to_scancode, "K", 14);
shput(control_to_scancode, "L", 15);
shput(control_to_scancode, "M", 16);
shput(control_to_scancode, "N", 17);
shput(control_to_scancode, "O", 18);
shput(control_to_scancode, "P", 19);
shput(control_to_scancode, "Q", 20);
shput(control_to_scancode, "R", 21);
shput(control_to_scancode, "S", 22);
shput(control_to_scancode, "T", 23);
shput(control_to_scancode, "U", 24);
shput(control_to_scancode, "V", 25);
shput(control_to_scancode, "W", 26);
shput(control_to_scancode, "X", 27);
shput(control_to_scancode, "Y", 28);
shput(control_to_scancode, "Z", 29);
shput(control_to_scancode, "1", 30);
shput(control_to_scancode, "2", 31);
shput(control_to_scancode, "3", 32);
shput(control_to_scancode, "4", 33);
shput(control_to_scancode, "5", 34);
shput(control_to_scancode, "6", 35);
shput(control_to_scancode, "7", 36);
shput(control_to_scancode, "8", 37);
shput(control_to_scancode, "9", 38);
shput(control_to_scancode, "0", 39);
shput(control_to_scancode, "RETURN", 40);
shput(control_to_scancode, "ENTER", 40); /* an alias */
shput(control_to_scancode, "ESCAPE", 41);
shput(control_to_scancode, "BACKSPACE", 42);
shput(control_to_scancode, "TAB", 43);
shput(control_to_scancode, "SPACE", 44);
shput(control_to_scancode, "MINUS", 45);
shput(control_to_scancode, "EQUALS", 46);
shput(control_to_scancode, "LEFTBRACKET", 47);
shput(control_to_scancode, "RIGHTBRACKET", 48);
shput(control_to_scancode, "BACKSLASH", 49);
shput(control_to_scancode, "NONUSHASH", 50);
shput(control_to_scancode, "SEMICOLON", 51);
shput(control_to_scancode, "APOSTROPHE", 52);
shput(control_to_scancode, "GRAVE", 53);
shput(control_to_scancode, "COMMA", 54);
shput(control_to_scancode, "PERIOD", 55);
shput(control_to_scancode, "SLASH", 56);
shput(control_to_scancode, "CAPSLOCK", 57);
shput(control_to_scancode, "F1", 58);
shput(control_to_scancode, "F2", 59);
shput(control_to_scancode, "F3", 60);
shput(control_to_scancode, "F4", 61);
shput(control_to_scancode, "F5", 62);
shput(control_to_scancode, "F6", 63);
shput(control_to_scancode, "F7", 64);
shput(control_to_scancode, "F8", 65);
shput(control_to_scancode, "F9", 66);
shput(control_to_scancode, "F10", 67);
shput(control_to_scancode, "F11", 68);
shput(control_to_scancode, "F12", 69);
shput(control_to_scancode, "PRINTSCREEN", 70);
shput(control_to_scancode, "SCROLLLOCK", 71);
shput(control_to_scancode, "PAUSE", 72);
shput(control_to_scancode, "INSERT", 73);
shput(control_to_scancode, "HOME", 74);
shput(control_to_scancode, "PAGEUP", 75);
shput(control_to_scancode, "DELETE", 76);
shput(control_to_scancode, "END", 77);
shput(control_to_scancode, "PAGEDOWN", 78);
shput(control_to_scancode, "RIGHT", 79);
shput(control_to_scancode, "LEFT", 80);
shput(control_to_scancode, "DOWN", 81);
shput(control_to_scancode, "UP", 82);
shput(control_to_scancode, "KPDIVIDE", 84);
shput(control_to_scancode, "KPMULTIPLY", 85);
shput(control_to_scancode, "KPMINUS", 86);
shput(control_to_scancode, "KPPLUS", 87);
shput(control_to_scancode, "KPENTER", 88);
shput(control_to_scancode, "KP1", 89);
shput(control_to_scancode, "KP2", 90);
shput(control_to_scancode, "KP3", 91);
shput(control_to_scancode, "KP4", 92);
shput(control_to_scancode, "KP5", 93);
shput(control_to_scancode, "KP6", 94);
shput(control_to_scancode, "KP7", 95);
shput(control_to_scancode, "KP8", 96);
shput(control_to_scancode, "KP9", 97);
shput(control_to_scancode, "KP0", 98);
shput(control_to_scancode, "LCTRL", 224);
shput(control_to_scancode, "LSHIFT", 225);
shput(control_to_scancode, "LALT", 226);
shput(control_to_scancode, "RCTRL", 228);
shput(control_to_scancode, "RSHIFT", 229);
/* TODO: support for double clicks */
shput(control_to_mouse_mask, "LCLICK", SDL_BUTTON(SDL_BUTTON_LEFT));
shput(control_to_mouse_mask, "MCLICK", SDL_BUTTON(SDL_BUTTON_MIDDLE));
shput(control_to_mouse_mask, "RCLICK", SDL_BUTTON(SDL_BUTTON_RIGHT));
}
static void update_action_pressed_state(InputState *input, Action *action) {
for (size_t i = 0; i < (uint64_t)ctx.keybind_slots; ++i) {
switch (action->bindings[i].source) {
case BUTTON_SOURCE_NOT_SET:
break;
case BUTTON_SOURCE_KEYBOARD_CHARACTER:
CRY("Action pressed state updated failed", "BUTTON_SOURCE_KEYBOARD_CHARACTER isn't handled");
break;
case BUTTON_SOURCE_GAMEPAD:
CRY("Action pressed state updated failed", "BUTTON_SOURCE_GAMEPAD isn't handled");
break;
@ -116,9 +232,6 @@ static void input_bind_code_to_action(InputState *input,
case BUTTON_SOURCE_KEYBOARD_PHYSICAL:
is_already_bound = binding->code.scancode == code.scancode;
break;
case BUTTON_SOURCE_KEYBOARD_CHARACTER:
is_already_bound = binding->code.keycode == code.keycode;
break;
case BUTTON_SOURCE_GAMEPAD:
is_already_bound = binding->code.gamepad_button == code.gamepad_button;
break;
@ -177,9 +290,6 @@ static void input_unbind_code_from_action(InputState *input,
case BUTTON_SOURCE_KEYBOARD_PHYSICAL:
is_bound = binding->code.scancode == code.scancode;
break;
case BUTTON_SOURCE_KEYBOARD_CHARACTER:
is_bound = binding->code.keycode == code.keycode;
break;
case BUTTON_SOURCE_GAMEPAD:
is_bound = binding->code.gamepad_button == code.gamepad_button;
break;
@ -208,10 +318,13 @@ static void input_unbind_code_from_action(InputState *input,
void input_state_init(InputState *input) {
sh_new_strdup(input->action_hash);
init_control_maps();
}
void input_state_deinit(InputState *input) {
shfree(control_to_mouse_mask);
shfree(control_to_scancode);
input_reset_state(input);
}
@ -264,25 +377,73 @@ void input_state_update(InputState *input) {
}
static Button *infer_control_desc(char const *control) {
Button *result = NULL;
char *copy = SDL_strdup(control);
char *saveptr = NULL;
char const *part = SDL_strtokr(copy, "+", &saveptr);
do {
struct ScancodeHashItem const *scancode = shgetp_null(control_to_scancode, part);
if (scancode) {
Button const button = {
.source = BUTTON_SOURCE_KEYBOARD_PHYSICAL,
.code.scancode = scancode->value,
};
arrpush(result, button);
continue;
}
struct MouseButtonHashItem const *mouse_button = shgetp_null(control_to_mouse_mask, part);
if (mouse_button) {
Button const button = {
.source = BUTTON_SOURCE_MOUSE,
.code.mouse_button = mouse_button->value,
};
arrpush(result, button);
continue;
}
log_warn("Unknown control part given (%s)", part);
} while ((part = SDL_strtokr(NULL, "+", &saveptr)));
SDL_free(copy);
return result;
}
void input_action(char const *action_name,
Control control)
char const *control)
{
SDL_assert_always(action_name);
if (CONTROL_SCANCODE_START <= control && control < CONTROL_SCANCODE_LIMIT)
Button *combo = infer_control_desc(control);
if (!combo) {
log_warn("Invalid control (%s) for action bind", control);
return;
}
/* TODO: */
if (arrlenu(combo) > 1) {
log_warn("TODO: Control combinations are not yet supported.");
return;
}
if (combo[0].source == BUTTON_SOURCE_KEYBOARD_PHYSICAL)
input_bind_code_to_action(&ctx.input,
action_name,
BUTTON_SOURCE_KEYBOARD_PHYSICAL,
(union ButtonCode) { .scancode = (SDL_Scancode)control });
(union ButtonCode) { .scancode = combo[0].code.scancode });
else if (CONTROL_MOUSECODE_START <= control && control < CONTROL_MOUSECODE_LIMIT) {
uint8_t const mouse_button = (uint8_t)(control - CONTROL_MOUSECODE_START);
else if (combo[0].source == BUTTON_SOURCE_MOUSE)
input_bind_code_to_action(&ctx.input,
action_name,
BUTTON_SOURCE_MOUSE,
(union ButtonCode) { .mouse_button = (uint8_t)SDL_BUTTON(mouse_button)});
} else
log_warn("(%s) Invalid control value given: %i.", __func__, control);
(union ButtonCode) { .mouse_button = combo[0].code.mouse_button });
else
log_warn("(%s) Unsupported control source value given: %i.", __func__, control);
arrfree(combo);
}

View File

@ -13,7 +13,6 @@
union ButtonCode {
SDL_Scancode scancode;
SDL_Keycode keycode;
SDL_GameControllerButton gamepad_button;
uint8_t mouse_button; /* SDL_BUTTON_ enum */
};
@ -22,7 +21,6 @@ union ButtonCode {
typedef enum ButtonSource {
BUTTON_SOURCE_NOT_SET,
BUTTON_SOURCE_KEYBOARD_PHYSICAL,
BUTTON_SOURCE_KEYBOARD_CHARACTER,
BUTTON_SOURCE_GAMEPAD,
BUTTON_SOURCE_MOUSE,
} ButtonSource;
@ -70,6 +68,14 @@ typedef struct InputState {
} InputState;
typedef struct ControlDesc {
union {
SDL_Scancode scancode;
uint8_t mouse_button;
};
} ControlDesc;
void input_state_init(InputState *input);
void input_state_deinit(InputState *input);