bad char
[vg.git] / vg_input.h
index 17f3f167aa23869262f5379819db5cc9afbffefe..1636e07458db2da4b5d1cbe512eb7886112c4cfb 100644 (file)
@@ -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; i<vg_input.named_input_count; i++ ){
-      struct input_binding *bind = &vg_input.named_inputs[i];
-      if( !strcmp( bind->name, 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; i<vg_list_size(vg_all_bindable_inputs); i++ ){
-      struct input_en *desc = &vg_all_bindable_inputs[i];
-
-      if( (desc->type == 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; i<vg_list_size(vg_all_bindable_inputs); i++ ){
-      struct input_en *desc = &vg_all_bindable_inputs[i];
-
-      if( !strcmp( desc->alias, 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; i<vg_input.named_input_count; i++ ){
-         struct input_binding *bind = &vg_input.named_inputs[i];
-         console_suggest_score_text( bind->name, argv[argc-1], 0 );
-      }
-   }
-   else if( argc == 2 ){
-      for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ ){
-         struct input_en *desc = &vg_all_bindable_inputs[i];
-         console_suggest_score_text( desc->alias, 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; i<num; i++ ){
-         struct input_binding *bind = &binds[i];
-
-         if( bind->type == 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; i<num; i++ ){
-      struct input_binding *bind = &binds[i];
-
-      if( bind->type == 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; j<VG_MAX_CONTROLLERS; j++ ){
-      struct vg_controller *esta = &vg_input.controllers[j];
-
-      if( esta->handle ){
-         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; i<VG_MAX_CONTROLLERS; i++ ){
-         struct vg_controller *controller = &vg_input.controllers[i];
-
-         if( controller->handle ){
-            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; i<VG_MAX_CONTROLLERS; i++ ){
-         struct vg_controller *esta = &vg_input.controllers[i];
-
-         if( ev->caxis.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; i<VG_MAX_CONTROLLERS; i++ ){
-            if( vg_input.controllers[i].instance_id == ev->cbutton.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; i<VG_MAX_CONTROLLERS; i++ ){
-         struct vg_controller *esta = &vg_input.controllers[i];
-
-         if( ev->cbutton.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; i<count; i++ ){
-         if( vg_input.sdl_keys[i] ){
-            vg_input.input_method = k_userinput_method_kbm;
-            break;
-         }
-      }
-
-      /* check for giving mouse priority */
-      if( SDL_GetMouseState(NULL,NULL) & 
-            (SDL_BUTTON(SDL_BUTTON_LEFT)|SDL_BUTTON(SDL_BUTTON_RIGHT)) )
-      {
-         vg_input.input_method = k_userinput_method_kbm;
-      }
-   }
-
-   /* update all inputs */
-   vg_input_update( vg_input.named_input_count, vg_input.named_inputs );
-}
-
-VG_STATIC int vg_console_enabled(void);
-VG_STATIC int vg_input_button_down( struct input_binding *bind )
-{
-   if( bind->button.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; i<joy_count; i++ ) {
-      const char *name = SDL_JoystickNameForIndex( i );
-      int is_controller = SDL_IsGameController(i);
-
-      vg_info( "%d: %s [controller: %d]\n", i, name, is_controller );
-
-      if( is_controller ){
-         vg_open_gamecontroller( i );
-      }
-   }
-}
-
-VG_STATIC void vg_input_init(void)
-{
-   vg_async_call( async_vg_input_init, NULL, 0 );
-}
-
-VG_STATIC void vg_input_free(void)
-{
-   for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
-      struct vg_controller *controller = &vg_input.controllers[i];
-
-      if( controller->handle ){
-         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 );