|
|
@ -7,22 +7,16 @@ |
|
|
|
#include "gui.h" |
|
|
|
#include "gui.h" |
|
|
|
#include "../common/string_utils.h" |
|
|
|
#include "../common/string_utils.h" |
|
|
|
#include "../common/common.h" |
|
|
|
#include "../common/common.h" |
|
|
|
|
|
|
|
#include "../common/hashmap.h" |
|
|
|
|
|
|
|
#include "../common/variant.h" |
|
|
|
#include "../common/parser.h" |
|
|
|
#include "../common/parser.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_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_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_mousemotion(int x, int y, int xrel, int yrel); |
|
|
|
static void input_on_mousewheel(int x, int y); |
|
|
|
static void input_on_mousewheel(int x, int y); |
|
|
|
static int map_find(const char* name); |
|
|
|
|
|
|
|
static void on_parser_assign(const char* key, const char* value, const char* filename, int current_line); |
|
|
|
static struct Hashmap* key_bindings = NULL; |
|
|
|
static struct Input_Map* input_map_list = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void input_init(void) |
|
|
|
void input_init(void) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -31,192 +25,227 @@ void input_init(void) |
|
|
|
platform->mousemotion_callback_set(&input_on_mousemotion); |
|
|
|
platform->mousemotion_callback_set(&input_on_mousemotion); |
|
|
|
platform->mousewheel_callback_set(&input_on_mousewheel); |
|
|
|
platform->mousewheel_callback_set(&input_on_mousewheel); |
|
|
|
|
|
|
|
|
|
|
|
input_map_list = array_new(struct Input_Map); |
|
|
|
key_bindings = hashmap_new(); |
|
|
|
if(!input_keybinds_load("keybindings.cfg", DIRT_USER)) |
|
|
|
|
|
|
|
|
|
|
|
/* 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_error("input:init", "Failed to load keybindings"); |
|
|
|
log_message("Reverting to default keybindings"); |
|
|
|
log_message("Reverting to default keybindings"); |
|
|
|
if(!input_keybinds_load("keybindings.cfg", DIRT_INSTALL)) |
|
|
|
if(!input_keybinds_load("keybindings.symtres", DIRT_INSTALL)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
log_error("input:init", "Failed to load default keybindings"); |
|
|
|
log_error("input:init", "Failed to load default keybindings"); |
|
|
|
|
|
|
|
input_keybinds_save("keybindings.symtres", DIRT_INSTALL); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
input_keybinds_save("keybindings.cfg"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Default keys for fallback */ |
|
|
|
input_keybinds_save("keybindings.symtres", DIRT_USER); |
|
|
|
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 ed_toggle_keys[1] = {{KEY_F1}}; |
|
|
|
|
|
|
|
struct Key_Combination win_fullscr_keys[1] = {{KEY_F11}}; |
|
|
|
|
|
|
|
struct Key_Combination win_max_keys[1] = {{KEY_F12}}; |
|
|
|
|
|
|
|
struct Key_Combination reload_game_keys[1] = {{KEY_F5}}; |
|
|
|
|
|
|
|
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("Editor_Toggle", ed_toggle_keys, 1); |
|
|
|
|
|
|
|
input_map_create("Window_Fullscreen", win_fullscr_keys, 1); |
|
|
|
|
|
|
|
input_map_create("Window_Maximize", win_max_keys, 1); |
|
|
|
|
|
|
|
input_map_create("Reload_Game_Lib", reload_game_keys, 1); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void input_cleanup(void) |
|
|
|
void input_cleanup(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
for(int i = 0; i < array_len(input_map_list); i++) |
|
|
|
char* key = NULL; |
|
|
|
|
|
|
|
struct Variant* value = NULL; |
|
|
|
|
|
|
|
HASHMAP_FOREACH(key_bindings, key, value) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct Input_Map* map = &input_map_list[i]; |
|
|
|
free(value->val_voidptr); |
|
|
|
if(map->name) free(map->name); |
|
|
|
|
|
|
|
array_free(map->keys); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
array_free(input_map_list); |
|
|
|
|
|
|
|
input_map_list = NULL; |
|
|
|
hashmap_free(key_bindings); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void on_parser_assign(const char* key, const char* value, const char* filename, int current_line) |
|
|
|
bool input_keybinds_load(const char* filename, int directory_type) |
|
|
|
{ |
|
|
|
{ |
|
|
|
char* value_copy = str_new(value); |
|
|
|
FILE* key_file = platform->file.open(directory_type, filename, "rb"); |
|
|
|
//value_copy[strlen(value_copy) - 1] = '\0';
|
|
|
|
if(!key_file) |
|
|
|
char* val = strtok(value_copy, ","); |
|
|
|
|
|
|
|
if(!val) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
log_warning("Unable to parse keys for keybinding %s in file %s, line %d", key, filename, current_line); |
|
|
|
log_error("input:keybinds_load", "Could not open %s", filename); |
|
|
|
free(value_copy); |
|
|
|
return false; |
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while(val) |
|
|
|
struct Parser* parser = parser_load_objects(key_file, filename); |
|
|
|
|
|
|
|
if(!parser) |
|
|
|
{ |
|
|
|
{ |
|
|
|
#define max_key_str_len 20 |
|
|
|
log_error("input:keybinds_load", "Failed to parse %s", filename); |
|
|
|
/* Check if there are any Modifiers */ |
|
|
|
fclose(key_file); |
|
|
|
int modifiers = KMD_NONE; |
|
|
|
return false; |
|
|
|
char* keys = strstr(val, "-"); |
|
|
|
} |
|
|
|
char* start_loc = val; |
|
|
|
|
|
|
|
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)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int key_modifier = platform->key_from_name(key_name); |
|
|
|
for(int i = 0; i < array_len(parser->objects); i++) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct Parser_Object* object = &parser->objects[i]; |
|
|
|
|
|
|
|
|
|
|
|
if(key_modifier == KEY_UNKNOWN) |
|
|
|
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) |
|
|
|
{ |
|
|
|
{ |
|
|
|
log_warning("Unrecognized key %s in keybindings file %s, at line %d", key_name, filename, current_line); |
|
|
|
key_binding.key_primary = key; |
|
|
|
skip_to_next = true; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch(key_modifier) |
|
|
|
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) |
|
|
|
{ |
|
|
|
{ |
|
|
|
case KEY_LSHIFT: case KEY_RSHIFT: modifiers |= KMD_SHIFT; break; |
|
|
|
key_binding.key_secondary = key; |
|
|
|
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) |
|
|
|
if(hashmap_value_exists(object->data, "mods_primary_ctrl")) |
|
|
|
{ |
|
|
|
{ |
|
|
|
val = strtok(NULL, ","); |
|
|
|
if(hashmap_bool_get(object->data, "mods_primary_ctrl")) |
|
|
|
continue; |
|
|
|
key_binding.mods_primary |= KMD_CTRL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Copy the last key after the hyphen */ |
|
|
|
if(hashmap_value_exists(object->data, "mods_primary_shift")) |
|
|
|
strncpy(key_name, start_loc, max_key_str_len); |
|
|
|
|
|
|
|
int key_code = platform->key_from_name(key_name); |
|
|
|
|
|
|
|
if(key_code == KEY_UNKNOWN) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
log_warning("Unrecognized key %s in keybindings file %s, at line %d", key_name, filename, current_line); |
|
|
|
if(hashmap_bool_get(object->data, "mods_primary_shift")) |
|
|
|
val = strtok(NULL, ","); |
|
|
|
key_binding.mods_primary |= KMD_SHIFT; |
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct Key_Combination key_comb = { .key = key_code, .mods = modifiers}; |
|
|
|
if(hashmap_value_exists(object->data, "mods_primary_alt")) |
|
|
|
input_map_create(key, &key_comb, 1); |
|
|
|
{ |
|
|
|
|
|
|
|
if(hashmap_bool_get(object->data, "mods_primary_alt")) |
|
|
|
val = strtok(NULL, ","); |
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
free(value_copy); |
|
|
|
|
|
|
|
|
|
|
|
parser_free(parser); |
|
|
|
|
|
|
|
fclose(key_file); |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool input_keybinds_load(const char* filename, int directory_type) |
|
|
|
bool input_keybinds_save(const char* filename, int directory_type) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool success = false; |
|
|
|
struct Parser* parser = parser_new(); |
|
|
|
FILE* config_file = platform->file.open(directory_type, filename, "r"); |
|
|
|
if(!parser) |
|
|
|
if(!config_file) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
log_error("input:keybinds_load", "Could not open %s", filename); |
|
|
|
log_error("input:keybinds_save", "Could not create Parser"); |
|
|
|
return success; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(!parser_load(config_file, filename, &on_parser_assign, false, 0)) |
|
|
|
|
|
|
|
{ |
|
|
|
char* key = NULL; |
|
|
|
log_error("input:keybinds_load", "Failed to parse file %s", filename); |
|
|
|
struct Variant* value = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
HASHMAP_FOREACH(key_bindings, key, value) |
|
|
|
{ |
|
|
|
{ |
|
|
|
log_message("Loaded keybindings from %s", filename); |
|
|
|
struct Key_Binding* key_binding = (struct Key_Binding*)value->val_voidptr; |
|
|
|
success = true; |
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fclose(config_file); |
|
|
|
|
|
|
|
return success; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool input_keybinds_save(const char* filename) |
|
|
|
log_message("Keybindings saved to %s", filename); |
|
|
|
{ |
|
|
|
|
|
|
|
bool success = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FILE* config_file = platform->file.open(DIRT_USER, filename, "w"); |
|
|
|
bool write_success = false; |
|
|
|
if(!config_file) |
|
|
|
FILE* key_file = platform->file.open(directory_type, filename, "w"); |
|
|
|
|
|
|
|
if(!key_file) |
|
|
|
{ |
|
|
|
{ |
|
|
|
log_error("input:keybinds_save", "Could not open %s", filename); |
|
|
|
log_error("input:keybinds_save", "Could not open %s", filename); |
|
|
|
return success; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
for(int i = 0; i < array_len(input_map_list); i++) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
struct Input_Map* map = &input_map_list[i]; |
|
|
|
if(parser_write_objects(parser, key_file, filename)) |
|
|
|
fprintf(config_file, "%s : ", map->name); |
|
|
|
{ |
|
|
|
for(int j = 0; j < array_len(map->keys); j++) |
|
|
|
log_message("Input Maps written to %s", filename); |
|
|
|
|
|
|
|
write_success = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(j != 0) fprintf(config_file, ", "); |
|
|
|
log_error("Failed to write Input Maps to %s", filename); |
|
|
|
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"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
fprintf(config_file, "\n"); |
|
|
|
|
|
|
|
fclose(config_file); |
|
|
|
parser_free(parser); |
|
|
|
log_message("Keybindings saved to %s", filename); |
|
|
|
fclose(key_file); |
|
|
|
success = true; |
|
|
|
return write_success; |
|
|
|
return success; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void input_on_mousemotion(int x, int y, int xrel, int yrel) |
|
|
|
void input_on_mousemotion(int x, int y, int xrel, int yrel) |
|
|
@ -248,31 +277,34 @@ void input_on_key(int key, int scancode, int state, int repeat, int mod_ctrl, in |
|
|
|
if(mod_ctrl) mods |= KMD_CTRL; |
|
|
|
if(mod_ctrl) mods |= KMD_CTRL; |
|
|
|
if(mod_shift) mods |= KMD_SHIFT; |
|
|
|
if(mod_shift) mods |= KMD_SHIFT; |
|
|
|
if(mod_alt) mods |= KMD_ALT; |
|
|
|
if(mod_alt) mods |= KMD_ALT; |
|
|
|
for(int i = 0; i < array_len(input_map_list); i++) |
|
|
|
|
|
|
|
|
|
|
|
char* map_key = NULL; |
|
|
|
|
|
|
|
struct Variant* value = NULL; |
|
|
|
|
|
|
|
HASHMAP_FOREACH(key_bindings, map_key, value) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct Input_Map* map = &input_map_list[i]; |
|
|
|
struct Key_Binding* key_binding = (struct Key_Binding*)value->val_voidptr; |
|
|
|
for(int j = 0; j < array_len(map->keys); j++) |
|
|
|
//Check with primary key
|
|
|
|
|
|
|
|
if(key_binding->key_primary == key && (key_binding->mods_primary & mods) == key_binding->mods_primary) |
|
|
|
{ |
|
|
|
{ |
|
|
|
/* if(map->state == KS_PRESSED && */ |
|
|
|
key_binding->state = state; |
|
|
|
/* state == KS_RELEASED && */ |
|
|
|
break; |
|
|
|
/* ((map->keys[j].mods & mods) == map->keys[j].mods)) */ |
|
|
|
} |
|
|
|
/* { */ |
|
|
|
|
|
|
|
/* map->state = state; */ |
|
|
|
//If not, then check with secondary key
|
|
|
|
/* } */ |
|
|
|
if(key_binding->key_secondary == key && (key_binding->mods_secondary & mods) == key_binding->mods_secondary) |
|
|
|
if(map->keys[j].key == key && ((map->keys[j].mods & mods) == map->keys[j].mods)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
key_binding->state = state; |
|
|
|
map->state = state; |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* TODO: This is temporary. After proper event loop is added this code should not be here */ |
|
|
|
/* 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); |
|
|
|
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) |
|
|
|
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
|
|
|
|
/* Probably add 'mouse maps', same as input maps for keyboard but with buttons.
|
|
|
|
Do we even need that? |
|
|
|
Do we even need that? |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
/* TODO: This is temporary. After proper event loop is added this code should not be here */ |
|
|
|
/* TODO: This is temporary. After proper event loop is added this code should not be here */ |
|
|
@ -284,25 +316,38 @@ void input_mouse_mode_set(enum Mouse_Mode mode) |
|
|
|
platform->mouse_relative_mode_set(mode == MM_NORMAL ? 0 : 1); |
|
|
|
platform->mouse_relative_mode_set(mode == MM_NORMAL ? 0 : 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool input_map_state_get(const char* map_name, int state) |
|
|
|
bool input_map_state_get(const char* name, int state) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int current_state = KS_INACTIVE; |
|
|
|
struct Key_Binding* key_binding = (struct Key_Binding*)hashmap_ptr_get(key_bindings, name); |
|
|
|
for(int i = 0; i < array_len(input_map_list); i++) |
|
|
|
if(!key_binding) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct Input_Map* map = &input_map_list[i]; |
|
|
|
log_error("input:map_state_get", "Map '%s' not found", name); |
|
|
|
if(strcmp(map->name, map_name) == 0) |
|
|
|
return false; |
|
|
|
{ |
|
|
|
|
|
|
|
current_state = map->state; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool result = false; |
|
|
|
return (key_binding->state == state); |
|
|
|
if(current_state == state) |
|
|
|
} |
|
|
|
{ |
|
|
|
|
|
|
|
result = true; |
|
|
|
bool input_map_create(const char* name, struct Key_Binding key_combination) |
|
|
|
} |
|
|
|
{ |
|
|
|
return result; |
|
|
|
//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) |
|
|
|
bool input_is_key_pressed(int key) |
|
|
@ -316,110 +361,66 @@ bool input_mousebutton_state_get(uint button, int state_type) |
|
|
|
return state_type == current_state ? true : false; |
|
|
|
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->mods = KMD_NONE; |
|
|
|
|
|
|
|
*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].mods = KMD_NONE; |
|
|
|
|
|
|
|
new_map->keys[i] = keys[i]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
log_message("Created Input Map : %s", name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void input_update(void) |
|
|
|
void input_update(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
for(int i = 0; i < array_len(input_map_list); i++) |
|
|
|
struct Variant* value = NULL; |
|
|
|
|
|
|
|
char* key = NULL; |
|
|
|
|
|
|
|
HASHMAP_FOREACH(key_bindings, key, value) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct Input_Map* map = &input_map_list[i]; |
|
|
|
struct Key_Binding* key_binding = (struct Key_Binding*)value->val_voidptr; |
|
|
|
if(map->state == KS_RELEASED) |
|
|
|
if(key_binding->state == KS_RELEASED) |
|
|
|
map->state = KS_INACTIVE; |
|
|
|
key_binding->state = KS_INACTIVE; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool input_map_remove(const char* name) |
|
|
|
bool input_map_remove(const char* name) |
|
|
|
{ |
|
|
|
{ |
|
|
|
assert(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; |
|
|
|
if(hashmap_value_exists(key_bindings, name)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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]; |
|
|
|
struct Key_Binding* current_key = (struct Key_Binding*)hashmap_ptr_get(key_bindings, name); |
|
|
|
if(array_len(map->keys) != num_keys) |
|
|
|
free(current_key); |
|
|
|
array_reset(map->keys, num_keys); |
|
|
|
hashmap_value_remove(key_bindings, name); |
|
|
|
for(int i = 0; i < num_keys; i++) |
|
|
|
|
|
|
|
map->keys[i] = keys[i]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
map->state = KS_INACTIVE; |
|
|
|
|
|
|
|
success = true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if(!success) |
|
|
|
else |
|
|
|
log_error("input:map_keys_set", "Map %s not found", name);
|
|
|
|
{ |
|
|
|
return success; |
|
|
|
log_error("input:map_remove", "Map '%s' not found", name); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool input_map_name_set(const char* name, const char* new_name) |
|
|
|
bool input_map_keys_set(const char* name, struct Key_Binding key_combination) |
|
|
|
{ |
|
|
|
{ |
|
|
|
assert(name && new_name); |
|
|
|
assert(name); |
|
|
|
bool success = false; |
|
|
|
struct Key_Binding* existing_combination = (struct Key_Binding*)hashmap_ptr_get(key_bindings, name); |
|
|
|
int index = map_find(name); |
|
|
|
if(!existing_combination) |
|
|
|
if(index > -1) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
struct Input_Map* map = &input_map_list[index]; |
|
|
|
log_error("input:map_keys_set", "Map '%s' not found", name); |
|
|
|
map->name = str_new(new_name); |
|
|
|
return false; |
|
|
|
success = true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if(!success) log_error("input:map_name_set", "Map %s not found", name); |
|
|
|
|
|
|
|
return success; |
|
|
|
memcpy(existing_combination, &key_combination, sizeof(key_combination)); |
|
|
|
|
|
|
|
existing_combination->state = KS_INACTIVE; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int map_find(const char* name) |
|
|
|
bool input_map_name_set(const char* name, const char* new_name) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int index = -1; |
|
|
|
//assert(name && new_name);
|
|
|
|
for(int i = 0; i < array_len(input_map_list); i++) |
|
|
|
//bool success = false;
|
|
|
|
{ |
|
|
|
//int index = map_find(name);
|
|
|
|
struct Input_Map* map = &input_map_list[i]; |
|
|
|
//if(index > -1)
|
|
|
|
if(strcmp(name, map->name) == 0) |
|
|
|
//{
|
|
|
|
{ |
|
|
|
// struct Key_Binding* map = &key_bindings[index];
|
|
|
|
index = i; |
|
|
|
// map->name = str_new(new_name);
|
|
|
|
break; |
|
|
|
// success = true;
|
|
|
|
} |
|
|
|
//}
|
|
|
|
} |
|
|
|
//if(!success) log_error("input:map_name_set", "Map %s not found", name);
|
|
|
|
return index; |
|
|
|
//return success;
|
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int input_mouse_mode_get(void) |
|
|
|
int input_mouse_mode_get(void) |
|
|
|