#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" #include "../common/hashmap.h" #include "../common/variant.h" #include "../common/parser.h" 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 struct Hashmap* key_bindings = 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); key_bindings = hashmap_new(); /* Default keys for fallback */ struct Key_Binding forward_keys = {KEY_W, KMOD_NONE, KEY_UP, KMOD_NONE, KS_INACTIVE}; struct Key_Binding backward_keys = {KEY_S, KMOD_NONE, KEY_DOWN, KMOD_NONE, KS_INACTIVE}; struct Key_Binding up_keys = {KEY_Q, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding down_keys = {KEY_E, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding left_keys = {KEY_A, KMOD_NONE, KEY_LEFT, KMOD_NONE, KS_INACTIVE}; struct Key_Binding right_keys = {KEY_D, KMOD_NONE, KEY_RIGHT, KMOD_NONE, KS_INACTIVE}; struct Key_Binding turn_right_keys = {KEY_L, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding turn_left_keys = {KEY_J, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding turn_up_keys = {KEY_I, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding turn_down_keys = {KEY_K, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding sprint_keys = {KEY_LSHIFT, KMOD_NONE, KEY_RSHIFT, KMOD_NONE, KS_INACTIVE}; struct Key_Binding ed_toggle_keys = {KEY_F1, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding win_fullscr_keys = {KEY_F11, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding win_max_keys = {KEY_F12, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; struct Key_Binding reload_game_keys = {KEY_F5, KMOD_NONE, KEY_NONE, KMOD_NONE, KS_INACTIVE}; input_map_create("Move_Forward", forward_keys); input_map_create("Move_Backward", backward_keys); input_map_create("Move_Up", up_keys); input_map_create("Move_Down", down_keys); input_map_create("Move_Left", left_keys); input_map_create("Move_Right", right_keys); input_map_create("Turn_Right", turn_right_keys); input_map_create("Turn_Left", turn_left_keys); input_map_create("Turn_Up", turn_up_keys); input_map_create("Turn_Down", turn_down_keys); input_map_create("Sprint", sprint_keys); input_map_create("Editor_Toggle", ed_toggle_keys); input_map_create("Window_Fullscreen", win_fullscr_keys); input_map_create("Window_Maximize", win_max_keys); input_map_create("Reload_Game_Lib", reload_game_keys); if(!input_keybinds_load("keybindings.symtres", DIRT_USER)) { log_error("input:init", "Failed to load keybindings"); log_message("Reverting to default keybindings"); if(!input_keybinds_load("keybindings.symtres", DIRT_INSTALL)) { log_error("input:init", "Failed to load default keybindings"); input_keybinds_save("keybindings.symtres", DIRT_INSTALL); } input_keybinds_save("keybindings.symtres", DIRT_USER); } } void input_cleanup(void) { char* key = NULL; struct Variant* value = NULL; HASHMAP_FOREACH(key_bindings, key, value) { free(value->val_voidptr); } hashmap_free(key_bindings); } bool input_keybinds_load(const char* filename, int directory_type) { FILE* key_file = platform->file.open(directory_type, filename, "rb"); if(!key_file) { log_error("input:keybinds_load", "Could not open %s", filename); return false; } struct Parser* parser = parser_load_objects(key_file, filename); if(!parser) { log_error("input:keybinds_load", "Failed to parse %s", filename); fclose(key_file); return false; } for(int i = 0; i < array_len(parser->objects); i++) { struct Parser_Object* object = &parser->objects[i]; const char* name_temp = NULL; struct Key_Binding key_binding = { .state = KS_INACTIVE, .key_primary = KEY_NONE, .mods_primary = KMD_NONE, .key_secondary = KEY_NONE, .mods_secondary = KMD_NONE }; if(hashmap_value_exists(object->data, "name")) name_temp = hashmap_str_get(object->data, "name"); if(hashmap_value_exists(object->data, "key_primary")) { int key = platform->key_from_name(hashmap_str_get(object->data, "key_primary")); if(key != KEY_UNKNOWN) { key_binding.key_primary = key; } } if(hashmap_value_exists(object->data, "key_secondary")) { int key = platform->key_from_name(hashmap_str_get(object->data, "key_secondary")); if(key != KEY_UNKNOWN) { key_binding.key_secondary = key; } } if(hashmap_value_exists(object->data, "mods_primary_ctrl")) { if(hashmap_bool_get(object->data, "mods_primary_ctrl")) key_binding.mods_primary |= KMD_CTRL; } if(hashmap_value_exists(object->data, "mods_primary_shift")) { if(hashmap_bool_get(object->data, "mods_primary_shift")) key_binding.mods_primary |= KMD_SHIFT; } if(hashmap_value_exists(object->data, "mods_primary_alt")) { if(hashmap_bool_get(object->data, "mods_primary_alt")) key_binding.mods_primary |= KMD_ALT; } if(hashmap_value_exists(object->data, "mods_secondary_ctrl")) { if(hashmap_bool_get(object->data, "mods_secondary_ctrl")) key_binding.mods_secondary |= KMD_CTRL; } if(hashmap_value_exists(object->data, "mods_secondary_shift")) { if(hashmap_bool_get(object->data, "mods_secondary_shift")) key_binding.mods_secondary = KMD_SHIFT; } if(hashmap_value_exists(object->data, "mods_secondary_alt")) { if(hashmap_bool_get(object->data, "mods_secondary_alt")) key_binding.mods_secondary = KMD_ALT; } input_map_create(name_temp, key_binding); } parser_free(parser); fclose(key_file); return true; } bool input_keybinds_save(const char* filename, int directory_type) { struct Parser* parser = parser_new(); if(!parser) { log_error("input:keybinds_save", "Could not create Parser"); return false; } char* key = NULL; struct Variant* value = NULL; HASHMAP_FOREACH(key_bindings, key, value) { struct Key_Binding* key_binding = (struct Key_Binding*)value->val_voidptr; struct Parser_Object* object = parser_object_new(parser, PO_KEY); if(!object) { log_error("input:keybinds_save", "Failed to create Parser_object for Map '%s'", key); continue; } bool mods_primary_ctrl = ((key_binding->mods_primary & KMD_CTRL) == KMD_CTRL) ? true : false; bool mods_primary_shift = ((key_binding->mods_primary & KMD_SHIFT) == KMD_SHIFT) ? true : false; bool mods_primary_alt = ((key_binding->mods_primary & KMD_ALT) == KMD_ALT) ? true : false; bool mods_secondary_ctrl = ((key_binding->mods_secondary & KMD_CTRL) == KMD_CTRL) ? true : false; bool mods_secondary_shift = ((key_binding->mods_secondary & KMD_SHIFT) == KMD_SHIFT) ? true : false; bool mods_secondary_alt = ((key_binding->mods_secondary & KMD_ALT) == KMD_ALT) ? true : false; hashmap_str_set(object->data, "name", key); hashmap_str_set(object->data, "key_primary", key_binding->key_primary == KEY_NONE ? "NONE" : platform->key_name_get(key_binding->key_primary)); hashmap_bool_set(object->data, "mods_primary_ctrl", mods_primary_ctrl); hashmap_bool_set(object->data, "mods_primary_shift", mods_primary_shift); hashmap_bool_set(object->data, "mods_primary_alt", mods_primary_alt); hashmap_str_set(object->data, "key_secondary", key_binding->key_secondary == KEY_NONE ? "NONE" : platform->key_name_get(key_binding->key_secondary)); hashmap_bool_set(object->data, "mods_secondary_ctrl", mods_secondary_ctrl); hashmap_bool_set(object->data, "mods_secondary_shift", mods_secondary_shift); hashmap_bool_set(object->data, "mods_secondary_alt", mods_secondary_alt); } log_message("Keybindings saved to %s", filename); bool write_success = false; FILE* key_file = platform->file.open(directory_type, filename, "w"); if(!key_file) { log_error("input:keybinds_save", "Could not open %s", filename); } else { if(parser_write_objects(parser, key_file, filename)) { log_message("Input Maps written to %s", filename); write_success = true; } else { log_error("Failed to write Input Maps to %s", filename); } } parser_free(parser); fclose(key_file); return write_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; char* map_key = NULL; struct Variant* value = NULL; HASHMAP_FOREACH(key_bindings, map_key, value) { struct Key_Binding* key_binding = (struct Key_Binding*)value->val_voidptr; //Check with primary key if(key_binding->key_primary == key && (key_binding->mods_primary & mods) == key_binding->mods_primary) { key_binding->state = state; break; } //If not, then check with secondary key if(key_binding->key_secondary == key && (key_binding->mods_secondary & mods) == key_binding->mods_secondary) { key_binding->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* name, int state) { struct Key_Binding* key_binding = (struct Key_Binding*)hashmap_ptr_get(key_bindings, name); if(!key_binding) { log_error("input:map_state_get", "Map '%s' not found", name); return false; } return (key_binding->state == state); } bool input_map_create(const char* name, struct Key_Binding key_combination) { //Check if a key map already exists if(hashmap_value_exists(key_bindings, name)) { log_warning("Removing existing Map '%s' and replacing with new one", name); input_map_remove(name); } struct Key_Binding* new_keybinding = malloc(sizeof(*new_keybinding)); if(!new_keybinding) { log_error("input:map_create", "Out of memory"); return false; } memcpy(new_keybinding, &key_combination, sizeof(key_combination)); hashmap_ptr_set(key_bindings, name, new_keybinding); log_message("Created new input map '%s'", name); return true; } 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_update(void) { struct Variant* value = NULL; char* key = NULL; HASHMAP_FOREACH(key_bindings, key, value) { struct Key_Binding* key_binding = (struct Key_Binding*)value->val_voidptr; if(key_binding->state == KS_RELEASED) key_binding->state = KS_INACTIVE; } } bool input_map_remove(const char* name) { assert(name); if(hashmap_value_exists(key_bindings, name)) { struct Key_Binding* current_key = (struct Key_Binding*)hashmap_ptr_get(key_bindings, name); free(current_key); hashmap_value_remove(key_bindings, name); } else { log_error("input:map_remove", "Map '%s' not found", name); return false; } return true; } bool input_map_keys_set(const char* name, struct Key_Binding key_combination) { assert(name); struct Key_Binding* existing_combination = (struct Key_Binding*)hashmap_ptr_get(key_bindings, name); if(!existing_combination) { log_error("input:map_keys_set", "Map '%s' not found", name); return false; } memcpy(existing_combination, &key_combination, sizeof(key_combination)); existing_combination->state = KS_INACTIVE; return true; } 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 Key_Binding* map = &key_bindings[index]; // map->name = str_new(new_name); // success = true; //} //if(!success) log_error("input:map_name_set", "Map %s not found", name); //return success; return false; } 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); }