X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_input.h;h=af0ac6882d9ff285cdbe6e95ba91d71a930553a8;hp=17f3f167aa23869262f5379819db5cc9afbffefe;hb=HEAD;hpb=6d772a1e69860f4ae3e838e8c5c164754e6533ae diff --git a/vg_input.h b/vg_input.h index 17f3f16..1636e07 100644 --- a/vg_input.h +++ b/vg_input.h @@ -1,86 +1,60 @@ -/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */ -#ifndef VG_INPUT_H -#define VG_INPUT_H - -#include "common.h" -#include "vg/vg_loader.h" +#pragma once +/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */ #define VG_MAX_CONTROLLERS 4 -VG_STATIC inline float vg_get_axis( const char *axis ); -VG_STATIC inline int vg_get_button( const char *button ); - -/* - * Cannot be used in fixed update - */ -VG_STATIC inline int vg_get_button_down( const char *button ); -VG_STATIC inline int vg_get_button_up( const char *button ); -VG_STATIC float controller_deadzone = 0.05f; - -enum vg_button_state{ - k_button_state_down = 1, - k_button_state_up = 3, - k_button_state_pressed = 2, - k_button_state_none = 0 -}; - -struct input_binding{ - const char *name; - - enum input_type{ - k_input_type_button, - k_input_type_axis, - k_input_type_axis_norm, +#include "vg_platform.h" - k_input_type_unknown, - k_input_type_keyboard_key, - k_input_type_mouse_button, /* ? TODO */ - k_input_type_gamepad_axis, - k_input_type_gamepad_button - } - type; - - union{ - struct input_axis{ - SDL_GameControllerAxis gamepad_axis; - SDL_Keycode keyboard_positive, - keyboard_negative; +extern f32 controller_deadzone; - int gamepad_inverted; - float value; - } - axis; +typedef u32 vg_input_op; +typedef vg_input_op *vg_input_program; - struct{ - SDL_GameControllerButton gamepad_id; - SDL_Keycode keyboard_id; - int mouse_id; - int value, prev; - } - button; - }; +enum vg_input_type +{ + k_vg_input_type_button_u8, + k_vg_input_type_axis_f32, + k_vg_input_type_joy_v2f +}; - int save_this; +enum vg_input_op +{ + /* data source */ + vg_keyboard, + vg_mouse, + vg_joy_button, + vg_joy_axis, + vg_joy_ls, + vg_joy_rs, + + /* modes */ + vg_mode_mul, + vg_mode_sub, + vg_mode_add, + vg_mode_absmax, + vg_mode_max, + + /* control */ + vg_index, + vg_end, + vg_gui_visible, + + /* math */ + vg_normalize }; -struct +struct vg_input { - const u8 *sdl_keys; - struct input_binding named_inputs[ 32 ]; - u32 named_input_count; + const u8 *sdl_keys; + u32 sdl_mouse; + f32 hidden_mouse_travel; struct vg_controller{ SDL_GameController *handle; /* handle for controller. NULL if unused */ SDL_JoystickID instance_id; /* uid used in events */ - enum evg_controller_type{ - k_vg_controller_type_standard, - k_vg_controller_type_trackpads - } - type; - float axises[ SDL_CONTROLLER_AXIS_MAX ]; - int buttons[ SDL_CONTROLLER_BUTTON_MAX ]; + u32 buttons[ SDL_CONTROLLER_BUTTON_MAX ]; } controllers[4]; @@ -89,669 +63,31 @@ struct /* what the user is currently using. the keyboard and controller are still * active simultaneously, but this reflects what the UI should show */ - enum userinput_method{ - k_userinput_method_xbox, - k_userinput_method_playstation, - k_userinput_method_steamgeneric, - k_userinput_method_kbm - } - input_method; -} -static vg_input; - -VG_STATIC void vg_create_unnamed_input( struct input_binding *bind, - enum input_type type ) -{ - memset( bind, 0, sizeof(struct input_binding) ); - - bind->name = "API DEFINED"; - bind->save_this = 0; - bind->type = type; - - bind->axis.gamepad_axis = -1; - bind->axis.keyboard_positive = -1; - bind->axis.keyboard_negative = -1; - bind->button.gamepad_id = -1; - bind->button.keyboard_id = -1; - bind->button.mouse_id = -1; -} - -VG_STATIC struct input_binding *vg_create_named_input( const char *name, - enum input_type type ) -{ - struct input_binding *bind = - &vg_input.named_inputs[ vg_input.named_input_count ++ ]; - memset( bind, 0, sizeof(struct input_binding) ); - - bind->name = name; - bind->save_this = 0; - bind->type = type; - - bind->axis.gamepad_axis = -1; - bind->axis.keyboard_positive = -1; - bind->axis.keyboard_negative = -1; - bind->button.gamepad_id = -1; - bind->button.keyboard_id = -1; - bind->button.mouse_id = -1; - - return bind; -} - -VG_STATIC struct input_binding *vg_get_named_input( const char *name ) -{ - if( name[0] == '+' || name[0] == '-' ) - name ++; - - for( u32 i=0; iname, name ) ) - return bind; - } - - return NULL; -} - -struct input_en -{ - enum input_type type; - - const char *alias; - int id; -} -vg_all_bindable_inputs[] = -{ - {k_input_type_keyboard_key, "space", SDLK_SPACE}, - {k_input_type_keyboard_key, ";", SDLK_SEMICOLON}, - {k_input_type_keyboard_key, "-", SDLK_MINUS}, - {k_input_type_keyboard_key, ".", SDLK_PERIOD}, - {k_input_type_keyboard_key, ",", SDLK_COMMA}, - {k_input_type_keyboard_key, "=", SDLK_EQUALS}, - {k_input_type_keyboard_key, "[", SDLK_LEFTBRACKET}, - {k_input_type_keyboard_key, "]", SDLK_RIGHTBRACKET}, - {k_input_type_keyboard_key, "left", SDLK_LEFT}, - {k_input_type_keyboard_key, "right", SDLK_RIGHT}, - {k_input_type_keyboard_key, "up", SDLK_UP}, - {k_input_type_keyboard_key, "down", SDLK_DOWN}, - {k_input_type_keyboard_key, "shift", SDLK_LSHIFT}, - {k_input_type_keyboard_key, "control", SDLK_LCTRL}, - {k_input_type_keyboard_key, "\2enter", SDLK_RETURN}, - {k_input_type_keyboard_key, "\2escape", SDLK_ESCAPE }, - - {k_input_type_gamepad_axis, "gp-lt", SDL_CONTROLLER_AXIS_TRIGGERLEFT}, - {k_input_type_gamepad_axis, "gp-rt", SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, - {k_input_type_gamepad_axis, "gp-ls-h", SDL_CONTROLLER_AXIS_LEFTX}, - {k_input_type_gamepad_axis, "gp-ls-v", SDL_CONTROLLER_AXIS_LEFTY}, - {k_input_type_gamepad_axis, "gp-rs-h", SDL_CONTROLLER_AXIS_RIGHTX}, - {k_input_type_gamepad_axis, "gp-rs-v", SDL_CONTROLLER_AXIS_RIGHTY}, - - {k_input_type_gamepad_button, "gp-a", SDL_CONTROLLER_BUTTON_A}, - {k_input_type_gamepad_button, "gp-b", SDL_CONTROLLER_BUTTON_B}, - {k_input_type_gamepad_button, "gp-x", SDL_CONTROLLER_BUTTON_X}, - {k_input_type_gamepad_button, "gp-y", SDL_CONTROLLER_BUTTON_Y}, - {k_input_type_gamepad_button, "gp-rb", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, - {k_input_type_gamepad_button, "gp-lb", SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, - {k_input_type_gamepad_button, "gp-rs", SDL_CONTROLLER_BUTTON_RIGHTSTICK}, - {k_input_type_gamepad_button, "gp-ls", SDL_CONTROLLER_BUTTON_LEFTSTICK}, - {k_input_type_gamepad_button, "gp-dpad-down", SDL_CONTROLLER_BUTTON_DPAD_DOWN}, - {k_input_type_gamepad_button, "gp-dpad-left", SDL_CONTROLLER_BUTTON_DPAD_LEFT}, - {k_input_type_gamepad_button,"gp-dpad-right",SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, - {k_input_type_gamepad_button, "gp-dpad-up", SDL_CONTROLLER_BUTTON_DPAD_UP}, - {k_input_type_gamepad_button, "\2gp-menu", SDL_CONTROLLER_BUTTON_BACK}, - - {k_input_type_mouse_button, "mouse1", SDL_BUTTON_LEFT }, - {k_input_type_mouse_button, "mouse2", SDL_BUTTON_RIGHT } -}; - -VG_STATIC const char *vg_input_to_str( u32 input, enum input_type input_type ) -{ - if( input == -1 ) - return NULL; - - if( input_type == k_input_type_keyboard_key ){ - if( (input >= SDLK_a) && (input <= SDLK_z) ){ - return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0" - "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input-SDLK_a)*2]; - } - - if( (input >= SDLK_0) && (input <= SDLK_9) ){ - return &"0\0" "1\0" "2\0" "3\0" "4\0" - "5\0" "6\0" "7\0" "8\0" "9\0"[(input-SDLK_0)*2]; - } - } - - for( int i=0; itype == input_type) && (desc->id == input) ) - return desc->alias; - } - - return NULL; -} - -VG_STATIC enum input_type vg_str_to_input( const char *str, u32 *input ) -{ - if( !str ){ - *input = -1; - return k_input_type_unknown; - } - - u32 len = strlen(str); - - if( len == 0 ){ - *input = -1; - return k_input_type_unknown; - } - - if( len == 1 ){ - u8 uch = str[0]; - - if( (uch >= (u8)'a') && (uch <= (u8)'z') ){ - *input = SDLK_a + (uch-(u8)'a'); - return k_input_type_keyboard_key; - } - - if( (uch >= (u8)'0') && (uch <= (u8)'9') ){ - *input = SDLK_0 + (uch-(u8)'0'); - return k_input_type_keyboard_key; - } - } - - for( int i=0; ialias, str ) ){ - *input = desc->id; - return desc->type; - } - } - - *input = -1; - return k_input_type_unknown; -} - -VG_STATIC void vg_print_binding_info( struct input_binding *bind ) -{ - vg_info( " name: %s\n", bind->name ); - vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"} - [ bind->type ] ); - vg_info( " save this? %d\n", bind->save_this ); - - if( (bind->type == k_input_type_axis) || - (bind->type == k_input_type_axis_norm) ) - { - vg_info( " gamepad_axis: %s\n", - vg_input_to_str(bind->axis.gamepad_axis, k_input_type_gamepad_axis)); - - vg_info( " keyboard_positive: %s\n", - vg_input_to_str(bind->axis.keyboard_positive, - k_input_type_keyboard_key )); - - vg_info( " keyboard_negative: %s\n", - vg_input_to_str(bind->axis.keyboard_negative, - k_input_type_keyboard_key )); - } - else{ - vg_info( " gamepad_id: %s\n", - vg_input_to_str(bind->button.gamepad_id, k_input_type_gamepad_button)); - vg_info( " keyboard_id: %s\n", - vg_input_to_str(bind->button.keyboard_id, - k_input_type_keyboard_key)); - vg_info( " mouse_id: %s\n", - vg_input_to_str(bind->button.mouse_id, - k_input_type_mouse_button)); - } -} - -VG_STATIC void vg_apply_bind_str( struct input_binding *bind, - const char *mod, - const char *str ) -{ - int axis_mod = 0; - char modch = ' '; - if( (mod[0] == '-') || (mod[0] == '+') ){ - axis_mod = 1; - modch = mod[0]; - mod ++; - } - - int invert = 0; - if( (str[0] == '-' ) ){ - invert = 1; - str ++; - } - - u32 id; - enum input_type type = vg_str_to_input( str, &id ); - - if( bind->type == k_input_type_button ){ - if( axis_mod ){ - vg_error( "Cannot use axis modifiers on button input!\n" ); - return; - } - - if( invert ){ - vg_error( "Cannot invert button input!\n" ); - return; - } - - if( type == k_input_type_keyboard_key ) - bind->button.keyboard_id = id; - else if( type == k_input_type_mouse_button ) - bind->button.mouse_id = id; - else if( type == k_input_type_gamepad_button ) - bind->button.gamepad_id = id; - else{ - vg_error( "Unknown button or key '%s'\n", str ); - return; - } - } - else if( (bind->type == k_input_type_axis ) || - (bind->type == k_input_type_axis_norm)) - { - if( axis_mod ){ - if( type == k_input_type_keyboard_key ){ - if( invert ){ - vg_error( "Cannot invert a keyboard key!\n" ); - return; - } - - if( modch == '+' ) - bind->axis.keyboard_positive = id; - else - bind->axis.keyboard_negative = id; - } - else{ - vg_error( "You can only bind keyboard keys to +- axises\n" ); - return; - } - } - else{ - if( type == k_input_type_gamepad_axis ){ - bind->axis.gamepad_inverted = invert; - bind->axis.gamepad_axis = id; - } - else{ - vg_error( "You can only bind gamepad axises to this\n" ); - return; - } - } - } -} - -/* - * bind jump x - * bind -horizontal a - * bind +horizontal d - * bind horizontal -gp-ls-h - */ - -VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] ) -{ - if( argc == 0 ){ - vg_info( "Usage: bind jump x\n" ); - vg_info( " bind -steerh j\n" ); - vg_info( " bind steerh gp-ls-h\n" ); - return 0; - } - - const char *str_bind_name = argv[0]; - struct input_binding *bind = vg_get_named_input( str_bind_name ); - - if( !bind ){ - vg_error( "There is no bind with that name '%s'\n", str_bind_name ); - return 0; - } - - if( argc == 1 ){ - vg_print_binding_info( bind ); - return 0; - } - - if( argc == 2 ){ - const char *str_input_id = argv[1]; - - vg_apply_bind_str( bind, str_bind_name, str_input_id ); - return 0; - } - - return 0; -} - -VG_STATIC void vg_rebind_input_cmd_poll( int argc, const char *argv[] ) -{ - if( argc == 0 ) - return; - - const char *str_bind_name = argv[0]; - - if( argc == 1 ){ - for( u32 i=0; iname, argv[argc-1], 0 ); - } - } - else if( argc == 2 ){ - for( int i=0; ialias, argv[argc-1], 0 ); - } - } -} - -VG_STATIC u8 vg_getkey( SDL_Keycode kc ) -{ - SDL_Scancode sc = SDL_GetScancodeFromKey( kc ); - return vg_input.sdl_keys[sc]; -} - -VG_STATIC void vg_input_update( u32 num, struct input_binding *binds ) -{ - if( vg_console.enabled ){ - for( i32 i=0; itype == k_input_type_button ){ - bind->button.prev = bind->button.value; - bind->button.value = 0; - } - } - - return; - } - - struct vg_controller *acontroller = NULL; - - if( vg_input.active_controller_index != -1 ) - acontroller = &vg_input.controllers[vg_input.active_controller_index]; - - for( i32 i=0; itype == k_input_type_button ){ - bind->button.prev = bind->button.value; - bind->button.value = 0; - - if( acontroller && (bind->button.gamepad_id != -1) ) - bind->button.value |= acontroller->buttons[bind->button.gamepad_id]; - - if( bind->button.keyboard_id != -1 ) - bind->button.value |= vg_getkey( bind->button.keyboard_id ); - - if( bind->button.mouse_id != -1 ){ - if(SDL_GetMouseState(NULL,NULL) & SDL_BUTTON(bind->button.mouse_id)) - bind->button.value |= 1; - } - } - else if( bind->type == k_input_type_axis ){ - float keyboard_value = 0.0f, - gamepad_value = 0.0f; - - if( bind->axis.keyboard_positive != -1 ) - if( vg_getkey( bind->axis.keyboard_positive ) ) - keyboard_value += 1.0f; - - if( bind->axis.keyboard_negative != -1 ) - if( vg_getkey( bind->axis.keyboard_negative ) ) - keyboard_value -= 1.0f; - - if( acontroller && (bind->axis.gamepad_axis != -1) ){ - gamepad_value = acontroller->axises[ bind->axis.gamepad_axis ]; - - if( bind->axis.gamepad_inverted ) - gamepad_value *= -1.0f; - } - - float deadz = vg_clampf( controller_deadzone, 0.0f, 0.999f ), - high = vg_maxf( 0.0f, fabsf(gamepad_value) - deadz ), - norm = high / (1.0f-deadz); - - gamepad_value = vg_signf( gamepad_value ) * norm; - - if( fabsf(keyboard_value) > fabsf(gamepad_value) ) - bind->axis.value = keyboard_value; - else - bind->axis.value = gamepad_value; - } - else if( bind->type == k_input_type_axis_norm ){ - float value = 0.0f; - if( bind->axis.keyboard_positive != -1 ) - if( vg_getkey( bind->axis.keyboard_positive )) - value = 1.0f; - - if( acontroller && (bind->axis.gamepad_axis != -1) ){ - float value1 = acontroller->axises[bind->axis.gamepad_axis]; - value = vg_maxf( value, value1 ); - } - - bind->axis.value = value; - } - } -} - -/* - * takes SDL device index, and tries to open that on any free channel - */ -VG_STATIC void vg_open_gamecontroller( Sint32 index ) -{ - struct vg_controller *controller = NULL; - int vg_id = 0; - const char *name = SDL_GameControllerNameForIndex( index ); - SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index ); - - if( instance_id == -1 ){ - vg_error( ". Invalid device index (vg_open_gamecontroller)\n" ); - return; - } - - for( int j=0; jhandle ){ - if( esta->instance_id == instance_id ){ - vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n", - esta->instance_id, j ); - return; - } - } - else{ - if( !controller ){ - controller = &vg_input.controllers[j]; - vg_id = j; - } - } - } - - if( controller ){ - controller->handle = SDL_GameControllerOpen( index ); - controller->instance_id = instance_id; - - if( controller->handle ){ - vg_success( - " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n", - instance_id, name, vg_id ); - - controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f; - controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f; - } - else{ - vg_error( ". Failed to attach game controller '%s'. Reason: %s\n", - name, SDL_GetError() ); - } - } - else{ - vg_error( ". Too many controllers open! ignoring '%s'\n", name ); - - } -} - -VG_STATIC void vg_input_device_event( SDL_Event *ev ) -{ - if( ev->type == SDL_CONTROLLERDEVICEADDED ){ - int is_controller = SDL_IsGameController( ev->cdevice.which ); - const char *name = SDL_JoystickNameForIndex( ev->cdevice.which ); - - Sint32 index = ev->cdevice.which; - SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index ); - vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n", - index, name ); - - if( is_controller ){ - vg_open_gamecontroller( index ); - } - } - else if( ev->type == SDL_CONTROLLERDEVICEREMOVED ){ - vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n", - ev->cdevice.which ); - - for( int i=0; ihandle ){ - if( controller->instance_id == ev->cdevice.which ){ - vg_info( " . closing controller at index #%d\n", i ); - SDL_GameControllerClose( controller->handle ); - controller->handle = NULL; - controller->instance_id = -1; - - if( vg_input.active_controller_index == i ){ - vg_input.active_controller_index = -1; - vg_info( " . active controller is now keyboard and mouse\n" ); - } - break; - } - } - } - } -} - -VG_STATIC void vg_input_controller_event( SDL_Event *ev ) -{ - if( ev->type == SDL_CONTROLLERAXISMOTION ){ - for( int i=0; icaxis.which == esta->instance_id ){ - float value = (float)ev->caxis.value / 32767.0f; - esta->axises[ ev->caxis.axis ] = value; - break; - } - } - } - else if( ev->type == SDL_CONTROLLERBUTTONDOWN ){ - struct vg_controller *active = NULL; - - if( vg_input.active_controller_index != -1 ) - active = &vg_input.controllers[vg_input.active_controller_index]; - - if( !active || (ev->cbutton.which != active->instance_id) ){ - active = NULL; - vg_input.active_controller_index = -1; - - for( int i=0; icbutton.which ){ - active = &vg_input.controllers[i]; - vg_input.active_controller_index = i; - break; - } - } - - if( active ){ - vg_info( "Switching active controller index to #%d\n", - vg_input.active_controller_index ); - } - else{ - vg_error( "Input out of range (SDL_JoystickID#%d)\n", - ev->cbutton.which ); - } - } - - if( active ) - active->buttons[ ev->cbutton.button ] = 1; - } - else if( ev->type == SDL_CONTROLLERBUTTONUP ){ - for( int i=0; icbutton.which == esta->instance_id ){ - esta->buttons[ ev->cbutton.button ] = 0; - break; - } - } - } -} - -VG_STATIC void vg_process_inputs(void) -{ - int count; - vg_input.sdl_keys = SDL_GetKeyboardState( &count ); - - if( vg_input.input_method != k_userinput_method_kbm ){ - /* check for giving keyboard priority */ - for( int i=0; ibutton.value && !bind->button.prev ) - return 1; - return 0; -} - -VG_STATIC void async_vg_input_init( void *payload, u32 size ) -{ - vg_console_reg_cmd( "bind", vg_rebind_input_cmd, vg_rebind_input_cmd_poll ); - - VG_VAR_F32( controller_deadzone, flags=VG_VAR_PERSISTENT ); - - vg_info( "Checking for controllers\n" ); - SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" ); - - int joy_count = SDL_NumJoysticks(); - for( int i=0; ihandle ){ - SDL_GameControllerClose( controller->handle ); - controller->handle = NULL; - } - } -} - -#endif + enum input_method{ + k_input_method_kbm, + k_input_method_controller + } + display_input_method; + SDL_GameControllerType display_input_type; +} +extern vg_input; + +u8 vg_getkey( SDL_Keycode kc ); +void vg_process_inputs(void); +void async_vg_input_init( void *payload, u32 size ); +void vg_input_init(void); +void vg_input_free(void); +struct vg_controller *vg_active_controller(void); +u8 vg_controller_button( SDL_GameControllerButton button ); +f32 vg_controller_axis( SDL_GameControllerAxis axis ); +void vg_exec_input_program( enum vg_input_type type, vg_input_op *ops, + void *out_result ); +const char *controller_button_str( SDL_GameControllerButton button ); +void vg_keyboard_key_string( vg_str *str, u32 key, int special_glyphs ); +void vg_mouse_button_string( vg_str *str, u32 button, int special_glyphs ); +void vg_joy_axis_string( vg_str *str, SDL_GameControllerAxis axis, + int special_glyphs ); +void vg_joy_string( vg_str *str, vg_input_op op, int special_glyphs ); +void vg_input_string( vg_str *str, vg_input_op *ops, int glyphs ); +void vg_input_device_event( SDL_Event *ev ); +void vg_input_controller_event( SDL_Event *ev );