/* * Mr. 4th Dimention - Allen Webster * * 19.08.2015 * * Command management functions * */ // TOP internal i32 get_or_add_map_index(Mapping *mapping, i32 mapid){ i32 user_map_count = mapping->user_map_count; i32 *map_id_table = mapping->map_id_table; i32 result = 0; for (; result < user_map_count; ++result){ if (map_id_table[result] == mapid){ break; } if (map_id_table[result] == -1){ map_id_table[result] = mapid; break; } } return(result); } internal i32 get_map_index(Mapping *mapping, i32 mapid){ i32 user_map_count = mapping->user_map_count; i32 *map_id_table = mapping->map_id_table; i32 result = 0; for (; result < user_map_count; ++result){ if (map_id_table[result] == mapid){ break; } } return(result); } internal Command_Map* get_map_base(Mapping *mapping, i32 mapid, b32 add){ Command_Map *map = 0; if (mapid < mapid_global){ i32 map_index = 0; if (add){ map_index = get_or_add_map_index(mapping, mapid); } else{ map_index = get_map_index(mapping, mapid); } if (map_index < mapping->user_map_count){ map = &mapping->user_maps[map_index]; } } else if (mapid == mapid_global){ map = &mapping->map_top; } else if (mapid == mapid_file){ map = &mapping->map_file; } return(map); } internal Command_Map* get_or_add_map(Mapping *mapping, i32 mapid){ Command_Map *map = get_map_base(mapping, mapid, true); return(map); } internal Command_Map* get_map(Mapping *mapping, i32 mapid){ Command_Map *map = get_map_base(mapping, mapid, false); return(map); } #define COMMAND_HASH_EMPTY 0 #define COMMAND_HASH_ERASED max_u64 internal u64 map_hash(Key_Code event_code, u8 modifiers){ u64 result = (event_code << 8) | modifiers; return(result); } internal b32 map_add(Command_Map *map, Key_Code event_code, u8 modifiers, Custom_Command_Function *custom){ b32 result = false; Assert(map->count * 8 < map->max * 7); u64 hash = map_hash(event_code, modifiers); u32 max = map->max; u32 index = hash % max; Command_Binding entry = map->commands[index]; for (; entry.custom != 0 && entry.hash != COMMAND_HASH_ERASED;){ if (entry.hash == hash){ result = true; break; } index = (index + 1) % max; entry = map->commands[index]; } Command_Binding bind = {}; bind.custom = custom; bind.hash = hash; map->commands[index] = bind; if (!result){ ++map->count; } return(result); } internal b32 map_find_entry(Command_Map *map, Key_Code event_code, u8 modifiers, u32 *index_out){ u64 hash = map_hash(event_code, modifiers); u32 max = map->max; u32 index = hash % max; b32 result = false; Command_Binding entry = map->commands[index]; for (; entry.custom != 0;){ if (entry.hash == hash){ *index_out = index; result = true; break; } index = (index + 1) % max; entry = map->commands[index]; } return(result); } internal b32 map_find(Command_Map *map, Key_Code event_code, u8 modifiers, Command_Binding *bind_out){ u32 index = 0; b32 result = map_find_entry(map, event_code, modifiers, &index); if (result){ *bind_out = map->commands[index]; } return(result); } internal b32 map_drop(Command_Map *map, Key_Code event_code, u8 modifiers){ u32 index = 0; b32 result = map_find_entry(map, event_code, modifiers, &index); if (result){ map->commands[index].custom = 0; map->commands[index].hash = COMMAND_HASH_ERASED; } return(result); } internal void map_init(Command_Map *map, Cursor *cursor, i32 max, i32 parent){ Assert(max >= 6); Assert(map->commands == 0); map->parent = parent; map->commands = push_array_zero(cursor, Command_Binding, max); map->count = 0; map->max = max; block_zero_array(map->vanilla_keyboard_default); } internal b32 map_get_modifiers_hash(u8 modifiers, u32 *hash_out){ b32 result = true; u32 hash = 0; if (modifiers & MDFR_SHIFT){ hash += MDFR_SHIFT; } if (modifiers & MDFR_CTRL){ hash += MDFR_CTRL; } if (modifiers & MDFR_CMND){ hash += MDFR_CMND; } if (modifiers & MDFR_ALT){ hash += MDFR_ALT; } *hash_out = hash; return(result); } internal void map_get_vanilla_keyboard_default(Command_Map *map, u8 command, Command_Binding *bind_out){ u32 modifiers_hashed = 0; if (map_get_modifiers_hash(command, &modifiers_hashed)){ *bind_out = map->vanilla_keyboard_default[modifiers_hashed]; } } internal Command_Binding map_extract(Command_Map *map, Key_Event_Data key){ Command_Binding bind = {}; b32 ctrl = key.modifiers[MDFR_CONTROL_INDEX]; b32 alt = key.modifiers[MDFR_ALT_INDEX]; b32 command = key.modifiers[MDFR_COMMAND_INDEX]; b32 shift = key.modifiers[MDFR_SHIFT_INDEX]; u8 mod_flags = MDFR_NONE; if (ctrl) mod_flags |= MDFR_CTRL; if (alt) mod_flags |= MDFR_ALT; if (command) mod_flags |= MDFR_CMND; if (shift) mod_flags |= MDFR_SHIFT; Key_Code code = key.character_no_caps_lock; if (code == 0){ code = key.keycode; map_find(map, code, mod_flags, &bind); } else{ if (code != '\n' && code != '\t' && code != ' '){ mod_flags &= ~(MDFR_SHIFT); } map_find(map, code, mod_flags, &bind); if (bind.custom == 0){ map_get_vanilla_keyboard_default(map, mod_flags, &bind); } } return(bind); } internal Command_Binding map_extract_recursive(Mapping *mapping, i32 map_id, Key_Event_Data key){ Command_Map *map = get_map(mapping, map_id); if (map == 0){ map = &mapping->map_top; } Command_Map *visited_maps[16] = {}; i32 visited_top = 0; Command_Binding cmd_bind = {}; for (; map != 0; ){ cmd_bind = map_extract(map, key); if (cmd_bind.custom == 0){ if (visited_top < ArrayCount(visited_maps)){ visited_maps[visited_top++] = map; map = get_map(mapping, map->parent); for (i32 i = 0; i < visited_top; ++i){ if (map == visited_maps[i]){ map = 0; break; } } } else{ map = 0; } } else{ map = 0; } } return(cmd_bind); } // BOTTOM