twn_input: singleton rework, twn_control.h and fixes
This commit is contained in:
		| @@ -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"); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -19,7 +19,6 @@ typedef struct State | ||||
| { | ||||
|     Bunny bunnies[MAX_BUNNIES]; | ||||
|     int bunniesCount; | ||||
|     InputState mouse_state; | ||||
| } State; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -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(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|   | ||||
| @@ -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(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|   | ||||
| @@ -8,12 +8,20 @@ | ||||
| #include <stdint.h> | ||||
|  | ||||
|  | ||||
| /* 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; | ||||
|   | ||||
							
								
								
									
										433
									
								
								include/twn_control.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										433
									
								
								include/twn_control.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,433 @@ | ||||
| #ifndef TWN_CONTROL_H | ||||
| #define TWN_CONTROL_H | ||||
|  | ||||
| /* | ||||
|   Simple DirectMedia Layer | ||||
|   Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> | ||||
|  | ||||
|   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 | ||||
| @@ -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 <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
|  | ||||
| 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 | ||||
|   | ||||
| @@ -1,420 +0,0 @@ | ||||
| #ifndef TWN_SCANCODE_H | ||||
| #define TWN_SCANCODE_H | ||||
|  | ||||
| /* | ||||
|   Simple DirectMedia Layer | ||||
|   Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> | ||||
|  | ||||
|   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 | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										116
									
								
								src/twn_input.c
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								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 <SDL2/SDL.h> | ||||
| @@ -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, | ||||
|     SDL_assert_always(action_name); | ||||
|  | ||||
|     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 }); | ||||
|  | ||||
|     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 = SDL_BUTTON(mouse_button)}); | ||||
|     } else | ||||
|         log_warn("(%s) Invalid control value given: %i.", __func__, control); | ||||
| } | ||||
|  | ||||
|  | ||||
| void input_unbind_action_scancode(InputState *input, | ||||
|                                   char *action_name, | ||||
|                                   Scancode scancode) | ||||
| void input_unbind_action_control(char const *action_name, | ||||
|                                  Control control) | ||||
| { | ||||
|     input_unbind_code_from_action(input, | ||||
|     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 = 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, | ||||
|     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 = mouse_button}); | ||||
|                                       (union ButtonCode) { .mouse_button = SDL_BUTTON(mouse_button)}); | ||||
|     } else | ||||
|         log_warn("(%s) Invalid control value given: %i.", __func__, control); | ||||
| } | ||||
|  | ||||
|  | ||||
| void input_unbind_action_mouse(InputState *input, | ||||
|                                char *action_name, | ||||
|                                uint8_t mouse_button) | ||||
| { | ||||
|     input_unbind_code_from_action(input, | ||||
|                                   action_name, | ||||
|                                   BUTTON_SOURCE_MOUSE, | ||||
|                                   (union ButtonCode) { .mouse_button = mouse_button}); | ||||
| } | ||||
| void input_add_action(char const *action_name) { | ||||
|     SDL_assert_always(action_name); | ||||
|  | ||||
|  | ||||
| void input_add_action(InputState *input, char *action_name) { | ||||
|     if (shgeti(input->action_hash, action_name) >= 0) { | ||||
|     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(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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(); | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user