diff --git a/apps/demos/bunnymark/game.c b/apps/demos/bunnymark/game.c index 7404f84..629fd18 100644 --- a/apps/demos/bunnymark/game.c +++ b/apps/demos/bunnymark/game.c @@ -16,14 +16,17 @@ void handle_input(void) { State *state = ctx.udata; - if (ctx.input.mouse_state == 1 && ctx.input.mouse_window_position.y > 60) + + if (ctx.mouse_window_position.y <= 60) + return; + + if (input_is_action_pressed("add_a_bit")) { // Left click for (int i = 0; i < LEFT_CLICK_ADD; i++) { if (state->bunniesCount < MAX_BUNNIES) { - state->bunnies[state->bunniesCount].position = - (Vec2){(float)ctx.input.mouse_window_position.x, (float)ctx.input.mouse_window_position.y}; + state->bunnies[state->bunniesCount].position = input_get_action_position("add_a_bit"); state->bunnies[state->bunniesCount].speed.x = (float)(rand() % 500 - 250) / 60.0; state->bunnies[state->bunniesCount].speed.y = (float)(rand() % 500 - 250) / 60.0; state->bunnies[state->bunniesCount].color = @@ -33,14 +36,13 @@ void handle_input(void) } } - if (ctx.input.mouse_state == 4) + if (input_is_action_pressed("add_a_lot")) { // Right click for (int i = 0; i < RIGHT_CLICK_ADD; i++) { if (state->bunniesCount < MAX_BUNNIES) { - state->bunnies[state->bunniesCount].position = - (Vec2){(float)ctx.input.mouse_window_position.x, (float)ctx.input.mouse_window_position.y}; + state->bunnies[state->bunniesCount].position = input_get_action_position("add_a_lot"); state->bunnies[state->bunniesCount].speed.x = (float)(rand() % 500 - 250) / 60.0; state->bunnies[state->bunniesCount].speed.y = (float)(rand() % 500 - 250) / 60.0; state->bunnies[state->bunniesCount].color = @@ -53,8 +55,7 @@ void handle_input(void) void game_tick(void) { - static char bunny_count_text[64]; - static char bunny_path[64] = "wabbit_alpha.png"; + char bunny_count_text[64]; // State *state = ctx.udata; if (ctx.initialization_needed) @@ -62,7 +63,12 @@ void game_tick(void) // Allocating State struct to store data there if (!ctx.udata) ctx.udata = ccalloc(1, sizeof(State)); - ((State *)ctx.udata)->bunniesCount = 0; + + input_add_action("add_a_bit"); + input_bind_action_control("add_a_bit", CONTROL_LEFT_MOUSE); + + input_add_action("add_a_lot"); + input_bind_action_control("add_a_lot", CONTROL_RIGHT_MOUSE); } State *state = ctx.udata; @@ -90,16 +96,16 @@ void game_tick(void) for (int i = 0; i < state->bunniesCount; i++) { // Draw each bunny based on their position and color, also scale accordingly - m_sprite(m_set(path, bunny_path), + m_sprite(m_set(path, "wabbit_alpha.png"), m_set(rect, ((Rect){.x = (int)state->bunnies[i].position.x, .y = (int)state->bunnies[i].position.y, .w = BUNNY_W * SPRITE_SCALE, .h = BUNNY_H * SPRITE_SCALE})), m_opt(color, (state->bunnies[i].color)), m_opt(stretch, true), ); } + // Formatting text to display, might want to add FPS here too snprintf(bunny_count_text, 64, "Bunnies: %d", state->bunniesCount); - draw_text(bunny_count_text, (Vec2){0, 0}, 40, BLACK, "/fonts/kenney-pixel.ttf"); } diff --git a/apps/demos/bunnymark/state.h b/apps/demos/bunnymark/state.h index 85b2d8f..436bbb2 100644 --- a/apps/demos/bunnymark/state.h +++ b/apps/demos/bunnymark/state.h @@ -19,7 +19,6 @@ typedef struct State { Bunny bunnies[MAX_BUNNIES]; int bunniesCount; - InputState mouse_state; } State; #endif diff --git a/apps/platformer/game.c b/apps/platformer/game.c index e756ee1..027e092 100644 --- a/apps/platformer/game.c +++ b/apps/platformer/game.c @@ -19,44 +19,44 @@ void game_tick(void) { state->scene = title_scene(state); } - input_add_action(&ctx.input, "debug_toggle"); - input_bind_action_scancode(&ctx.input, "debug_toggle", SCANCODE_BACKSPACE); + input_add_action("debug_toggle"); + input_bind_action_control("debug_toggle", CONTROL_BACKSPACE); - input_add_action(&ctx.input, "debug_dump_atlases"); - input_bind_action_scancode(&ctx.input, "debug_dump_atlases", SCANCODE_HOME); + input_add_action("debug_dump_atlases"); + input_bind_action_control("debug_dump_atlases", CONTROL_HOME); - input_add_action(&ctx.input, "player_left"); - input_bind_action_scancode(&ctx.input, "player_left", SCANCODE_A); + input_add_action("player_left"); + input_bind_action_control("player_left", CONTROL_A); - input_add_action(&ctx.input, "player_right"); - input_bind_action_scancode(&ctx.input, "player_right", SCANCODE_D); + input_add_action("player_right"); + input_bind_action_control("player_right", CONTROL_D); - input_add_action(&ctx.input, "player_forward"); - input_bind_action_scancode(&ctx.input, "player_forward", SCANCODE_W); + input_add_action("player_forward"); + input_bind_action_control("player_forward", CONTROL_W); - input_add_action(&ctx.input, "player_backward"); - input_bind_action_scancode(&ctx.input, "player_backward", SCANCODE_S); + input_add_action("player_backward"); + input_bind_action_control("player_backward", CONTROL_S); - input_add_action(&ctx.input, "player_jump"); - input_bind_action_scancode(&ctx.input, "player_jump", SCANCODE_SPACE); + input_add_action("player_jump"); + input_bind_action_control("player_jump", CONTROL_SPACE); - input_add_action(&ctx.input, "player_run"); - input_bind_action_scancode(&ctx.input, "player_run", SCANCODE_LSHIFT); + input_add_action("player_run"); + input_bind_action_control("player_run", CONTROL_LSHIFT); - input_add_action(&ctx.input, "ui_accept"); - input_bind_action_scancode(&ctx.input, "ui_accept", SCANCODE_RETURN); + input_add_action("ui_accept"); + input_bind_action_control("ui_accept", CONTROL_RETURN); - input_add_action(&ctx.input, "mouse_capture_toggle"); - input_bind_action_scancode(&ctx.input, "mouse_capture_toggle", SCANCODE_ESCAPE); + input_add_action("mouse_capture_toggle"); + input_bind_action_control("mouse_capture_toggle", CONTROL_ESCAPE); } State *state = ctx.udata; - if (input_is_action_just_pressed(&ctx.input, "debug_toggle")) { + if (input_is_action_just_pressed("debug_toggle")) { ctx.debug = !ctx.debug; } - if (input_is_action_just_pressed(&ctx.input, "debug_dump_atlases")) { + if (input_is_action_just_pressed("debug_dump_atlases")) { textures_dump_atlases(); } diff --git a/apps/platformer/player.c b/apps/platformer/player.c index 80e1712..bb62eb4 100644 --- a/apps/platformer/player.c +++ b/apps/platformer/player.c @@ -17,22 +17,22 @@ static void update_timers(Player *player) { } -static void input_move(InputState *input, Player *player) { +static void input_move(Player *player) { /* apply horizontal damping when the player stops moving */ /* in other words, make it decelerate to a standstill */ - if (!input_is_action_pressed(input, "player_left") && - !input_is_action_pressed(input, "player_right")) + if (!input_is_action_pressed("player_left") && + !input_is_action_pressed("player_right")) { player->dx *= player->horizontal_damping; } int input_dir = 0; - if (input_is_action_pressed(input, "player_left")) + if (input_is_action_pressed("player_left")) input_dir = -1; - if (input_is_action_pressed(input, "player_right")) + if (input_is_action_pressed("player_right")) input_dir = 1; - if (input_is_action_pressed(input, "player_left") && - input_is_action_pressed(input, "player_right")) + if (input_is_action_pressed("player_left") && + input_is_action_pressed("player_right")) input_dir = 0; player->dx += (float)input_dir * player->run_horizontal_speed; @@ -53,10 +53,10 @@ static void jump(Player *player) { } -static void input_jump(InputState *input, Player *player) { +static void input_jump(Player *player) { player->current_gravity_multiplier = player->jump_default_multiplier; - if (input_is_action_just_pressed(input, "player_jump")) { + if (input_is_action_just_pressed("player_jump")) { player->jump_air_timer = 0; player->jump_buffer_timer = player->jump_buffer_ticks; @@ -65,7 +65,7 @@ static void input_jump(InputState *input, Player *player) { } } - if (input_is_action_pressed(input, "player_jump")) { + if (input_is_action_pressed("player_jump")) { if (player->action != PLAYER_ACTION_GROUND && player->jump_air_timer > 0) { player->current_gravity_multiplier = player->jump_boosted_multiplier; player->dy += player->jump_force_increase; @@ -284,8 +284,8 @@ void player_destroy(Player *player) { void player_calc(Player *player) { update_timers(player); - input_move(&ctx.input, player); - input_jump(&ctx.input, player); + input_move(player); + input_jump(player); player->rect.x += player->dx; update_collider_x(player); diff --git a/apps/platformer/scenes/ingame.c b/apps/platformer/scenes/ingame.c index 63408a5..de4eb8a 100644 --- a/apps/platformer/scenes/ingame.c +++ b/apps/platformer/scenes/ingame.c @@ -16,22 +16,22 @@ static void ingame_tick(State *state) { const Vec3 right = m_vec_norm(m_vec_cross(scn->cam.target, scn->cam.up)); const float speed = 0.04f; /* TODO: put this in a better place */ - if (input_is_action_pressed(&ctx.input, "player_left")) + if (input_is_action_pressed("player_left")) scn->cam.pos = vec3_sub(scn->cam.pos, m_vec_scale(right, speed)); - if (input_is_action_pressed(&ctx.input, "player_right")) + if (input_is_action_pressed("player_right")) scn->cam.pos = vec3_add(scn->cam.pos, m_vec_scale(right, speed)); - if (input_is_action_pressed(&ctx.input, "player_forward")) + if (input_is_action_pressed("player_forward")) scn->cam.pos = vec3_add(scn->cam.pos, m_vec_scale(scn->cam.target, speed)); - if (input_is_action_pressed(&ctx.input, "player_backward")) + if (input_is_action_pressed("player_backward")) scn->cam.pos = vec3_sub(scn->cam.pos, m_vec_scale(scn->cam.target, speed)); - if (input_is_action_pressed(&ctx.input, "player_jump")) + if (input_is_action_pressed("player_jump")) scn->cam.pos.y += speed; - if (input_is_action_pressed(&ctx.input, "player_run")) + if (input_is_action_pressed("player_run")) scn->cam.pos.y -= speed; } diff --git a/apps/platformer/scenes/title.c b/apps/platformer/scenes/title.c index 92b3689..1790d17 100644 --- a/apps/platformer/scenes/title.c +++ b/apps/platformer/scenes/title.c @@ -14,7 +14,7 @@ static void title_tick(State *state) { SceneTitle *scn = (SceneTitle *)state->scene; (void)scn; - if (input_is_action_just_pressed(&state->ctx->input, "ui_accept")) { + if (input_is_action_just_pressed("ui_accept")) { switch_to(state, ingame_scene); return; } diff --git a/apps/scenery/game.c b/apps/scenery/game.c index cdfcc6c..df95747 100644 --- a/apps/scenery/game.c +++ b/apps/scenery/game.c @@ -20,44 +20,44 @@ void game_tick(void) { state->scene = title_scene(state); } - input_add_action(&ctx.input, "debug_toggle"); - input_bind_action_scancode(&ctx.input, "debug_toggle", SCANCODE_BACKSPACE); + input_add_action("debug_toggle"); + input_bind_action_control("debug_toggle", CONTROL_BACKSPACE); - input_add_action(&ctx.input, "debug_dump_atlases"); - input_bind_action_scancode(&ctx.input, "debug_dump_atlases", SCANCODE_HOME); + input_add_action("debug_dump_atlases"); + input_bind_action_control("debug_dump_atlases", CONTROL_HOME); - input_add_action(&ctx.input, "player_left"); - input_bind_action_scancode(&ctx.input, "player_left", SCANCODE_A); + input_add_action("player_left"); + input_bind_action_control("player_left", CONTROL_A); - input_add_action(&ctx.input, "player_right"); - input_bind_action_scancode(&ctx.input, "player_right", SCANCODE_D); + input_add_action("player_right"); + input_bind_action_control("player_right", CONTROL_D); - input_add_action(&ctx.input, "player_forward"); - input_bind_action_scancode(&ctx.input, "player_forward", SCANCODE_W); + input_add_action("player_forward"); + input_bind_action_control("player_forward", CONTROL_W); - input_add_action(&ctx.input, "player_backward"); - input_bind_action_scancode(&ctx.input, "player_backward", SCANCODE_S); + input_add_action("player_backward"); + input_bind_action_control("player_backward", CONTROL_S); - input_add_action(&ctx.input, "player_jump"); - input_bind_action_scancode(&ctx.input, "player_jump", SCANCODE_SPACE); + input_add_action("player_jump"); + input_bind_action_control("player_jump", CONTROL_SPACE); - input_add_action(&ctx.input, "player_run"); - input_bind_action_scancode(&ctx.input, "player_run", SCANCODE_LSHIFT); + input_add_action("player_run"); + input_bind_action_control("player_run", CONTROL_LSHIFT); - input_add_action(&ctx.input, "ui_accept"); - input_bind_action_scancode(&ctx.input, "ui_accept", SCANCODE_RETURN); + input_add_action("ui_accept"); + input_bind_action_control("ui_accept", CONTROL_RETURN); - input_add_action(&ctx.input, "mouse_capture_toggle"); - input_bind_action_scancode(&ctx.input, "mouse_capture_toggle", SCANCODE_ESCAPE); + input_add_action("mouse_capture_toggle"); + input_bind_action_control("mouse_capture_toggle", CONTROL_ESCAPE); } State *state = ctx.udata; - if (input_is_action_just_pressed(&ctx.input, "debug_toggle")) { + if (input_is_action_just_pressed("debug_toggle")) { ctx.debug = !ctx.debug; } - if (input_is_action_just_pressed(&ctx.input, "debug_dump_atlases")) { + if (input_is_action_just_pressed("debug_dump_atlases")) { textures_dump_atlases(); } diff --git a/apps/scenery/scenes/ingame.c b/apps/scenery/scenes/ingame.c index ece900c..1393083 100644 --- a/apps/scenery/scenes/ingame.c +++ b/apps/scenery/scenes/ingame.c @@ -15,10 +15,10 @@ static void ingame_tick(State *state) { SceneIngame *scn = (SceneIngame *)state->scene; - if (input_is_mouse_captured(&ctx.input)) { + if (input_is_mouse_captured()) { const float sensitivity = 0.6f; /* TODO: put this in a better place */ - scn->yaw += (float)ctx.input.mouse_relative_position.x * sensitivity; - scn->pitch -= (float)ctx.input.mouse_relative_position.y * sensitivity; + scn->yaw += (float)ctx.mouse_relative_position.x * sensitivity; + scn->pitch -= (float)ctx.mouse_relative_position.y * sensitivity; scn->pitch = clampf(scn->pitch, -89.0f, 89.0f); const float yaw_rad = scn->yaw * (float)DEG2RAD; @@ -33,27 +33,27 @@ static void ingame_tick(State *state) { const Vec3 right = m_vec_norm(m_vec_cross(scn->cam.target, scn->cam.up)); const float speed = 0.04f; /* TODO: put this in a better place */ - if (input_is_action_pressed(&ctx.input, "player_left")) + if (input_is_action_pressed("player_left")) scn->cam.pos = vec3_sub(scn->cam.pos, m_vec_scale(right, speed)); - if (input_is_action_pressed(&ctx.input, "player_right")) + if (input_is_action_pressed("player_right")) scn->cam.pos = vec3_add(scn->cam.pos, m_vec_scale(right, speed)); - if (input_is_action_pressed(&ctx.input, "player_forward")) + if (input_is_action_pressed("player_forward")) scn->cam.pos = vec3_add(scn->cam.pos, m_vec_scale(scn->cam.target, speed)); - if (input_is_action_pressed(&ctx.input, "player_backward")) + if (input_is_action_pressed("player_backward")) scn->cam.pos = vec3_sub(scn->cam.pos, m_vec_scale(scn->cam.target, speed)); - if (input_is_action_pressed(&ctx.input, "player_jump")) + if (input_is_action_pressed("player_jump")) scn->cam.pos.y += speed; - if (input_is_action_pressed(&ctx.input, "player_run")) + if (input_is_action_pressed("player_run")) scn->cam.pos.y -= speed; /* toggle mouse capture with end key */ - if (input_is_action_just_pressed(&ctx.input, "mouse_capture_toggle")) { - input_set_mouse_captured(&ctx.input, !input_is_mouse_captured(&ctx.input)); + if (input_is_action_just_pressed("mouse_capture_toggle")) { + input_set_mouse_captured(!input_is_mouse_captured()); } draw_camera(&scn->cam); @@ -111,7 +111,7 @@ Scene *ingame_scene(State *state) { m_opt(channel, "soundtrack"), m_opt(repeat, true)); - input_set_mouse_captured(&ctx.input, true); + input_set_mouse_captured(true); return (Scene *)new_scene; } diff --git a/apps/scenery/scenes/title.c b/apps/scenery/scenes/title.c index 90efd0b..9361ade 100644 --- a/apps/scenery/scenes/title.c +++ b/apps/scenery/scenes/title.c @@ -11,7 +11,7 @@ static void title_tick(State *state) { SceneTitle *scn = (SceneTitle *)state->scene; (void)scn; - if (input_is_action_just_pressed(&state->ctx->input, "ui_accept")) { + if (input_is_action_just_pressed("ui_accept")) { switch_to(state, ingame_scene); return; } diff --git a/include/twn_context.h b/include/twn_context.h index 562c050..4f15066 100644 --- a/include/twn_context.h +++ b/include/twn_context.h @@ -8,12 +8,20 @@ #include +/* context that is valid for current frame */ +/* changes to it should not have an effect, unless specified */ +/* TODO: ensure the statement above */ typedef struct Context { - InputState input; + /* you may read from and write to these from game code */ + void *udata; + /* TODO: is it what we actually want? */ int64_t delta_time; /* preserves real time frame delta with no manipilation */ uint64_t tick_count; + Vec2i mouse_window_position; + Vec2i mouse_relative_position; + /* set just once on startup */ uint64_t random_seed; @@ -21,14 +29,13 @@ typedef struct Context { /* use it to simulate low framerate (e.g. at 60 tps, set to 2 for 30 fps) */ /* it can be changed at runtime; any resulting logic anomalies are bugs */ unsigned int update_multiplicity; + + /* TODO: use Vec2i? */ int window_w; int window_h; int base_draw_w; int base_draw_h; - /* you may read from and write to these from game code */ - void *udata; - bool debug; bool is_running; bool window_size_has_changed; diff --git a/include/twn_control.h b/include/twn_control.h new file mode 100644 index 0000000..00808d5 --- /dev/null +++ b/include/twn_control.h @@ -0,0 +1,433 @@ +#ifndef TWN_CONTROL_H +#define TWN_CONTROL_H + +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* based on SDL2 */ +/* main difference is that we combine mouse and scancode sources into one enum space */ + +typedef enum +{ +CONTROL_SCANCODE_START = 0, + CONTROL_UNKNOWN = 0, + + /** + * \name Usage page 0x07 + * + * These values are from usage page 0x07 (USB keyboard page). + */ + /* @{ */ + + CONTROL_A = 4, + CONTROL_B = 5, + CONTROL_C = 6, + CONTROL_D = 7, + CONTROL_E = 8, + CONTROL_F = 9, + CONTROL_G = 10, + CONTROL_H = 11, + CONTROL_I = 12, + CONTROL_J = 13, + CONTROL_K = 14, + CONTROL_L = 15, + CONTROL_M = 16, + CONTROL_N = 17, + CONTROL_O = 18, + CONTROL_P = 19, + CONTROL_Q = 20, + CONTROL_R = 21, + CONTROL_S = 22, + CONTROL_T = 23, + CONTROL_U = 24, + CONTROL_V = 25, + CONTROL_W = 26, + CONTROL_X = 27, + CONTROL_Y = 28, + CONTROL_Z = 29, + + CONTROL_1 = 30, + CONTROL_2 = 31, + CONTROL_3 = 32, + CONTROL_4 = 33, + CONTROL_5 = 34, + CONTROL_6 = 35, + CONTROL_7 = 36, + CONTROL_8 = 37, + CONTROL_9 = 38, + CONTROL_0 = 39, + + CONTROL_RETURN = 40, + CONTROL_ESCAPE = 41, + CONTROL_BACKSPACE = 42, + CONTROL_TAB = 43, + CONTROL_SPACE = 44, + + CONTROL_MINUS = 45, + CONTROL_EQUALS = 46, + CONTROL_LEFTBRACKET = 47, + CONTROL_RIGHTBRACKET = 48, + CONTROL_BACKSLASH = 49, /**< Located at the lower left of the return + * key on ISO keyboards and at the right end + * of the QWERTY row on ANSI keyboards. + * Produces REVERSE SOLIDUS (backslash) and + * VERTICAL LINE in a US layout, REVERSE + * SOLIDUS and VERTICAL LINE in a UK Mac + * layout, NUMBER SIGN and TILDE in a UK + * Windows layout, DOLLAR SIGN and POUND SIGN + * in a Swiss German layout, NUMBER SIGN and + * APOSTROPHE in a German layout, GRAVE + * ACCENT and POUND SIGN in a French Mac + * layout, and ASTERISK and MICRO SIGN in a + * French Windows layout. + */ + CONTROL_NONUSHASH = 50, /**< ISO USB keyboards actually use this code + * instead of 49 for the same key, but all + * OSes I've seen treat the two codes + * identically. So, as an implementor, unless + * your keyboard generates both of those + * codes and your OS treats them differently, + * you should generate CONTROL_BACKSLASH + * instead of this code. As a user, you + * should not rely on this code because SDL + * will never generate it with most (all?) + * keyboards. + */ + CONTROL_SEMICOLON = 51, + CONTROL_APOSTROPHE = 52, + CONTROL_GRAVE = 53, /**< Located in the top left corner (on both ANSI + * and ISO keyboards). Produces GRAVE ACCENT and + * TILDE in a US Windows layout and in US and UK + * Mac layouts on ANSI keyboards, GRAVE ACCENT + * and NOT SIGN in a UK Windows layout, SECTION + * SIGN and PLUS-MINUS SIGN in US and UK Mac + * layouts on ISO keyboards, SECTION SIGN and + * DEGREE SIGN in a Swiss German layout (Mac: + * only on ISO keyboards), CIRCUMFLEX ACCENT and + * DEGREE SIGN in a German layout (Mac: only on + * ISO keyboards), SUPERSCRIPT TWO and TILDE in a + * French Windows layout, COMMERCIAL AT and + * NUMBER SIGN in a French Mac layout on ISO + * keyboards, and LESS-THAN SIGN and GREATER-THAN + * SIGN in a Swiss German, German, or French Mac + * layout on ANSI keyboards. + */ + CONTROL_COMMA = 54, + CONTROL_PERIOD = 55, + CONTROL_SLASH = 56, + + CONTROL_CAPSLOCK = 57, + + CONTROL_F1 = 58, + CONTROL_F2 = 59, + CONTROL_F3 = 60, + CONTROL_F4 = 61, + CONTROL_F5 = 62, + CONTROL_F6 = 63, + CONTROL_F7 = 64, + CONTROL_F8 = 65, + CONTROL_F9 = 66, + CONTROL_F10 = 67, + CONTROL_F11 = 68, + CONTROL_F12 = 69, + + CONTROL_PRINTSCREEN = 70, + CONTROL_SCROLLLOCK = 71, + CONTROL_PAUSE = 72, + CONTROL_INSERT = 73, /**< insert on PC, help on some Mac keyboards (but + does send code 73, not 117) */ + CONTROL_HOME = 74, + CONTROL_PAGEUP = 75, + CONTROL_DELETE = 76, + CONTROL_END = 77, + CONTROL_PAGEDOWN = 78, + CONTROL_RIGHT = 79, + CONTROL_LEFT = 80, + CONTROL_DOWN = 81, + CONTROL_UP = 82, + + CONTROL_NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards + */ + CONTROL_KP_DIVIDE = 84, + CONTROL_KP_MULTIPLY = 85, + CONTROL_KP_MINUS = 86, + CONTROL_KP_PLUS = 87, + CONTROL_KP_ENTER = 88, + CONTROL_KP_1 = 89, + CONTROL_KP_2 = 90, + CONTROL_KP_3 = 91, + CONTROL_KP_4 = 92, + CONTROL_KP_5 = 93, + CONTROL_KP_6 = 94, + CONTROL_KP_7 = 95, + CONTROL_KP_8 = 96, + CONTROL_KP_9 = 97, + CONTROL_KP_0 = 98, + CONTROL_KP_PERIOD = 99, + + CONTROL_NONUSBACKSLASH = 100, /**< This is the additional key that ISO + * keyboards have over ANSI ones, + * located between left shift and Y. + * Produces GRAVE ACCENT and TILDE in a + * US or UK Mac layout, REVERSE SOLIDUS + * (backslash) and VERTICAL LINE in a + * US or UK Windows layout, and + * LESS-THAN SIGN and GREATER-THAN SIGN + * in a Swiss German, German, or French + * layout. */ + CONTROL_APPLICATION = 101, /**< windows contextual menu, compose */ + CONTROL_POWER = 102, /**< The USB document says this is a status flag, + * not a physical key - but some Mac keyboards + * do have a power key. */ + CONTROL_KP_EQUALS = 103, + CONTROL_F13 = 104, + CONTROL_F14 = 105, + CONTROL_F15 = 106, + CONTROL_F16 = 107, + CONTROL_F17 = 108, + CONTROL_F18 = 109, + CONTROL_F19 = 110, + CONTROL_F20 = 111, + CONTROL_F21 = 112, + CONTROL_F22 = 113, + CONTROL_F23 = 114, + CONTROL_F24 = 115, + CONTROL_EXECUTE = 116, + CONTROL_HELP = 117, /**< AL Integrated Help Center */ + CONTROL_MENU = 118, /**< Menu (show menu) */ + CONTROL_SELECT = 119, + CONTROL_STOP = 120, /**< AC Stop */ + CONTROL_AGAIN = 121, /**< AC Redo/Repeat */ + CONTROL_UNDO = 122, /**< AC Undo */ + CONTROL_CUT = 123, /**< AC Cut */ + CONTROL_COPY = 124, /**< AC Copy */ + CONTROL_PASTE = 125, /**< AC Paste */ + CONTROL_FIND = 126, /**< AC Find */ + CONTROL_MUTE = 127, + CONTROL_VOLUMEUP = 128, + CONTROL_VOLUMEDOWN = 129, +/* not sure whether there's a reason to enable these */ +/* CONTROL_LOCKINGCAPSLOCK = 130, */ +/* CONTROL_LOCKINGNUMLOCK = 131, */ +/* CONTROL_LOCKINGSCROLLLOCK = 132, */ + CONTROL_KP_COMMA = 133, + CONTROL_KP_EQUALSAS400 = 134, + + CONTROL_INTERNATIONAL1 = 135, /**< used on Asian keyboards, see + footnotes in USB doc */ + CONTROL_INTERNATIONAL2 = 136, + CONTROL_INTERNATIONAL3 = 137, /**< Yen */ + CONTROL_INTERNATIONAL4 = 138, + CONTROL_INTERNATIONAL5 = 139, + CONTROL_INTERNATIONAL6 = 140, + CONTROL_INTERNATIONAL7 = 141, + CONTROL_INTERNATIONAL8 = 142, + CONTROL_INTERNATIONAL9 = 143, + CONTROL_LANG1 = 144, /**< Hangul/English toggle */ + CONTROL_LANG2 = 145, /**< Hanja conversion */ + CONTROL_LANG3 = 146, /**< Katakana */ + CONTROL_LANG4 = 147, /**< Hiragana */ + CONTROL_LANG5 = 148, /**< Zenkaku/Hankaku */ + CONTROL_LANG6 = 149, /**< reserved */ + CONTROL_LANG7 = 150, /**< reserved */ + CONTROL_LANG8 = 151, /**< reserved */ + CONTROL_LANG9 = 152, /**< reserved */ + + CONTROL_ALTERASE = 153, /**< Erase-Eaze */ + CONTROL_SYSREQ = 154, + CONTROL_CANCEL = 155, /**< AC Cancel */ + CONTROL_CLEAR = 156, + CONTROL_PRIOR = 157, + CONTROL_RETURN2 = 158, + CONTROL_SEPARATOR = 159, + CONTROL_OUT = 160, + CONTROL_OPER = 161, + CONTROL_CLEARAGAIN = 162, + CONTROL_CRSEL = 163, + CONTROL_EXSEL = 164, + + CONTROL_KP_00 = 176, + CONTROL_KP_000 = 177, + CONTROL_THOUSANDSSEPARATOR = 178, + CONTROL_DECIMALSEPARATOR = 179, + CONTROL_CURRENCYUNIT = 180, + CONTROL_CURRENCYSUBUNIT = 181, + CONTROL_KP_LEFTPAREN = 182, + CONTROL_KP_RIGHTPAREN = 183, + CONTROL_KP_LEFTBRACE = 184, + CONTROL_KP_RIGHTBRACE = 185, + CONTROL_KP_TAB = 186, + CONTROL_KP_BACKSPACE = 187, + CONTROL_KP_A = 188, + CONTROL_KP_B = 189, + CONTROL_KP_C = 190, + CONTROL_KP_D = 191, + CONTROL_KP_E = 192, + CONTROL_KP_F = 193, + CONTROL_KP_XOR = 194, + CONTROL_KP_POWER = 195, + CONTROL_KP_PERCENT = 196, + CONTROL_KP_LESS = 197, + CONTROL_KP_GREATER = 198, + CONTROL_KP_AMPERSAND = 199, + CONTROL_KP_DBLAMPERSAND = 200, + CONTROL_KP_VERTICALBAR = 201, + CONTROL_KP_DBLVERTICALBAR = 202, + CONTROL_KP_COLON = 203, + CONTROL_KP_HASH = 204, + CONTROL_KP_SPACE = 205, + CONTROL_KP_AT = 206, + CONTROL_KP_EXCLAM = 207, + CONTROL_KP_MEMSTORE = 208, + CONTROL_KP_MEMRECALL = 209, + CONTROL_KP_MEMCLEAR = 210, + CONTROL_KP_MEMADD = 211, + CONTROL_KP_MEMSUBTRACT = 212, + CONTROL_KP_MEMMULTIPLY = 213, + CONTROL_KP_MEMDIVIDE = 214, + CONTROL_KP_PLUSMINUS = 215, + CONTROL_KP_CLEAR = 216, + CONTROL_KP_CLEARENTRY = 217, + CONTROL_KP_BINARY = 218, + CONTROL_KP_OCTAL = 219, + CONTROL_KP_DECIMAL = 220, + CONTROL_KP_HEXADECIMAL = 221, + + CONTROL_LCTRL = 224, + CONTROL_LSHIFT = 225, + CONTROL_LALT = 226, /**< alt, option */ + CONTROL_LGUI = 227, /**< windows, command (apple), meta */ + CONTROL_RCTRL = 228, + CONTROL_RSHIFT = 229, + CONTROL_RALT = 230, /**< alt gr, option */ + CONTROL_RGUI = 231, /**< windows, command (apple), meta */ + + CONTROL_MODE = 257, /**< I'm not sure if this is really not covered + * by any of the above, but since there's a + * special KMOD_MODE for it I'm adding it here + */ + + /* @} *//* Usage page 0x07 */ + + /** + * \name Usage page 0x0C + * + * These values are mapped from usage page 0x0C (USB consumer page). + * See https://usb.org/sites/default/files/hut1_2.pdf + * + * There are way more keys in the spec than we can represent in the + * current scancode range, so pick the ones that commonly come up in + * real world usage. + */ + /* @{ */ + + CONTROL_AUDIONEXT = 258, + CONTROL_AUDIOPREV = 259, + CONTROL_AUDIOSTOP = 260, + CONTROL_AUDIOPLAY = 261, + CONTROL_AUDIOMUTE = 262, + CONTROL_MEDIASELECT = 263, + CONTROL_WWW = 264, /**< AL Internet Browser */ + CONTROL_MAIL = 265, + CONTROL_CALCULATOR = 266, /**< AL Calculator */ + CONTROL_COMPUTER = 267, + CONTROL_AC_SEARCH = 268, /**< AC Search */ + CONTROL_AC_HOME = 269, /**< AC Home */ + CONTROL_AC_BACK = 270, /**< AC Back */ + CONTROL_AC_FORWARD = 271, /**< AC Forward */ + CONTROL_AC_STOP = 272, /**< AC Stop */ + CONTROL_AC_REFRESH = 273, /**< AC Refresh */ + CONTROL_AC_BOOKMARKS = 274, /**< AC Bookmarks */ + + /* @} *//* Usage page 0x0C */ + + /** + * \name Walther keys + * + * These are values that Christian Walther added (for mac keyboard?). + */ + /* @{ */ + + CONTROL_BRIGHTNESSDOWN = 275, + CONTROL_BRIGHTNESSUP = 276, + CONTROL_DISPLAYSWITCH = 277, /**< display mirroring/dual display + switch, video mode switch */ + CONTROL_KBDILLUMTOGGLE = 278, + CONTROL_KBDILLUMDOWN = 279, + CONTROL_KBDILLUMUP = 280, + CONTROL_EJECT = 281, + CONTROL_SLEEP = 282, /**< SC System Sleep */ + + CONTROL_APP1 = 283, + CONTROL_APP2 = 284, + + /* @} *//* Walther keys */ + + /** + * \name Usage page 0x0C (additional media keys) + * + * These values are mapped from usage page 0x0C (USB consumer page). + */ + /* @{ */ + + CONTROL_AUDIOREWIND = 285, + CONTROL_AUDIOFASTFORWARD = 286, + + /* @} *//* Usage page 0x0C (additional media keys) */ + + /** + * \name Mobile keys + * + * These are values that are often used on mobile phones. + */ + /* @{ */ + + CONTROL_SOFTLEFT = 287, /**< Usually situated below the display on phones and + used as a multi-function feature key for selecting + a software defined function shown on the bottom left + of the display. */ + CONTROL_SOFTRIGHT = 288, /**< Usually situated below the display on phones and + used as a multi-function feature key for selecting + a software defined function shown on the bottom right + of the display. */ + CONTROL_CALL = 289, /**< Used for accepting phone calls. */ + CONTROL_ENDCALL = 290, /**< Used for rejecting phone calls. */ + + /* @} *//* Mobile keys */ + + /* Add any other keys here. */ + +CONTROL_SCANCODE_LIMIT = 512, /**< not a key, just marks the number of scancodes + for array bounds */ + +CONTROL_MOUSECODE_START = 512, + + CONTROL_LEFT_MOUSE = 513, + CONTROL_RIGHT_MOUSE = 515, + CONTROL_MIDDLE_MOUSE = 514, + CONTROL_X1 = 516, + CONTROL_X2 = 517, + +CONTROL_MOUSECODE_LIMIT = 532, + +} Control; + +#endif diff --git a/include/twn_input.h b/include/twn_input.h index 17c2f4a..2c4ac6b 100644 --- a/include/twn_input.h +++ b/include/twn_input.h @@ -4,87 +4,26 @@ #include "twn_config.h" #include "twn_types.h" #include "twn_engine_api.h" -#include "twn_scancode.h" +#include "twn_control.h" #include #include #include -typedef enum ButtonSource { - BUTTON_SOURCE_NOT_SET, - BUTTON_SOURCE_KEYBOARD_PHYSICAL, - BUTTON_SOURCE_KEYBOARD_CHARACTER, - BUTTON_SOURCE_GAMEPAD, - BUTTON_SOURCE_MOUSE, -} ButtonSource; +TWN_API void input_bind_action_control(const char *action_name, Control control); +TWN_API void input_unbind_action_control(const char *action_name, Control control); -/* internal */ -typedef struct Button Button; +TWN_API void input_add_action(const char *action_name); +TWN_API void input_delete_action(const char *action_name); +TWN_API bool input_is_action_pressed(const char *action_name); +TWN_API bool input_is_action_just_pressed(const char *action_name); +TWN_API bool input_is_action_just_released(const char *action_name); -/* represents the collective state of a group of buttons */ -/* that is, changes in the states of any of the bound buttons will affect it */ -typedef struct Action { - size_t num_bindings; +TWN_API Vec2 input_get_action_position(const char *action_name); - /* if you bind more than the number set in the configuration file */ - /* it forgets the first Button to add the new one at the end */ - Button *bindings; - - Vec2 position; /* set if applicable, e.g. mouse click */ - bool is_pressed; - bool just_changed; -} Action; - - -typedef struct ActionHashItem { - char *key; - Action value; -} ActionHashItem; - - -/* TODO: don't assume SDL button mask */ -typedef struct InputState { - uint32_t mouse_state; /* SDL mouse button bitmask */ - Vec2i mouse_window_position; - Vec2i mouse_relative_position; - ButtonSource last_active_source; - bool is_anything_just_pressed; - - /* engine state */ - ActionHashItem *action_hash; - const uint8_t *keyboard_state; /* array of booleans indexed by scancode */ -} InputState; - - -TWN_API void input_state_init(InputState *input); -TWN_API void input_state_deinit(InputState *input); -TWN_API void input_state_update(InputState *input); - -TWN_API void input_bind_action_scancode(InputState *input, - char *action_name, - Scancode scancode); -TWN_API void input_unbind_action_scancode(InputState *input, - char *action_name, - Scancode scancode); -TWN_API void input_bind_action_mouse(InputState *input, - char *action_name, - uint8_t mouse_button); -TWN_API void input_unbind_action_mouse(InputState *input, - char *action_name, - uint8_t mouse_button); - -TWN_API void input_add_action(InputState *input, char *action_name); -TWN_API void input_delete_action(InputState *input, char *action_name); - -TWN_API bool input_is_action_pressed(InputState *input, char *action_name); -TWN_API bool input_is_action_just_pressed(InputState *input, char *action_name); -TWN_API bool input_is_action_just_released(InputState *input, char *action_name); - -TWN_API Vec2 input_get_action_position(InputState *input, char *action_name); - -TWN_API void input_set_mouse_captured(InputState *input, bool value); -TWN_API bool input_is_mouse_captured(InputState *input); +TWN_API void input_set_mouse_captured(bool enabled); +TWN_API bool input_is_mouse_captured(void); #endif diff --git a/include/twn_scancode.h b/include/twn_scancode.h deleted file mode 100644 index f9daed2..0000000 --- a/include/twn_scancode.h +++ /dev/null @@ -1,420 +0,0 @@ -#ifndef TWN_SCANCODE_H -#define TWN_SCANCODE_H - -/* - Simple DirectMedia Layer - Copyright (C) 1997-2024 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/* based on SDL2 */ - -typedef enum -{ - SCANCODE_UNKNOWN = 0, - - /** - * \name Usage page 0x07 - * - * These values are from usage page 0x07 (USB keyboard page). - */ - /* @{ */ - - SCANCODE_A = 4, - SCANCODE_B = 5, - SCANCODE_C = 6, - SCANCODE_D = 7, - SCANCODE_E = 8, - SCANCODE_F = 9, - SCANCODE_G = 10, - SCANCODE_H = 11, - SCANCODE_I = 12, - SCANCODE_J = 13, - SCANCODE_K = 14, - SCANCODE_L = 15, - SCANCODE_M = 16, - SCANCODE_N = 17, - SCANCODE_O = 18, - SCANCODE_P = 19, - SCANCODE_Q = 20, - SCANCODE_R = 21, - SCANCODE_S = 22, - SCANCODE_T = 23, - SCANCODE_U = 24, - SCANCODE_V = 25, - SCANCODE_W = 26, - SCANCODE_X = 27, - SCANCODE_Y = 28, - SCANCODE_Z = 29, - - SCANCODE_1 = 30, - SCANCODE_2 = 31, - SCANCODE_3 = 32, - SCANCODE_4 = 33, - SCANCODE_5 = 34, - SCANCODE_6 = 35, - SCANCODE_7 = 36, - SCANCODE_8 = 37, - SCANCODE_9 = 38, - SCANCODE_0 = 39, - - SCANCODE_RETURN = 40, - SCANCODE_ESCAPE = 41, - SCANCODE_BACKSPACE = 42, - SCANCODE_TAB = 43, - SCANCODE_SPACE = 44, - - SCANCODE_MINUS = 45, - SCANCODE_EQUALS = 46, - SCANCODE_LEFTBRACKET = 47, - SCANCODE_RIGHTBRACKET = 48, - SCANCODE_BACKSLASH = 49, /**< Located at the lower left of the return - * key on ISO keyboards and at the right end - * of the QWERTY row on ANSI keyboards. - * Produces REVERSE SOLIDUS (backslash) and - * VERTICAL LINE in a US layout, REVERSE - * SOLIDUS and VERTICAL LINE in a UK Mac - * layout, NUMBER SIGN and TILDE in a UK - * Windows layout, DOLLAR SIGN and POUND SIGN - * in a Swiss German layout, NUMBER SIGN and - * APOSTROPHE in a German layout, GRAVE - * ACCENT and POUND SIGN in a French Mac - * layout, and ASTERISK and MICRO SIGN in a - * French Windows layout. - */ - SCANCODE_NONUSHASH = 50, /**< ISO USB keyboards actually use this code - * instead of 49 for the same key, but all - * OSes I've seen treat the two codes - * identically. So, as an implementor, unless - * your keyboard generates both of those - * codes and your OS treats them differently, - * you should generate SCANCODE_BACKSLASH - * instead of this code. As a user, you - * should not rely on this code because SDL - * will never generate it with most (all?) - * keyboards. - */ - SCANCODE_SEMICOLON = 51, - SCANCODE_APOSTROPHE = 52, - SCANCODE_GRAVE = 53, /**< Located in the top left corner (on both ANSI - * and ISO keyboards). Produces GRAVE ACCENT and - * TILDE in a US Windows layout and in US and UK - * Mac layouts on ANSI keyboards, GRAVE ACCENT - * and NOT SIGN in a UK Windows layout, SECTION - * SIGN and PLUS-MINUS SIGN in US and UK Mac - * layouts on ISO keyboards, SECTION SIGN and - * DEGREE SIGN in a Swiss German layout (Mac: - * only on ISO keyboards), CIRCUMFLEX ACCENT and - * DEGREE SIGN in a German layout (Mac: only on - * ISO keyboards), SUPERSCRIPT TWO and TILDE in a - * French Windows layout, COMMERCIAL AT and - * NUMBER SIGN in a French Mac layout on ISO - * keyboards, and LESS-THAN SIGN and GREATER-THAN - * SIGN in a Swiss German, German, or French Mac - * layout on ANSI keyboards. - */ - SCANCODE_COMMA = 54, - SCANCODE_PERIOD = 55, - SCANCODE_SLASH = 56, - - SCANCODE_CAPSLOCK = 57, - - SCANCODE_F1 = 58, - SCANCODE_F2 = 59, - SCANCODE_F3 = 60, - SCANCODE_F4 = 61, - SCANCODE_F5 = 62, - SCANCODE_F6 = 63, - SCANCODE_F7 = 64, - SCANCODE_F8 = 65, - SCANCODE_F9 = 66, - SCANCODE_F10 = 67, - SCANCODE_F11 = 68, - SCANCODE_F12 = 69, - - SCANCODE_PRINTSCREEN = 70, - SCANCODE_SCROLLLOCK = 71, - SCANCODE_PAUSE = 72, - SCANCODE_INSERT = 73, /**< insert on PC, help on some Mac keyboards (but - does send code 73, not 117) */ - SCANCODE_HOME = 74, - SCANCODE_PAGEUP = 75, - SCANCODE_DELETE = 76, - SCANCODE_END = 77, - SCANCODE_PAGEDOWN = 78, - SCANCODE_RIGHT = 79, - SCANCODE_LEFT = 80, - SCANCODE_DOWN = 81, - SCANCODE_UP = 82, - - SCANCODE_NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards - */ - SCANCODE_KP_DIVIDE = 84, - SCANCODE_KP_MULTIPLY = 85, - SCANCODE_KP_MINUS = 86, - SCANCODE_KP_PLUS = 87, - SCANCODE_KP_ENTER = 88, - SCANCODE_KP_1 = 89, - SCANCODE_KP_2 = 90, - SCANCODE_KP_3 = 91, - SCANCODE_KP_4 = 92, - SCANCODE_KP_5 = 93, - SCANCODE_KP_6 = 94, - SCANCODE_KP_7 = 95, - SCANCODE_KP_8 = 96, - SCANCODE_KP_9 = 97, - SCANCODE_KP_0 = 98, - SCANCODE_KP_PERIOD = 99, - - SCANCODE_NONUSBACKSLASH = 100, /**< This is the additional key that ISO - * keyboards have over ANSI ones, - * located between left shift and Y. - * Produces GRAVE ACCENT and TILDE in a - * US or UK Mac layout, REVERSE SOLIDUS - * (backslash) and VERTICAL LINE in a - * US or UK Windows layout, and - * LESS-THAN SIGN and GREATER-THAN SIGN - * in a Swiss German, German, or French - * layout. */ - SCANCODE_APPLICATION = 101, /**< windows contextual menu, compose */ - SCANCODE_POWER = 102, /**< The USB document says this is a status flag, - * not a physical key - but some Mac keyboards - * do have a power key. */ - SCANCODE_KP_EQUALS = 103, - SCANCODE_F13 = 104, - SCANCODE_F14 = 105, - SCANCODE_F15 = 106, - SCANCODE_F16 = 107, - SCANCODE_F17 = 108, - SCANCODE_F18 = 109, - SCANCODE_F19 = 110, - SCANCODE_F20 = 111, - SCANCODE_F21 = 112, - SCANCODE_F22 = 113, - SCANCODE_F23 = 114, - SCANCODE_F24 = 115, - SCANCODE_EXECUTE = 116, - SCANCODE_HELP = 117, /**< AL Integrated Help Center */ - SCANCODE_MENU = 118, /**< Menu (show menu) */ - SCANCODE_SELECT = 119, - SCANCODE_STOP = 120, /**< AC Stop */ - SCANCODE_AGAIN = 121, /**< AC Redo/Repeat */ - SCANCODE_UNDO = 122, /**< AC Undo */ - SCANCODE_CUT = 123, /**< AC Cut */ - SCANCODE_COPY = 124, /**< AC Copy */ - SCANCODE_PASTE = 125, /**< AC Paste */ - SCANCODE_FIND = 126, /**< AC Find */ - SCANCODE_MUTE = 127, - SCANCODE_VOLUMEUP = 128, - SCANCODE_VOLUMEDOWN = 129, -/* not sure whether there's a reason to enable these */ -/* SCANCODE_LOCKINGCAPSLOCK = 130, */ -/* SCANCODE_LOCKINGNUMLOCK = 131, */ -/* SCANCODE_LOCKINGSCROLLLOCK = 132, */ - SCANCODE_KP_COMMA = 133, - SCANCODE_KP_EQUALSAS400 = 134, - - SCANCODE_INTERNATIONAL1 = 135, /**< used on Asian keyboards, see - footnotes in USB doc */ - SCANCODE_INTERNATIONAL2 = 136, - SCANCODE_INTERNATIONAL3 = 137, /**< Yen */ - SCANCODE_INTERNATIONAL4 = 138, - SCANCODE_INTERNATIONAL5 = 139, - SCANCODE_INTERNATIONAL6 = 140, - SCANCODE_INTERNATIONAL7 = 141, - SCANCODE_INTERNATIONAL8 = 142, - SCANCODE_INTERNATIONAL9 = 143, - SCANCODE_LANG1 = 144, /**< Hangul/English toggle */ - SCANCODE_LANG2 = 145, /**< Hanja conversion */ - SCANCODE_LANG3 = 146, /**< Katakana */ - SCANCODE_LANG4 = 147, /**< Hiragana */ - SCANCODE_LANG5 = 148, /**< Zenkaku/Hankaku */ - SCANCODE_LANG6 = 149, /**< reserved */ - SCANCODE_LANG7 = 150, /**< reserved */ - SCANCODE_LANG8 = 151, /**< reserved */ - SCANCODE_LANG9 = 152, /**< reserved */ - - SCANCODE_ALTERASE = 153, /**< Erase-Eaze */ - SCANCODE_SYSREQ = 154, - SCANCODE_CANCEL = 155, /**< AC Cancel */ - SCANCODE_CLEAR = 156, - SCANCODE_PRIOR = 157, - SCANCODE_RETURN2 = 158, - SCANCODE_SEPARATOR = 159, - SCANCODE_OUT = 160, - SCANCODE_OPER = 161, - SCANCODE_CLEARAGAIN = 162, - SCANCODE_CRSEL = 163, - SCANCODE_EXSEL = 164, - - SCANCODE_KP_00 = 176, - SCANCODE_KP_000 = 177, - SCANCODE_THOUSANDSSEPARATOR = 178, - SCANCODE_DECIMALSEPARATOR = 179, - SCANCODE_CURRENCYUNIT = 180, - SCANCODE_CURRENCYSUBUNIT = 181, - SCANCODE_KP_LEFTPAREN = 182, - SCANCODE_KP_RIGHTPAREN = 183, - SCANCODE_KP_LEFTBRACE = 184, - SCANCODE_KP_RIGHTBRACE = 185, - SCANCODE_KP_TAB = 186, - SCANCODE_KP_BACKSPACE = 187, - SCANCODE_KP_A = 188, - SCANCODE_KP_B = 189, - SCANCODE_KP_C = 190, - SCANCODE_KP_D = 191, - SCANCODE_KP_E = 192, - SCANCODE_KP_F = 193, - SCANCODE_KP_XOR = 194, - SCANCODE_KP_POWER = 195, - SCANCODE_KP_PERCENT = 196, - SCANCODE_KP_LESS = 197, - SCANCODE_KP_GREATER = 198, - SCANCODE_KP_AMPERSAND = 199, - SCANCODE_KP_DBLAMPERSAND = 200, - SCANCODE_KP_VERTICALBAR = 201, - SCANCODE_KP_DBLVERTICALBAR = 202, - SCANCODE_KP_COLON = 203, - SCANCODE_KP_HASH = 204, - SCANCODE_KP_SPACE = 205, - SCANCODE_KP_AT = 206, - SCANCODE_KP_EXCLAM = 207, - SCANCODE_KP_MEMSTORE = 208, - SCANCODE_KP_MEMRECALL = 209, - SCANCODE_KP_MEMCLEAR = 210, - SCANCODE_KP_MEMADD = 211, - SCANCODE_KP_MEMSUBTRACT = 212, - SCANCODE_KP_MEMMULTIPLY = 213, - SCANCODE_KP_MEMDIVIDE = 214, - SCANCODE_KP_PLUSMINUS = 215, - SCANCODE_KP_CLEAR = 216, - SCANCODE_KP_CLEARENTRY = 217, - SCANCODE_KP_BINARY = 218, - SCANCODE_KP_OCTAL = 219, - SCANCODE_KP_DECIMAL = 220, - SCANCODE_KP_HEXADECIMAL = 221, - - SCANCODE_LCTRL = 224, - SCANCODE_LSHIFT = 225, - SCANCODE_LALT = 226, /**< alt, option */ - SCANCODE_LGUI = 227, /**< windows, command (apple), meta */ - SCANCODE_RCTRL = 228, - SCANCODE_RSHIFT = 229, - SCANCODE_RALT = 230, /**< alt gr, option */ - SCANCODE_RGUI = 231, /**< windows, command (apple), meta */ - - SCANCODE_MODE = 257, /**< I'm not sure if this is really not covered - * by any of the above, but since there's a - * special KMOD_MODE for it I'm adding it here - */ - - /* @} *//* Usage page 0x07 */ - - /** - * \name Usage page 0x0C - * - * These values are mapped from usage page 0x0C (USB consumer page). - * See https://usb.org/sites/default/files/hut1_2.pdf - * - * There are way more keys in the spec than we can represent in the - * current scancode range, so pick the ones that commonly come up in - * real world usage. - */ - /* @{ */ - - SCANCODE_AUDIONEXT = 258, - SCANCODE_AUDIOPREV = 259, - SCANCODE_AUDIOSTOP = 260, - SCANCODE_AUDIOPLAY = 261, - SCANCODE_AUDIOMUTE = 262, - SCANCODE_MEDIASELECT = 263, - SCANCODE_WWW = 264, /**< AL Internet Browser */ - SCANCODE_MAIL = 265, - SCANCODE_CALCULATOR = 266, /**< AL Calculator */ - SCANCODE_COMPUTER = 267, - SCANCODE_AC_SEARCH = 268, /**< AC Search */ - SCANCODE_AC_HOME = 269, /**< AC Home */ - SCANCODE_AC_BACK = 270, /**< AC Back */ - SCANCODE_AC_FORWARD = 271, /**< AC Forward */ - SCANCODE_AC_STOP = 272, /**< AC Stop */ - SCANCODE_AC_REFRESH = 273, /**< AC Refresh */ - SCANCODE_AC_BOOKMARKS = 274, /**< AC Bookmarks */ - - /* @} *//* Usage page 0x0C */ - - /** - * \name Walther keys - * - * These are values that Christian Walther added (for mac keyboard?). - */ - /* @{ */ - - SCANCODE_BRIGHTNESSDOWN = 275, - SCANCODE_BRIGHTNESSUP = 276, - SCANCODE_DISPLAYSWITCH = 277, /**< display mirroring/dual display - switch, video mode switch */ - SCANCODE_KBDILLUMTOGGLE = 278, - SCANCODE_KBDILLUMDOWN = 279, - SCANCODE_KBDILLUMUP = 280, - SCANCODE_EJECT = 281, - SCANCODE_SLEEP = 282, /**< SC System Sleep */ - - SCANCODE_APP1 = 283, - SCANCODE_APP2 = 284, - - /* @} *//* Walther keys */ - - /** - * \name Usage page 0x0C (additional media keys) - * - * These values are mapped from usage page 0x0C (USB consumer page). - */ - /* @{ */ - - SCANCODE_AUDIOREWIND = 285, - SCANCODE_AUDIOFASTFORWARD = 286, - - /* @} *//* Usage page 0x0C (additional media keys) */ - - /** - * \name Mobile keys - * - * These are values that are often used on mobile phones. - */ - /* @{ */ - - SCANCODE_SOFTLEFT = 287, /**< Usually situated below the display on phones and - used as a multi-function feature key for selecting - a software defined function shown on the bottom left - of the display. */ - SCANCODE_SOFTRIGHT = 288, /**< Usually situated below the display on phones and - used as a multi-function feature key for selecting - a software defined function shown on the bottom right - of the display. */ - SCANCODE_CALL = 289, /**< Used for accepting phone calls. */ - SCANCODE_ENDCALL = 290, /**< Used for rejecting phone calls. */ - - /* @} *//* Mobile keys */ - - /* Add any other keys here. */ - - NUM_SCANCODES = 512 /**< not a key, just marks the number of scancodes - for array bounds */ -} Scancode; - -#endif diff --git a/src/twn_engine_context_c.h b/src/twn_engine_context_c.h index 398cc5b..bb6cbb1 100644 --- a/src/twn_engine_context_c.h +++ b/src/twn_engine_context_c.h @@ -4,6 +4,7 @@ #include "twn_context.h" #include "twn_textures_c.h" #include "twn_audio_c.h" +#include "twn_input_c.h" #include "twn_engine_api.h" #include "rendering/twn_draw_c.h" @@ -18,6 +19,8 @@ typedef struct EngineContext { /* user code facing context */ Context game; + InputState input; + /* the program's actual argc and argv */ int argc; char **argv; @@ -64,6 +67,7 @@ typedef struct EngineContext { bool was_successful; } EngineContext; +/* TODO: does it need to be marked with TWN_API? */ TWN_API extern EngineContext ctx; #endif diff --git a/src/twn_input.c b/src/twn_input.c index 47e51ee..aad353c 100644 --- a/src/twn_input.c +++ b/src/twn_input.c @@ -1,5 +1,6 @@ #include "twn_input_c.h" #include "twn_util.h" +#include "twn_control.h" #include "twn_engine_context_c.h" #include @@ -38,7 +39,7 @@ static void update_action_pressed_state(InputState *input, Action *action) { action->just_changed = !action->is_pressed; action->is_pressed = true; action->position.x = (float)input->mouse_window_position.x; - action->position.x = (float)input->mouse_window_position.x; + action->position.y = (float)input->mouse_window_position.y; /* TODO: */ /* @@ -63,7 +64,7 @@ static void update_action_pressed_state(InputState *input, Action *action) { static void input_bind_code_to_action(InputState *input, - char *action_name, + char const *action_name, ButtonSource source, union ButtonCode code) { @@ -120,7 +121,7 @@ static void input_bind_code_to_action(InputState *input, static void input_unbind_code_from_action(InputState *input, - char *action_name, + char const *action_name, ButtonSource source, union ButtonCode code) { @@ -193,6 +194,9 @@ void input_state_update(InputState *input) { SDL_GetRelativeMouseState(&input->mouse_relative_position.x, &input->mouse_relative_position.y); + ctx.game.mouse_window_position = input->mouse_window_position; + ctx.game.mouse_relative_position = input->mouse_relative_position; + for (size_t i = 0; i < shlenu(input->action_hash); ++i) { Action *action = &input->action_hash[i].value; update_action_pressed_state(input, action); @@ -200,76 +204,82 @@ void input_state_update(InputState *input) { } -void input_bind_action_scancode(InputState *input, - char *action_name, - Scancode scancode) +void input_bind_action_control(char const *action_name, + Control control) { - input_bind_code_to_action(input, - action_name, - BUTTON_SOURCE_KEYBOARD_PHYSICAL, - (union ButtonCode) { .scancode = scancode }); -} + SDL_assert_always(action_name); - -void input_unbind_action_scancode(InputState *input, - char *action_name, - Scancode scancode) -{ - input_unbind_code_from_action(input, + if (CONTROL_SCANCODE_START <= control && control < CONTROL_SCANCODE_LIMIT) + input_bind_code_to_action(&ctx.input, action_name, BUTTON_SOURCE_KEYBOARD_PHYSICAL, - (union ButtonCode) { .scancode = scancode }); -} + (union ButtonCode) { .scancode = (SDL_Scancode)control }); - -void input_bind_action_mouse(InputState *input, - char *action_name, - uint8_t mouse_button) -{ - input_bind_code_to_action(input, - action_name, - BUTTON_SOURCE_MOUSE, - (union ButtonCode) { .mouse_button = mouse_button}); -} - - -void input_unbind_action_mouse(InputState *input, - char *action_name, - uint8_t mouse_button) -{ - input_unbind_code_from_action(input, + else if (CONTROL_MOUSECODE_START <= control && control < CONTROL_MOUSECODE_LIMIT) { + uint8_t const mouse_button = (uint8_t)(control - CONTROL_MOUSECODE_START); + input_bind_code_to_action(&ctx.input, action_name, BUTTON_SOURCE_MOUSE, - (union ButtonCode) { .mouse_button = mouse_button}); + (union ButtonCode) { .mouse_button = SDL_BUTTON(mouse_button)}); + } else + log_warn("(%s) Invalid control value given: %i.", __func__, control); } -void input_add_action(InputState *input, char *action_name) { - if (shgeti(input->action_hash, action_name) >= 0) { +void input_unbind_action_control(char const *action_name, + Control control) +{ + SDL_assert_always(action_name); + + if (CONTROL_SCANCODE_START <= control && control < CONTROL_SCANCODE_LIMIT) + input_unbind_code_from_action(&ctx.input, + action_name, + BUTTON_SOURCE_KEYBOARD_PHYSICAL, + (union ButtonCode) { .scancode = (SDL_Scancode)control }); + + else if (CONTROL_MOUSECODE_START <= control && control < CONTROL_MOUSECODE_LIMIT) { + uint8_t const mouse_button = (uint8_t)(control - CONTROL_MOUSECODE_START); + input_unbind_code_from_action(&ctx.input, + action_name, + BUTTON_SOURCE_MOUSE, + (union ButtonCode) { .mouse_button = SDL_BUTTON(mouse_button)}); + } else + log_warn("(%s) Invalid control value given: %i.", __func__, control); +} + + +void input_add_action(char const *action_name) { + SDL_assert_always(action_name); + + if (shgeti(ctx.input.action_hash, action_name) >= 0) { log_warn("(%s) Action \"%s\" is already registered.", __func__, action_name); return; } Action new_action = { 0 }; new_action.bindings = ccalloc(ctx.keybind_slots, sizeof *new_action.bindings); - shput(input->action_hash, action_name, new_action); + shput(ctx.input.action_hash, action_name, new_action); } -void input_delete_action(InputState *input, char *action_name) { - ActionHashItem *action = shgetp_null(input->action_hash, action_name); +void input_delete_action(char const *action_name) { + SDL_assert_always(action_name); + + ActionHashItem *action = shgetp_null(ctx.input.action_hash, action_name); if (action == NULL) { log_warn("(%s) Action \"%s\" is not registered.", __func__, action_name); return; } SDL_free(action->value.bindings); - shdel(input->action_hash, action_name); + shdel(ctx.input.action_hash, action_name); } -bool input_is_action_pressed(InputState *input, char *action_name) { - ActionHashItem *action = shgetp_null(input->action_hash, action_name); +bool input_is_action_pressed(char const *action_name) { + SDL_assert_always(action_name); + + ActionHashItem *action = shgetp_null(ctx.input.action_hash, action_name); if (action == NULL) { log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); return false; @@ -278,8 +288,10 @@ bool input_is_action_pressed(InputState *input, char *action_name) { } -bool input_is_action_just_pressed(InputState *input, char *action_name) { - ActionHashItem *action = shgetp_null(input->action_hash, action_name); +bool input_is_action_just_pressed(char const *action_name) { + SDL_assert_always(action_name); + + ActionHashItem *action = shgetp_null(ctx.input.action_hash, action_name); if (action == NULL) { log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); return false; @@ -288,8 +300,10 @@ bool input_is_action_just_pressed(InputState *input, char *action_name) { } -bool input_is_action_just_released(InputState *input, char *action_name) { - ActionHashItem *action = shgetp_null(input->action_hash, action_name); +bool input_is_action_just_released(char const *action_name) { + SDL_assert_always(action_name); + + ActionHashItem *action = shgetp_null(ctx.input.action_hash, action_name); if (action == NULL) { log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); return false; @@ -298,8 +312,10 @@ bool input_is_action_just_released(InputState *input, char *action_name) { } -Vec2 input_get_action_position(InputState *input, char *action_name) { - ActionHashItem *action = shgetp_null(input->action_hash, action_name); +Vec2 input_get_action_position(char const *action_name) { + SDL_assert_always(action_name); + + ActionHashItem *action = shgetp_null(ctx.input.action_hash, action_name); if (action == NULL) { log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); return (Vec2) { 0 }; @@ -309,15 +325,13 @@ Vec2 input_get_action_position(InputState *input, char *action_name) { } -void input_set_mouse_captured(InputState *input, bool enabled) { - (void)input; - /* TODO: returns -1 if not supported, but like... do we care? */ - SDL_SetRelativeMouseMode(enabled); +void input_set_mouse_captured(bool enabled) { + if (SDL_SetRelativeMouseMode(enabled) != 0) + log_warn("(%s) Mouse capture isn't supported.", __func__); } -bool input_is_mouse_captured(InputState *input) { - (void)input; +bool input_is_mouse_captured(void) { return SDL_GetRelativeMouseMode(); } diff --git a/src/twn_input_c.h b/src/twn_input_c.h index 72f1de7..a96c704 100644 --- a/src/twn_input_c.h +++ b/src/twn_input_c.h @@ -1,5 +1,5 @@ -#ifndef INPUT_INTERNAL_API_H -#define INPUT_INTERNAL_API_H +#ifndef TWN_INPUT_C_H +#define TWN_INPUT_C_H #include "twn_input.h" #include "twn_vec.h" @@ -15,6 +15,15 @@ union ButtonCode { }; +typedef enum ButtonSource { + BUTTON_SOURCE_NOT_SET, + BUTTON_SOURCE_KEYBOARD_PHYSICAL, + BUTTON_SOURCE_KEYBOARD_CHARACTER, + BUTTON_SOURCE_GAMEPAD, + BUTTON_SOURCE_MOUSE, +} ButtonSource; + + /* an input to which an action is bound */ /* it is not limited to literal buttons */ typedef struct Button { @@ -23,6 +32,45 @@ typedef struct Button { } Button; +/* represents the collective state of a group of buttons */ +/* that is, changes in the states of any of the bound buttons will affect it */ +typedef struct Action { + size_t num_bindings; + + /* if you bind more than the number set in the configuration file */ + /* it forgets the first Button to add the new one at the end */ + Button *bindings; + + Vec2 position; /* set if applicable, e.g. mouse click */ + bool is_pressed; + bool just_changed; +} Action; + + +typedef struct ActionHashItem { + char *key; + Action value; +} ActionHashItem; + + +typedef struct InputState { + const uint8_t *keyboard_state; /* array of booleans indexed by scancode */ + ActionHashItem *action_hash; + Vec2i mouse_window_position; + Vec2i mouse_relative_position; + uint32_t mouse_state; /* SDL mouse button bitmask */ + ButtonSource last_active_source; + bool is_anything_just_pressed; + bool mouse_captured; +} InputState; + + +void input_state_init(InputState *input); + +void input_state_deinit(InputState *input); + +void input_state_update(InputState *input); + void input_reset_state(InputState *input); #endif diff --git a/src/twn_loop.c b/src/twn_loop.c index 38f77fc..77e2322 100644 --- a/src/twn_loop.c +++ b/src/twn_loop.c @@ -188,7 +188,7 @@ static void main_loop(void) { poll_events(); - input_state_update(&ctx.game.input); + input_state_update(&ctx.input); game_object_tick(); @@ -634,7 +634,7 @@ static bool initialize(void) { ctx.keybind_slots = datum_keybind_slots.u.i; } } - input_state_init(&ctx.game.input); + input_state_init(&ctx.input); /* scripting */ /* @@ -657,7 +657,7 @@ static void clean_up(void) { scripting_deinit(ctx); */ - input_state_deinit(&ctx.game.input); + input_state_deinit(&ctx.input); text_cache_deinit(&ctx.text_cache); textures_cache_deinit(&ctx.texture_cache); @@ -675,7 +675,7 @@ static void clean_up(void) { static void reset_state(void) { - input_reset_state(&ctx.game.input); + input_reset_state(&ctx.input); textures_reset_state(); }