#include #include #include #include "input.h" #include "../common/array.h" #include "../common/log.h" #include "gui.h" #include "../common/string_utils.h" #include "../common/common.h" struct Input_Map { char* name; struct Key_Combination* keys; int state; }; static void input_on_key(int key, int scancode, int state, int repeat, int mod_ctrl, int mod_shift, int mod_alt); static void input_on_mousebutton(int button, int state, int x, int y, int8 num_clicks); static void input_on_mousemotion(int x, int y, int xrel, int yrel); static void input_on_mousewheel(int x, int y); static int map_find(const char* name); static struct Input_Map* input_map_list = NULL; void input_init(void) { platform->keyboard_callback_set(&input_on_key); platform->mousebutton_callback_set(&input_on_mousebutton); platform->mousemotion_callback_set(&input_on_mousemotion); platform->mousewheel_callback_set(&input_on_mousewheel); input_map_list = array_new(struct Input_Map); if(!input_keybinds_load("keybindings.cfg", DT_USER)) { log_error("input:init", "Failed to load keybindings"); log_message("Reverting to default keybindings"); if(!input_keybinds_load("keybindings.cfg", DT_INSTALL)) { log_error("input:init", "Failed to load default keybindings"); } else { input_keybinds_save("keybindings.cfg"); } } /* struct Key_Combination forward_keys[2] = {{KEY_W, KMD_NONE}, {KEY_UP, KMD_ALT | KMD_SHIFT}}; */ /* struct Key_Combination backward_keys[2] = {{KEY_S, KMD_NONE}, {KEY_DOWN, KMD_NONE}}; */ /* struct Key_Combination up_keys[2] = {KEY_Q}; */ /* struct Key_Combination down_keys[2] = {KEY_E}; */ /* struct Key_Combination left_keys[2] = {KEY_A, KEY_LEFT}; */ /* struct Key_Combination right_keys[2] = {KEY_D, KEY_RIGHT}; */ /* struct Key_Combination turn_right_keys[1] = {KEY_L}; */ /* struct Key_Combination turn_left_keys[1] = {KEY_J}; */ /* struct Key_Combination turn_up_keys[1] = {KEY_I}; */ /* struct Key_Combination turn_down_keys[1] = {KEY_K}; */ /* struct Key_Combination sprint_keys[2] = {KEY_LSHIFT, KEY_RSHIFT}; */ /* struct Key_Combination recompute_keys[2] = {KEY_F5, KEY_H}; */ /* struct Key_Combination ed_toggle_keys[1] = {KEY_F1}; */ /* struct Key_Combination win_fullscr_keys[1] = {KEY_F11}; */ /* struct Key_Combination win_max_keys[1] = {KEY_F12}; */ /* input_map_create("Move_Forward", forward_keys, 2); */ /* input_map_create("Move_Backward", backward_keys, 2); */ /* input_map_create("Move_Up", up_keys, 1); */ /* input_map_create("Move_Down", down_keys, 1); */ /* input_map_create("Move_Left", left_keys, 2); */ /* input_map_create("Move_Right", right_keys, 2); */ /* input_map_create("Turn_Right", turn_right_keys, 1); */ /* input_map_create("Turn_Left", turn_left_keys, 1); */ /* input_map_create("Turn_Up", turn_up_keys, 1); */ /* input_map_create("Turn_Down", turn_down_keys, 1); */ /* input_map_create("Sprint", sprint_keys, 2); */ /* input_map_create("Recompute", recompute_keys, 2); */ /* input_map_create("Editor_Toggle", ed_toggle_keys, 1); */ /* input_map_create("Window_Fullscreen", win_fullscr_keys, 1); */ /* input_map_create("Window_Maximize", win_max_keys, 1); */ } void input_cleanup(void) { for(int i = 0; i < array_len(input_map_list); i++) { struct Input_Map* map = &input_map_list[i]; if(map->name) free(map->name); array_free(map->keys); } array_free(input_map_list); input_map_list = NULL; } bool input_keybinds_load(const char* filename, int directory_type) { bool success = false; const int MAX_KEYBIND_LEN = 128; const int MAX_LINE_LEN = 512; FILE* config_file = platform->file.open(directory_type, filename, "r"); if(!config_file) { log_error("input:keybinds_load", "Could not open %s", filename); return success; } /* Read line by line, ignore comments */ char key_str[MAX_KEYBIND_LEN]; char line_buffer[MAX_LINE_LEN]; memset(key_str, '\0', MAX_KEYBIND_LEN); memset(line_buffer, '\0', MAX_LINE_LEN); int current_line = 0; while(fgets(line_buffer, MAX_LINE_LEN - 1, config_file)) { current_line++; line_buffer[strcspn(line_buffer, "\r\n")] = '\0'; if(line_buffer[0] == '#' || strlen(line_buffer) == 0) continue; //log_message("Line : %s", line_buffer); memset(key_str, '\0', MAX_KEYBIND_LEN); char* value_str = strstr(line_buffer, ":"); if(!value_str) { log_warning("Malformed value in config file %s, line %d", filename, current_line); continue; } value_str++; /* Ignore the colon(:) and set the pointer after it */ if(sscanf(line_buffer, " %1024[^: ] : %*s", key_str) != 1) { log_warning("Unable to read key in keybindings file %s, line %d", filename, current_line); continue; } char* val = strtok(value_str, ","); if(!val) { log_warning("Unable to parse keys for keybinding %s in file %s, line %d", key_str, filename, current_line); continue; } while(val) { //log_message("Key read : %s", val); /* Check if there are any Modifiers */ int modifiers = KMD_NONE; char* keys = strstr(val, "-"); char* start_loc = val; const int max_key_str_len = 20; char key_name[max_key_str_len]; int skip_to_next = 0; while(keys) { memset(key_name, '\0', max_key_str_len); strncpy(key_name, start_loc, (keys - start_loc)); //log_message("key_name : %s", key_name); int key_modifier = platform->key_from_name(key_name); if(key_modifier == KEY_UNKNOWN) { log_warning("Unrecognized key %s in keybindings file %s, at line %d", key_name, filename, current_line); skip_to_next = 1; break; } switch(key_modifier) { case KEY_LSHIFT: case KEY_RSHIFT: modifiers |= KMD_SHIFT; break; case KEY_LCTRL: case KEY_RCTRL: modifiers |= KMD_CTRL; break; case KEY_LALT: case KEY_RALT: modifiers |= KMD_ALT; break; }; ++keys; start_loc = keys; keys = strstr(keys, "-"); } if(skip_to_next) { val = strtok(NULL, ","); continue; } /* Copy the last key after the hyphen */ strncpy(key_name, start_loc, max_key_str_len); int key = platform->key_from_name(key_name); if(key == KEY_UNKNOWN) { log_warning("Unrecognized key %s in keybindings file %s, at line %d", key_name, filename, current_line); val = strtok(NULL, ","); continue; } struct Key_Combination key_comb = { .key = key, .mods = modifiers}; input_map_create(key_str, &key_comb, 1); val = strtok(NULL, ","); } } success = true; fclose(config_file); return success; } bool input_keybinds_save(const char* filename) { bool success = false; FILE* config_file = platform->file.open(DT_USER, filename, "w"); if(!config_file) { log_error("input:keybinds_save", "Could not open %s", filename); return success; } for(int i = 0; i < array_len(input_map_list); i++) { struct Input_Map* map = &input_map_list[i]; fprintf(config_file, "%s : ", map->name); for(int j = 0; j < array_len(map->keys); j++) { if(j != 0) fprintf(config_file, ", "); struct Key_Combination* key_comb = &map->keys[j]; if((key_comb->mods & KMD_ALT) == KMD_ALT) fprintf(config_file, "%s-", platform->key_name_get(KEY_LALT)); if((key_comb->mods & KMD_SHIFT) == KMD_SHIFT) fprintf(config_file, "%s-", platform->key_name_get(KEY_LSHIFT)); if((key_comb->mods & KMD_CTRL) == KMD_CTRL) fprintf(config_file, "%s-", platform->key_name_get(KEY_LCTRL)); fprintf(config_file, "%s", platform->key_name_get(key_comb->key)); } fprintf(config_file, "\n"); } fclose(config_file); log_message("Keybindings saved to %s", filename); success = true; return success; } void input_on_mousemotion(int x, int y, int xrel, int yrel) { /* TODO: This is temporary. After proper event loop is added this code should not be here */ gui_handle_mousemotion_event(x, y, xrel, yrel); } void input_on_mousewheel(int x, int y) { /* TODO: This is temporary. After proper event loop is added this code should not be here */ gui_handle_mousewheel_event(x, y); } void input_mouse_pos_get(int* xpos, int* ypos) { assert(xpos && ypos); platform->mouse_position_get(xpos, ypos); } void input_mouse_pos_set(int xpos, int ypos) { platform->mouse_global_position_set(xpos, ypos); } void input_on_key(int key, int scancode, int state, int repeat, int mod_ctrl, int mod_shift, int mod_alt) { int mods = KMD_NONE; if(mod_ctrl) mods |= KMD_CTRL; if(mod_shift) mods |= KMD_SHIFT; if(mod_alt) mods |= KMD_ALT; for(int i = 0; i < array_len(input_map_list); i++) { struct Input_Map* map = &input_map_list[i]; for(int j = 0; j < array_len(map->keys); j++) { /* if(map->state == KS_PRESSED && */ /* state == KS_RELEASED && */ /* ((map->keys[j].mods & mods) == map->keys[j].mods)) */ /* { */ /* map->state = state; */ /* } */ if(map->keys[j].key == key && ((map->keys[j].mods & mods) == map->keys[j].mods)) { map->state = state; break; } } } /* TODO: This is temporary. After proper event loop is added this code should not be here */ gui_handle_keyboard_event(key, state, mod_ctrl, mod_shift); } void input_on_mousebutton(int button, int state, int x, int y, int8 num_clicks) { /* Probably add 'mouse maps', same as input maps for keyboard but with buttons Do we even need that? */ /* TODO: This is temporary. After proper event loop is added this code should not be here */ gui_handle_mousebutton_event(button, state, x, y); } void input_mouse_mode_set(enum Mouse_Mode mode) { platform->mouse_relative_mode_set(mode == MM_NORMAL ? 0 : 1); } bool input_map_state_get(const char* map_name, int state) { int current_state = KS_INACTIVE; for(int i = 0; i < array_len(input_map_list); i++) { struct Input_Map* map = &input_map_list[i]; if(strcmp(map->name, map_name) == 0) { current_state = map->state; break; } } bool result = false; if(current_state == state) { result = true; } return result; } bool input_is_key_pressed(int key) { return platform->is_key_pressed(key); } bool input_mousebutton_state_get(uint button, int state_type) { int current_state = platform->mousebutton_state_get(button); return state_type == current_state ? true : false; } void input_map_create(const char* name, struct Key_Combination* keys, int num_keys) { assert(name && keys && num_keys > 0); int index = map_find(name); if(index > -1) { struct Input_Map* map = &input_map_list[index]; for(int i = 0; i < num_keys; i++) { struct Key_Combination* new_comb = array_grow(map->keys, struct Key_Combination); *new_comb = keys[i]; log_message("Added new Key combination to input map : %s", name); } } else { struct Input_Map* new_map = array_grow(input_map_list, struct Input_Map); new_map->name = str_new(name); new_map->keys = array_new_cap(struct Key_Combination, num_keys); new_map->state = KS_INACTIVE; for(int i = 0; i < num_keys; i++) new_map->keys[i] = keys[i]; log_message("Created Input Map : %s", name); } } void input_update(void) { for(int i = 0; i < array_len(input_map_list); i++) { struct Input_Map* map = &input_map_list[i]; if(map->state == KS_RELEASED) map->state = KS_INACTIVE; } } bool input_map_remove(const char* name) { assert(name); bool success = false; int index = map_find(name); if(index > -1) { array_remove_at(input_map_list, (int)index); success = true; } if(!success) log_error("input:map_remove", "Map %s not found", name); return success; } bool input_map_keys_set(const char* name, struct Key_Combination* keys, int num_keys) { assert(name && keys && num_keys > 0); bool success = false; int index = map_find(name); if(index > -1) { struct Input_Map* map = &input_map_list[index]; if(array_len(map->keys) != num_keys) array_reset(map->keys, num_keys); for(int i = 0; i < num_keys; i++) map->keys[i] = keys[i]; map->state = KS_INACTIVE; success = true; } if(!success) log_error("input:map_keys_set", "Map %s not found", name); return success; } bool input_map_name_set(const char* name, const char* new_name) { assert(name && new_name); bool success = false; int index = map_find(name); if(index > -1) { struct Input_Map* map = &input_map_list[index]; map->name = str_new(new_name); success = true; } if(!success) log_error("input:map_name_set", "Map %s not found", name); return success; } int map_find(const char* name) { int index = -1; for(int i = 0; i < array_len(input_map_list); i++) { struct Input_Map* map = &input_map_list[i]; if(strcmp(name, map->name) == 0) { index = i; break; } } return index; } int input_mouse_mode_get(void) { int mouse_mode = MM_NORMAL; if(platform->mouse_relative_mode_get()) mouse_mode = MM_RELATIVE; return mouse_mode; } void input_mouse_delta_get(int* xpos, int* ypos) { platform->mouse_delta_get(xpos, ypos); }