537 lines
18 KiB
C++
537 lines
18 KiB
C++
/*
|
|
* Mr. 4th Dimention - Allen Webster
|
|
*
|
|
* 19.08.2015
|
|
*
|
|
* Command management functions
|
|
*
|
|
*/
|
|
|
|
// TOP
|
|
|
|
function u64
|
|
mapping__key(Input_Event_Kind kind, u32 sub_code){
|
|
return((((u64)kind) << 32) | sub_code);
|
|
}
|
|
|
|
function Command_Map*
|
|
mapping__alloc_map(Mapping *mapping){
|
|
Command_Map *result = mapping->free_maps;
|
|
if (result != 0){
|
|
sll_stack_pop(mapping->free_maps);
|
|
}
|
|
else{
|
|
result = push_array(mapping->node_arena, Command_Map, 1);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function void
|
|
mapping__free_map(Mapping *mapping, Command_Map *map){
|
|
sll_stack_push(mapping->free_maps, map);
|
|
}
|
|
|
|
function Command_Modified_Binding*
|
|
mapping__alloc_modified_binding(Mapping *mapping){
|
|
Command_Modified_Binding *result = mapping->free_bindings;
|
|
if (result != 0){
|
|
sll_stack_pop(mapping->free_bindings);
|
|
}
|
|
else{
|
|
result = push_array(mapping->node_arena, Command_Modified_Binding, 1);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function void
|
|
mapping__free_modified_binding(Mapping *mapping, Command_Modified_Binding *binding){
|
|
sll_stack_push(mapping->free_bindings, binding);
|
|
}
|
|
|
|
function Command_Binding_List*
|
|
mapping__alloc_binding_list(Mapping *mapping){
|
|
Command_Binding_List *result = mapping->free_lists;
|
|
if (result != 0){
|
|
sll_stack_pop(mapping->free_lists);
|
|
}
|
|
else{
|
|
result = push_array(mapping->node_arena, Command_Binding_List, 1);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function void
|
|
mapping__free_binding_list(Mapping *mapping, Command_Binding_List *binding_list){
|
|
sll_stack_push(mapping->free_lists, binding_list);
|
|
}
|
|
|
|
function Command_Binding_List*
|
|
map__get_list(Command_Map *map, u64 key){
|
|
Command_Binding_List *result = 0;
|
|
Table_Lookup lookup = table_lookup(&map->event_code_to_binding_list, key);
|
|
if (lookup.found_match){
|
|
u64 val = 0;
|
|
table_read(&map->event_code_to_binding_list, lookup, &val);
|
|
result = (Command_Binding_List*)IntAsPtr(val);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function Command_Binding_List*
|
|
map__get_or_make_list(Mapping *mapping, Command_Map *map, u64 key){
|
|
Command_Binding_List *result = map__get_list(map, key);
|
|
if (result == 0){
|
|
result = mapping__alloc_binding_list(mapping);
|
|
block_zero_struct(result);
|
|
sll_queue_push(map->list_first, map->list_last, result);
|
|
table_insert(&map->event_code_to_binding_list, key, (u64)PtrAsInt(result));
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
////////////////////////////////
|
|
|
|
function void
|
|
mapping_init(Thread_Context *tctx, Mapping *mapping){
|
|
block_zero_struct(mapping);
|
|
mapping->node_arena = reserve_arena(tctx);
|
|
heap_init(&mapping->heap, mapping->node_arena);
|
|
mapping->heap_wrapper = base_allocator_on_heap(&mapping->heap);
|
|
mapping->id_to_map = make_table_u64_u64(tctx->allocator, 10);
|
|
mapping->id_counter = 1;
|
|
}
|
|
|
|
function void
|
|
mapping_release(Thread_Context *tctx, Mapping *mapping){
|
|
if (mapping->node_arena != 0){
|
|
release_arena(tctx, mapping->node_arena);
|
|
table_free(&mapping->id_to_map);
|
|
}
|
|
}
|
|
|
|
function void
|
|
map__init(Mapping *mapping, Command_Map *map, Command_Map_ID id){
|
|
block_zero_struct(map);
|
|
map->id = id;
|
|
map->node_arena = make_arena(&mapping->heap_wrapper, KB(2));
|
|
map->event_code_to_binding_list = make_table_u64_u64(&mapping->heap_wrapper, 100);
|
|
map->cmd_to_binding_trigger = make_table_u64_u64(&mapping->heap_wrapper, 100);
|
|
}
|
|
|
|
function Command_Map*
|
|
mapping_begin_new_map(Mapping *mapping){
|
|
Command_Map *map = mapping__alloc_map(mapping);
|
|
map__init(mapping, map, mapping->id_counter);
|
|
mapping->id_counter += 1;
|
|
table_insert(&mapping->id_to_map, map->id, (u64)PtrAsInt(map));
|
|
return(map);
|
|
}
|
|
|
|
function Command_Map*
|
|
mapping_get_map(Mapping *mapping, Command_Map_ID id){
|
|
Command_Map *result = 0;
|
|
Table_Lookup lookup = table_lookup(&mapping->id_to_map, id);
|
|
if (lookup.found_match){
|
|
u64 val = 0;
|
|
table_read(&mapping->id_to_map, lookup, &val);
|
|
result = (Command_Map*)IntAsPtr(val);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function Command_Map_ID
|
|
mapping_validate_id(Mapping *mapping, Command_Map_ID id){
|
|
Table_Lookup lookup = table_lookup(&mapping->id_to_map, id);
|
|
if (!lookup.found_match){
|
|
id = 0;
|
|
}
|
|
return(id);
|
|
}
|
|
|
|
function Command_Map*
|
|
mapping_get_or_make_map(Mapping *mapping, Command_Map_ID id){
|
|
Command_Map *result = mapping_get_map(mapping, id);
|
|
if (result == 0){
|
|
result = mapping__alloc_map(mapping);
|
|
map__init(mapping, result, id);
|
|
table_insert(&mapping->id_to_map, result->id, (u64)PtrAsInt(result));
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function void
|
|
mapping_release_map(Mapping *mapping, Command_Map *map){
|
|
table_erase(&mapping->id_to_map, map->id);
|
|
if (map->binding_last != 0){
|
|
map->binding_last->next = mapping->free_bindings;
|
|
mapping->free_bindings = map->binding_first;
|
|
}
|
|
if (map->list_last != 0){
|
|
map->list_last->next = mapping->free_lists;
|
|
mapping->free_lists = map->list_first;
|
|
}
|
|
table_free(&map->event_code_to_binding_list);
|
|
linalloc_clear(&map->node_arena);
|
|
}
|
|
|
|
function Command_Binding
|
|
map_get_binding_non_recursive(Command_Map *map, Input_Event *event){
|
|
Command_Binding result = {};
|
|
|
|
if (map != 0){
|
|
b32 do_table_lookup = false;
|
|
Input_Modifier_Set *mods = 0;
|
|
u64 key = 0;
|
|
|
|
switch (event->kind){
|
|
case InputEventKind_TextInsert:
|
|
{
|
|
result = map->text_input_command;
|
|
}break;
|
|
|
|
case InputEventKind_KeyStroke:
|
|
{
|
|
key = mapping__key(InputEventKind_KeyStroke, event->key.code);
|
|
do_table_lookup = true;
|
|
mods = &event->key.modifiers;
|
|
}break;
|
|
|
|
case InputEventKind_MouseButton:
|
|
{
|
|
key = mapping__key(InputEventKind_MouseButton, event->mouse.code);
|
|
do_table_lookup = true;
|
|
mods = &event->mouse.modifiers;
|
|
}break;
|
|
|
|
case InputEventKind_MouseWheel:
|
|
{
|
|
key = mapping__key(InputEventKind_MouseWheel, 0);
|
|
do_table_lookup = true;
|
|
mods = &event->mouse_wheel.modifiers;
|
|
}break;
|
|
|
|
case InputEventKind_MouseMove:
|
|
{
|
|
key = mapping__key(InputEventKind_MouseMove, 0);
|
|
do_table_lookup = true;
|
|
mods = &event->mouse_move.modifiers;
|
|
}break;
|
|
|
|
case InputEventKind_Core:
|
|
{
|
|
key = mapping__key(InputEventKind_Core, event->core.code);
|
|
do_table_lookup = true;
|
|
}break;
|
|
}
|
|
|
|
if (do_table_lookup){
|
|
Table_Lookup lookup = table_lookup(&map->event_code_to_binding_list, key);
|
|
if (lookup.found_match){
|
|
u64 val = 0;
|
|
table_read(&map->event_code_to_binding_list, lookup, &val);
|
|
Command_Binding_List *list = (Command_Binding_List*)IntAsPtr(val);
|
|
if (mods != 0){
|
|
for (SNode *node = list->first;
|
|
node != 0;
|
|
node = node->next){
|
|
Command_Modified_Binding *mod_binding = CastFromMember(Command_Modified_Binding, order_node, node);
|
|
Input_Modifier_Set *binding_mod_set = &mod_binding->mods;
|
|
b32 is_a_match = true;
|
|
i32 binding_mod_count = binding_mod_set->count;
|
|
Key_Code *binding_mods = binding_mod_set->mods;
|
|
for (i32 i = 0; i < binding_mod_count; i += 1){
|
|
if (!has_modifier(mods, binding_mods[i])){
|
|
is_a_match = false;
|
|
break;
|
|
}
|
|
}
|
|
if (is_a_match){
|
|
result = mod_binding->binding;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
Command_Modified_Binding *mod_binding = CastFromMember(Command_Modified_Binding, order_node, list->first);
|
|
result = mod_binding->binding;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
function Command_Binding
|
|
map_get_binding_recursive(Mapping *mapping, Command_Map *map, Input_Event *event){
|
|
Command_Binding result = {};
|
|
for (i32 safety_counter = 0;
|
|
map != 0 && safety_counter < 40;
|
|
safety_counter += 1){
|
|
result = map_get_binding_non_recursive(map, event);
|
|
if (result.custom != 0){
|
|
break;
|
|
}
|
|
map = mapping_get_map(mapping, map->parent);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function void
|
|
map_set_parent(Command_Map *map, Command_Map *parent){
|
|
if (map != 0 && parent != 0){
|
|
map->parent = parent->id;
|
|
}
|
|
}
|
|
|
|
function void
|
|
map_null_parent(Command_Map *map){
|
|
map->parent = 0;
|
|
}
|
|
|
|
function void
|
|
map__command_add_trigger(Command_Map *map, Custom_Command_Function *custom,
|
|
Command_Trigger *trigger){
|
|
if (map != 0){
|
|
u64 key = (u64)(PtrAsInt(custom));
|
|
Table_Lookup lookup = table_lookup(&map->cmd_to_binding_trigger, key);
|
|
Command_Trigger_List *list = 0;
|
|
if (!lookup.found_match){
|
|
list = push_array_zero(&map->node_arena, Command_Trigger_List, 1);
|
|
table_insert(&map->cmd_to_binding_trigger, key, (u64)(PtrAsInt(list)));
|
|
}
|
|
else{
|
|
u64 val = 0;
|
|
table_read(&map->cmd_to_binding_trigger, lookup, &val);
|
|
list = (Command_Trigger_List*)IntAsPtr(val);
|
|
}
|
|
Command_Trigger *trigger_ptr = push_array(&map->node_arena, Command_Trigger, 1);
|
|
block_copy_struct(trigger_ptr, trigger);
|
|
sll_queue_push(list->first, list->last, trigger_ptr);
|
|
}
|
|
}
|
|
|
|
function Command_Trigger_List
|
|
map_get_triggers(Command_Map *map, Custom_Command_Function *custom){
|
|
Command_Trigger_List result = {};
|
|
if (map != 0){
|
|
u64 key = (u64)(PtrAsInt(custom));
|
|
Table_Lookup lookup = table_lookup(&map->cmd_to_binding_trigger, key);
|
|
if (lookup.found_match){
|
|
u64 val = 0;
|
|
table_read(&map->cmd_to_binding_trigger, lookup, &val);
|
|
result = *(Command_Trigger_List*)IntAsPtr(val);
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function void
|
|
map_set_binding(Mapping *mapping, Command_Map *map, Custom_Command_Function *custom,
|
|
u32 code1, u32 code2, Input_Modifier_Set *mods){
|
|
if (map != 0){
|
|
u64 key = mapping__key(code1, code2);
|
|
Command_Binding_List *list = map__get_or_make_list(mapping, map, key);
|
|
Command_Modified_Binding *mod_binding = mapping__alloc_modified_binding(mapping);
|
|
sll_stack_push(map->binding_first, mod_binding);
|
|
if (map->binding_last == 0){
|
|
map->binding_last = map->binding_first;
|
|
}
|
|
sll_stack_push(list->first, &mod_binding->order_node);
|
|
if (list->last == 0){
|
|
list->last= list->first;
|
|
}
|
|
list->count += 1;
|
|
mod_binding->mods = copy_modifier_set(&map->node_arena, mods);
|
|
mod_binding->binding.custom = custom;
|
|
|
|
Command_Trigger trigger = {};
|
|
trigger.kind = code1;
|
|
trigger.sub_code = code2;
|
|
trigger.mods = mod_binding->mods;
|
|
map__command_add_trigger(map, custom, &trigger);
|
|
}
|
|
}
|
|
|
|
function void
|
|
map_set_binding_key(Mapping *mapping, Command_Map *map, Custom_Command_Function *custom,
|
|
Key_Code code, Input_Modifier_Set *modifiers){
|
|
map_set_binding(mapping, map, custom, InputEventKind_KeyStroke, code, modifiers);
|
|
}
|
|
|
|
function void
|
|
map_set_binding_mouse(Mapping *mapping, Command_Map *map, Custom_Command_Function *custom,
|
|
Mouse_Code code, Input_Modifier_Set *modifiers){
|
|
map_set_binding(mapping, map, custom, InputEventKind_MouseButton, code, modifiers);
|
|
}
|
|
|
|
function void
|
|
map_set_binding_core(Mapping *mapping, Command_Map *map, Custom_Command_Function *custom,
|
|
Core_Code code, Input_Modifier_Set *modifiers){
|
|
map_set_binding(mapping, map, custom, InputEventKind_Core, code, modifiers);
|
|
}
|
|
|
|
function void
|
|
map_set_binding_text_input(Command_Map *map, Custom_Command_Function *custom){
|
|
if (map != 0){
|
|
map->text_input_command.custom = custom;
|
|
Command_Trigger trigger = {};
|
|
trigger.kind = InputEventKind_TextInsert;
|
|
map__command_add_trigger(map, custom, &trigger);
|
|
}
|
|
}
|
|
|
|
function Command_Binding_List*
|
|
map_get_binding_list_on_key(Command_Map *map, Key_Code code){
|
|
Command_Binding_List *result = 0;
|
|
if (map != 0){
|
|
u64 key = mapping__key(InputEventKind_KeyStroke, code);
|
|
result = map__get_list(map, key);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function Command_Binding_List*
|
|
map_get_binding_list_on_mouse_button(Command_Map *map, Mouse_Code code){
|
|
Command_Binding_List *result = 0;
|
|
if (map != 0){
|
|
u64 key = mapping__key(InputEventKind_MouseButton, code);
|
|
result = map__get_list(map, key);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
function Command_Binding_List*
|
|
map_get_binding_list_on_core(Command_Map *map, Core_Code code){
|
|
Command_Binding_List *result = 0;
|
|
if (map != 0){
|
|
u64 key = mapping__key(InputEventKind_Core, code);
|
|
result = map__get_list(map, key);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
////////////////////////////////
|
|
|
|
function void
|
|
map_set_parent(Mapping *mapping, Command_Map_ID map_id, Command_Map_ID parent_id){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
Command_Map *parent = mapping_get_map(mapping, parent_id);
|
|
map_set_parent(map, parent);
|
|
}
|
|
|
|
function void
|
|
map_set_parent(Mapping *mapping, Command_Map *map, Command_Map_ID parent_id){
|
|
Command_Map *parent = mapping_get_map(mapping, parent_id);
|
|
map_set_parent(map, parent);
|
|
}
|
|
|
|
function void
|
|
map_null_parent(Mapping *mapping, Command_Map_ID map_id){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
map_null_parent(map);
|
|
}
|
|
|
|
function void
|
|
map_set_binding(Mapping *mapping, Command_Map_ID map_id, Custom_Command_Function *custom,
|
|
u32 code1, u32 code2, Input_Modifier_Set *modifiers){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
map_set_binding(mapping, map, custom, code1, code2, modifiers);
|
|
}
|
|
|
|
function void
|
|
map_set_binding_key(Mapping *mapping, Command_Map_ID map_id, Custom_Command_Function *custom,
|
|
Key_Code code, Input_Modifier_Set *modifiers){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
map_set_binding_key(mapping, map, custom, code, modifiers);
|
|
}
|
|
|
|
function void
|
|
map_set_binding_mouse(Mapping *mapping, Command_Map_ID map_id, Custom_Command_Function *custom,
|
|
Mouse_Code code, Input_Modifier_Set *modifiers){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
map_set_binding_mouse(mapping, map, custom, code, modifiers);
|
|
}
|
|
|
|
function void
|
|
map_set_binding_core(Mapping *mapping, Command_Map_ID map_id, Custom_Command_Function *custom,
|
|
Core_Code code, Input_Modifier_Set *modifiers){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
map_set_binding_core(mapping, map, custom, code, modifiers);
|
|
}
|
|
|
|
function void
|
|
map_set_binding_text_input(Mapping *mapping, Command_Map_ID map_id, Custom_Command_Function *custom){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
map_set_binding_text_input(map, custom);
|
|
}
|
|
|
|
function Command_Binding_List*
|
|
map_get_binding_list_on_key(Mapping *mapping, Command_Map_ID map_id, Key_Code code){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
return(map_get_binding_list_on_key(map, code));
|
|
}
|
|
|
|
function Command_Binding
|
|
map_get_binding_non_recursive(Mapping *mapping, Command_Map_ID map_id, Input_Event *event){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
return(map_get_binding_non_recursive(map, event));
|
|
}
|
|
|
|
function Command_Binding
|
|
map_get_binding_recursive(Mapping *mapping, Command_Map_ID map_id, Input_Event *event){
|
|
Command_Map *map = mapping_get_map(mapping, map_id);
|
|
return(map_get_binding_recursive(mapping, map, event));
|
|
}
|
|
|
|
////////////////////////////////
|
|
|
|
function void
|
|
map_set_binding_lv(Mapping *mapping, Command_Map *map,
|
|
Custom_Command_Function *custom, u32 code1, u32 code2, va_list args){
|
|
Input_Modifier_Set mods = {};
|
|
Key_Code mods_array[Input_MaxModifierCount];
|
|
mods.mods = mods_array;
|
|
for (;mods.count < ArrayCount(mods_array);){
|
|
i32 v = va_arg(args, i32);
|
|
if (v <= 0){
|
|
break;
|
|
}
|
|
mods.mods[mods.count] = v;
|
|
mods.count += 1;
|
|
}
|
|
return(map_set_binding(mapping, map, custom, code1, code2, &mods));
|
|
}
|
|
function void
|
|
map_set_binding_l(Mapping *mapping, Command_Map *map,
|
|
Custom_Command_Function *custom, u32 code1, u32 code2, ...){
|
|
va_list args;
|
|
va_start(args, code2);
|
|
map_set_binding_lv(mapping, map, custom, code1, code2, args);
|
|
va_end(args);
|
|
}
|
|
|
|
#define MappingScope() Mapping *m = 0; Command_Map *map = 0
|
|
#define SelectMapping(N) m = (N)
|
|
#define SelectMap(ID) map = mapping_get_or_make_map(m, (ID))
|
|
#define ParentMap(ID) map_set_parent(m, map, (ID))
|
|
#define BindTextInput(F) map_set_binding_text_input(map, (F))
|
|
// TODO(allen): detect compiler and apply va args extensions correctly
|
|
#define Bind(F, K, ...) \
|
|
map_set_binding_l(m, map, (F), InputEventKind_KeyStroke, (K), __VA_ARGS__, 0)
|
|
#define BindRelease(F, K, ...) \
|
|
map_set_binding_l(m, map, (F), InputEventKind_KeyRelease, (K), __VA_ARGS__, 0)
|
|
#define BindMouse(F, K, ...) \
|
|
map_set_binding_l(m, map, (F), InputEventKind_MouseButton, (K), __VA_ARGS__, 0)
|
|
#define BindMouseRelease(F, K, ...) \
|
|
map_set_binding_l(m, map, (F), InputEventKind_MouseButtonRelease, (K), __VA_ARGS__, 0)
|
|
#define BindMouseWheel(F, ...) \
|
|
map_set_binding_l(m, map, (F), InputEventKind_MouseWheel, 0, __VA_ARGS__, 0)
|
|
#define BindMouseMove(F, ...) \
|
|
map_set_binding_l(m, map, (F), InputEventKind_MouseMove, 0, __VA_ARGS__, 0)
|
|
#define BindCore(F, K, ...) \
|
|
map_set_binding_l(m, map, (F), InputEventKind_Core, (K), __VA_ARGS__, 0)
|
|
|
|
// BOTTOM
|
|
|