1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
6 #include "vg/vg_loader.h"
8 VG_STATIC
inline float vg_get_axis( const char *axis
);
9 VG_STATIC
inline int vg_get_button( const char *button
);
12 * Cannot be used in fixed update
14 VG_STATIC
inline int vg_get_button_down( const char *button
);
15 VG_STATIC
inline int vg_get_button_up( const char *button
);
17 VG_STATIC
float g_controller_deadzone
= 0.05f
;
21 k_button_state_down
= 1,
22 k_button_state_up
= 3,
23 k_button_state_pressed
= 2,
24 k_button_state_none
= 0
35 k_input_type_axis_norm
,
38 k_input_type_keyboard_key
,
39 k_input_type_mouse_button
, /* ? TODO */
40 k_input_type_gamepad_axis
,
41 k_input_type_gamepad_button
49 SDL_GameControllerAxis gamepad_axis
;
50 SDL_Keycode keyboard_positive
,
60 SDL_GameControllerButton gamepad_id
;
61 SDL_Keycode keyboard_id
;
73 struct input_binding named_inputs
[ 32 ];
74 u32 named_input_count
;
76 const char *controller_name
;
77 SDL_GameController
*controller_handle
; /* null if unplugged */
78 SDL_JoystickID controller_joystick_id
;
79 int controller_should_use_trackpad_look
;
81 float controller_axises
[ SDL_CONTROLLER_AXIS_MAX
];
82 int controller_buttons
[ SDL_CONTROLLER_BUTTON_MAX
];
86 VG_STATIC
void vg_create_unnamed_input( struct input_binding
*bind
,
87 enum input_type type
)
89 memset( bind
, 0, sizeof(struct input_binding
) );
91 bind
->name
= "API DEFINED";
95 bind
->axis
.gamepad_axis
= -1;
96 bind
->axis
.keyboard_positive
= -1;
97 bind
->axis
.keyboard_negative
= -1;
98 bind
->button
.gamepad_id
= -1;
99 bind
->button
.keyboard_id
= -1;
102 VG_STATIC
struct input_binding
*vg_create_named_input( const char *name
,
103 enum input_type type
)
105 struct input_binding
*bind
=
106 &vg_input
.named_inputs
[ vg_input
.named_input_count
++ ];
107 memset( bind
, 0, sizeof(struct input_binding
) );
113 bind
->axis
.gamepad_axis
= -1;
114 bind
->axis
.keyboard_positive
= -1;
115 bind
->axis
.keyboard_negative
= -1;
116 bind
->button
.gamepad_id
= -1;
117 bind
->button
.keyboard_id
= -1;
122 VG_STATIC
struct input_binding
*vg_get_named_input( const char *name
)
124 if( name
[0] == '+' || name
[0] == '-' )
127 for( u32 i
=0; i
<vg_input
.named_input_count
; i
++ )
129 struct input_binding
*bind
= &vg_input
.named_inputs
[i
];
130 if( !strcmp( bind
->name
, name
) )
139 enum input_type type
;
144 vg_all_bindable_inputs
[] =
146 {k_input_type_keyboard_key
, "space", SDLK_SPACE
},
147 {k_input_type_keyboard_key
, ";", SDLK_SEMICOLON
},
148 {k_input_type_keyboard_key
, "-", SDLK_MINUS
},
149 {k_input_type_keyboard_key
, ".", SDLK_PERIOD
},
150 {k_input_type_keyboard_key
, ",", SDLK_COMMA
},
151 {k_input_type_keyboard_key
, "=", SDLK_EQUALS
},
152 {k_input_type_keyboard_key
, "[", SDLK_LEFTBRACKET
},
153 {k_input_type_keyboard_key
, "]", SDLK_RIGHTBRACKET
},
154 {k_input_type_keyboard_key
, "left", SDLK_LEFT
},
155 {k_input_type_keyboard_key
, "right", SDLK_RIGHT
},
156 {k_input_type_keyboard_key
, "up", SDLK_UP
},
157 {k_input_type_keyboard_key
, "down", SDLK_DOWN
},
158 {k_input_type_keyboard_key
, "shift", SDLK_LSHIFT
},
159 {k_input_type_keyboard_key
, "control", SDLK_LCTRL
},
160 {k_input_type_keyboard_key
, "\2enter", SDLK_RETURN
},
161 {k_input_type_keyboard_key
, "\2escape", SDLK_ESCAPE
},
163 {k_input_type_gamepad_axis
, "gp-lt", SDL_CONTROLLER_AXIS_TRIGGERLEFT
},
164 {k_input_type_gamepad_axis
, "gp-rt", SDL_CONTROLLER_AXIS_TRIGGERRIGHT
},
165 {k_input_type_gamepad_axis
, "gp-ls-h", SDL_CONTROLLER_AXIS_LEFTX
},
166 {k_input_type_gamepad_axis
, "gp-ls-v", SDL_CONTROLLER_AXIS_LEFTY
},
167 {k_input_type_gamepad_axis
, "gp-rs-h", SDL_CONTROLLER_AXIS_RIGHTX
},
168 {k_input_type_gamepad_axis
, "gp-rs-v", SDL_CONTROLLER_AXIS_RIGHTY
},
170 {k_input_type_gamepad_button
, "gp-a", SDL_CONTROLLER_BUTTON_A
},
171 {k_input_type_gamepad_button
, "gp-b", SDL_CONTROLLER_BUTTON_B
},
172 {k_input_type_gamepad_button
, "gp-x", SDL_CONTROLLER_BUTTON_X
},
173 {k_input_type_gamepad_button
, "gp-y", SDL_CONTROLLER_BUTTON_Y
},
174 {k_input_type_gamepad_button
, "gp-rb", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
},
175 {k_input_type_gamepad_button
, "gp-lb", SDL_CONTROLLER_BUTTON_LEFTSHOULDER
},
176 {k_input_type_gamepad_button
, "gp-rs", SDL_CONTROLLER_BUTTON_RIGHTSTICK
},
177 {k_input_type_gamepad_button
, "gp-ls", SDL_CONTROLLER_BUTTON_LEFTSTICK
},
178 {k_input_type_gamepad_button
, "gp-dpad-down", SDL_CONTROLLER_BUTTON_DPAD_DOWN
},
179 {k_input_type_gamepad_button
, "gp-dpad-left", SDL_CONTROLLER_BUTTON_DPAD_LEFT
},
180 {k_input_type_gamepad_button
,"gp-dpad-right",SDL_CONTROLLER_BUTTON_DPAD_RIGHT
},
181 {k_input_type_gamepad_button
, "gp-dpad-up", SDL_CONTROLLER_BUTTON_DPAD_UP
},
182 {k_input_type_gamepad_button
, "\2gp-menu", SDL_CONTROLLER_BUTTON_BACK
}
185 VG_STATIC
const char *vg_input_to_str( u32 input
, enum input_type input_type
)
190 if( input_type
== k_input_type_keyboard_key
)
192 if( (input
>= SDLK_a
) && (input
<= SDLK_z
) )
194 return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
195 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input
-SDLK_a
)*2];
198 if( (input
>= SDLK_0
) && (input
<= SDLK_9
) )
200 return &"0\0" "1\0" "2\0" "3\0" "4\0"
201 "5\0" "6\0" "7\0" "8\0" "9\0"[(input
-SDLK_0
)*2];
205 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ )
207 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
209 if( (desc
->type
== input_type
) && (desc
->id
== input
) )
216 VG_STATIC
enum input_type
vg_str_to_input( const char *str
, u32
*input
)
221 return k_input_type_unknown
;
224 u32 len
= strlen(str
);
229 return k_input_type_unknown
;
236 if( (uch
>= (u8
)'a') && (uch
<= (u8
)'z') )
238 *input
= SDLK_a
+ (uch
-(u8
)'a');
239 return k_input_type_keyboard_key
;
242 if( (uch
>= (u8
)'0') && (uch
<= (u8
)'9') )
244 *input
= SDLK_0
+ (uch
-(u8
)'0');
245 return k_input_type_keyboard_key
;
249 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ )
251 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
253 if( !strcmp( desc
->alias
, str
) )
261 return k_input_type_unknown
;
264 VG_STATIC
void vg_print_binding_info( struct input_binding
*bind
)
266 vg_info( " name: %s\n", bind
->name
);
267 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
269 vg_info( " save this? %d\n", bind
->save_this
);
271 if( (bind
->type
== k_input_type_axis
) ||
272 (bind
->type
== k_input_type_axis_norm
) )
274 vg_info( " gamepad_axis: %s\n",
275 vg_input_to_str(bind
->axis
.gamepad_axis
, k_input_type_gamepad_axis
));
277 vg_info( " keyboard_positive: %s\n",
278 vg_input_to_str(bind
->axis
.keyboard_positive
,
279 k_input_type_keyboard_key
));
281 vg_info( " keyboard_negative: %s\n",
282 vg_input_to_str(bind
->axis
.keyboard_negative
,
283 k_input_type_keyboard_key
));
287 vg_info( " gamepad_id: %s\n",
288 vg_input_to_str(bind
->button
.gamepad_id
, k_input_type_gamepad_button
));
289 vg_info( " keyboard_id: %s\n",
290 vg_input_to_str(bind
->button
.keyboard_id
,
291 k_input_type_keyboard_key
));
295 VG_STATIC
void vg_apply_bind_str( struct input_binding
*bind
,
301 if( (mod
[0] == '-') || (mod
[0] == '+') )
309 if( (str
[0] == '-' ) )
316 enum input_type type
= vg_str_to_input( str
, &id
);
318 if( bind
->type
== k_input_type_button
)
322 vg_error( "Cannot use axis modifiers on button input!\n" );
328 vg_error( "Cannot invert button input!\n" );
332 if( type
== k_input_type_keyboard_key
)
333 bind
->button
.keyboard_id
= id
;
334 else if( type
== k_input_type_gamepad_button
)
335 bind
->button
.gamepad_id
= id
;
338 vg_error( "Unknown button or key '%s'\n", str
);
342 else if( (bind
->type
== k_input_type_axis
) ||
343 (bind
->type
== k_input_type_axis_norm
))
347 if( type
== k_input_type_keyboard_key
)
351 vg_error( "Cannot invert a keyboard key!\n" );
356 bind
->axis
.keyboard_positive
= id
;
358 bind
->axis
.keyboard_negative
= id
;
362 vg_error( "You can only bind keyboard keys to +- axises\n" );
368 if( type
== k_input_type_gamepad_axis
)
370 bind
->axis
.gamepad_inverted
= invert
;
371 bind
->axis
.gamepad_axis
= id
;
375 vg_error( "You can only bind gamepad axises to this\n" );
386 * bind -gp-ls-h horizontal
389 VG_STATIC
int vg_rebind_input_cmd( int argc
, const char *argv
[] )
393 vg_info( "Usage: bind jump x\n" );
394 vg_info( " bind -steerh j\n" );
395 vg_info( " bind steerh gp-ls-h\n" );
399 const char *str_bind_name
= argv
[0];
400 struct input_binding
*bind
= vg_get_named_input( str_bind_name
);
404 vg_error( "There is no bind with that name '%s'\n", str_bind_name
);
410 vg_print_binding_info( bind
);
416 const char *str_input_id
= argv
[1];
418 vg_apply_bind_str( bind
, str_bind_name
, str_input_id
);
425 VG_STATIC u8
vg_getkey( SDL_Keycode kc
)
427 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
428 return vg_input
.sdl_keys
[sc
];
431 VG_STATIC
void vg_input_update( u32 num
, struct input_binding
*binds
)
433 if( vg_console
.enabled
)
435 for( i32 i
=0; i
<num
; i
++ )
437 struct input_binding
*bind
= &binds
[i
];
439 if( bind
->type
== k_input_type_button
)
441 bind
->button
.prev
= bind
->button
.value
;
442 bind
->button
.value
= 0;
449 for( i32 i
=0; i
<num
; i
++ )
451 struct input_binding
*bind
= &binds
[i
];
453 if( bind
->type
== k_input_type_button
)
455 bind
->button
.prev
= bind
->button
.value
;
456 bind
->button
.value
= 0;
458 if( bind
->button
.gamepad_id
!= -1 )
459 bind
->button
.value
|=
460 vg_input
.controller_buttons
[ bind
->button
.gamepad_id
];
462 if( bind
->button
.keyboard_id
!= -1 )
463 bind
->button
.value
|= vg_getkey( bind
->button
.keyboard_id
);
465 else if( bind
->type
== k_input_type_axis
)
467 float keyboard_value
= 0.0f
,
468 gamepad_value
= 0.0f
;
470 if( bind
->axis
.keyboard_positive
!= -1 )
471 if( vg_getkey( bind
->axis
.keyboard_positive
) )
472 keyboard_value
+= 1.0f
;
474 if( bind
->axis
.keyboard_negative
!= -1 )
475 if( vg_getkey( bind
->axis
.keyboard_negative
) )
476 keyboard_value
-= 1.0f
;
478 if( bind
->axis
.gamepad_axis
!= -1 )
481 vg_input
.controller_axises
[ bind
->axis
.gamepad_axis
];
483 if( bind
->axis
.gamepad_inverted
)
484 gamepad_value
*= -1.0f
;
487 float deadz
= vg_clampf( g_controller_deadzone
, 0.0f
, 0.999f
),
488 high
= vg_maxf( 0.0f
, fabsf(gamepad_value
) - deadz
),
489 norm
= high
/ (1.0f
-deadz
);
491 gamepad_value
= vg_signf( gamepad_value
) * norm
;
493 if( fabsf(keyboard_value
) > fabsf(gamepad_value
) )
494 bind
->axis
.value
= keyboard_value
;
496 bind
->axis
.value
= gamepad_value
;
498 else if( bind
->type
== k_input_type_axis_norm
)
501 if( bind
->axis
.keyboard_positive
!= -1 )
502 if( vg_getkey( bind
->axis
.keyboard_positive
))
505 if( bind
->axis
.gamepad_axis
!= -1 )
506 value
= vg_maxf( value
,
507 vg_input
.controller_axises
[bind
->axis
.gamepad_axis
] );
509 bind
->axis
.value
= value
;
514 VG_STATIC
void vg_input_controller_event( SDL_Event
*ev
)
516 if( ev
->type
== SDL_CONTROLLERAXISMOTION
)
518 if( ev
->caxis
.which
== vg_input
.controller_joystick_id
)
520 vg_input
.controller_axises
[ ev
->caxis
.axis
] =
521 (float)ev
->caxis
.value
/ 32767.0f
;
524 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
)
526 if( ev
->cbutton
.which
== vg_input
.controller_joystick_id
)
527 vg_input
.controller_buttons
[ ev
->cbutton
.button
] = 1;
529 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
)
531 if( ev
->cbutton
.which
== vg_input
.controller_joystick_id
)
532 vg_input
.controller_buttons
[ ev
->cbutton
.button
] = 0;
536 VG_STATIC
void vg_try_attach_controller(void)
538 int joy_count
= SDL_NumJoysticks();
539 for( int i
=0; i
<joy_count
; i
++ )
541 if( SDL_IsGameController(i
) )
543 vg_input
.controller_handle
= SDL_GameControllerOpen(i
);
544 vg_input
.controller_joystick_id
= i
;
545 vg_success( "Attached game controller with joystick ID %d\n", i
);
552 VG_STATIC
void vg_update_inputs(void)
554 vg_input
.sdl_keys
= SDL_GetKeyboardState(NULL
);
556 if( vg_input
.controller_handle
)
558 if( !SDL_GameControllerGetAttached( vg_input
.controller_handle
) )
560 SDL_GameControllerClose( vg_input
.controller_handle
);
561 vg_input
.controller_handle
= NULL
;
565 if( !vg_input
.controller_handle
)
567 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
568 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
569 vg_try_attach_controller();
572 /* update all inputs */
573 vg_input_update( vg_input
.named_input_count
, vg_input
.named_inputs
);
576 VG_STATIC
int vg_console_enabled(void);
577 VG_STATIC
int vg_input_button_down( struct input_binding
*bind
)
579 if( bind
->button
.value
&& !bind
->button
.prev
)
584 VG_STATIC
void vg_input_init(void)
586 vg_acquire_thread_sync();
588 vg_function_push( (struct vg_cmd
)
591 .function
= vg_rebind_input_cmd
594 vg_convar_push( (struct vg_convar
){
595 .name
= "controller_deadzone",
596 .data
= &g_controller_deadzone
,
597 .data_type
= k_convar_dtype_f32
,
598 .opt_f32
= { .clamp
= 0 },
602 vg_info( "Checking for controller\n" );
603 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
605 int joy_count
= SDL_NumJoysticks();
606 for( int i
=0; i
<joy_count
; i
++ )
608 vg_info( "joystick %d: %s [gamecontroller: %d]\n",
609 i
, SDL_JoystickNameForIndex( i
),
610 SDL_IsGameController(i
) );
613 vg_try_attach_controller();
615 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
616 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
618 vg_release_thread_sync();
621 VG_STATIC
void vg_input_free(void)
623 if( vg_input
.controller_handle
)
625 SDL_GameControllerClose( vg_input
.controller_handle
);
626 vg_input
.controller_handle
= NULL
;