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
);
16 VG_STATIC
float controller_deadzone
= 0.05f
;
19 k_button_state_down
= 1,
20 k_button_state_up
= 3,
21 k_button_state_pressed
= 2,
22 k_button_state_none
= 0
31 k_input_type_axis_norm
,
34 k_input_type_keyboard_key
,
35 k_input_type_mouse_button
, /* ? TODO */
36 k_input_type_gamepad_axis
,
37 k_input_type_gamepad_button
43 SDL_GameControllerAxis gamepad_axis
;
44 SDL_Keycode keyboard_positive
,
53 SDL_GameControllerButton gamepad_id
;
54 SDL_Keycode keyboard_id
;
67 struct input_binding named_inputs
[ 32 ];
68 u32 named_input_count
;
70 const char *controller_name
;
71 SDL_GameController
*controller_handle
; /* null if unplugged */
72 SDL_JoystickID controller_joystick_id
;
73 int controller_should_use_trackpad_look
;
75 float controller_axises
[ SDL_CONTROLLER_AXIS_MAX
];
76 int controller_buttons
[ SDL_CONTROLLER_BUTTON_MAX
];
80 VG_STATIC
void vg_create_unnamed_input( struct input_binding
*bind
,
81 enum input_type type
)
83 memset( bind
, 0, sizeof(struct input_binding
) );
85 bind
->name
= "API DEFINED";
89 bind
->axis
.gamepad_axis
= -1;
90 bind
->axis
.keyboard_positive
= -1;
91 bind
->axis
.keyboard_negative
= -1;
92 bind
->button
.gamepad_id
= -1;
93 bind
->button
.keyboard_id
= -1;
94 bind
->button
.mouse_id
= -1;
97 VG_STATIC
struct input_binding
*vg_create_named_input( const char *name
,
98 enum input_type type
)
100 struct input_binding
*bind
=
101 &vg_input
.named_inputs
[ vg_input
.named_input_count
++ ];
102 memset( bind
, 0, sizeof(struct input_binding
) );
108 bind
->axis
.gamepad_axis
= -1;
109 bind
->axis
.keyboard_positive
= -1;
110 bind
->axis
.keyboard_negative
= -1;
111 bind
->button
.gamepad_id
= -1;
112 bind
->button
.keyboard_id
= -1;
113 bind
->button
.mouse_id
= -1;
118 VG_STATIC
struct input_binding
*vg_get_named_input( const char *name
)
120 if( name
[0] == '+' || name
[0] == '-' )
123 for( u32 i
=0; i
<vg_input
.named_input_count
; i
++ ){
124 struct input_binding
*bind
= &vg_input
.named_inputs
[i
];
125 if( !strcmp( bind
->name
, name
) )
134 enum input_type type
;
139 vg_all_bindable_inputs
[] =
141 {k_input_type_keyboard_key
, "space", SDLK_SPACE
},
142 {k_input_type_keyboard_key
, ";", SDLK_SEMICOLON
},
143 {k_input_type_keyboard_key
, "-", SDLK_MINUS
},
144 {k_input_type_keyboard_key
, ".", SDLK_PERIOD
},
145 {k_input_type_keyboard_key
, ",", SDLK_COMMA
},
146 {k_input_type_keyboard_key
, "=", SDLK_EQUALS
},
147 {k_input_type_keyboard_key
, "[", SDLK_LEFTBRACKET
},
148 {k_input_type_keyboard_key
, "]", SDLK_RIGHTBRACKET
},
149 {k_input_type_keyboard_key
, "left", SDLK_LEFT
},
150 {k_input_type_keyboard_key
, "right", SDLK_RIGHT
},
151 {k_input_type_keyboard_key
, "up", SDLK_UP
},
152 {k_input_type_keyboard_key
, "down", SDLK_DOWN
},
153 {k_input_type_keyboard_key
, "shift", SDLK_LSHIFT
},
154 {k_input_type_keyboard_key
, "control", SDLK_LCTRL
},
155 {k_input_type_keyboard_key
, "\2enter", SDLK_RETURN
},
156 {k_input_type_keyboard_key
, "\2escape", SDLK_ESCAPE
},
158 {k_input_type_gamepad_axis
, "gp-lt", SDL_CONTROLLER_AXIS_TRIGGERLEFT
},
159 {k_input_type_gamepad_axis
, "gp-rt", SDL_CONTROLLER_AXIS_TRIGGERRIGHT
},
160 {k_input_type_gamepad_axis
, "gp-ls-h", SDL_CONTROLLER_AXIS_LEFTX
},
161 {k_input_type_gamepad_axis
, "gp-ls-v", SDL_CONTROLLER_AXIS_LEFTY
},
162 {k_input_type_gamepad_axis
, "gp-rs-h", SDL_CONTROLLER_AXIS_RIGHTX
},
163 {k_input_type_gamepad_axis
, "gp-rs-v", SDL_CONTROLLER_AXIS_RIGHTY
},
165 {k_input_type_gamepad_button
, "gp-a", SDL_CONTROLLER_BUTTON_A
},
166 {k_input_type_gamepad_button
, "gp-b", SDL_CONTROLLER_BUTTON_B
},
167 {k_input_type_gamepad_button
, "gp-x", SDL_CONTROLLER_BUTTON_X
},
168 {k_input_type_gamepad_button
, "gp-y", SDL_CONTROLLER_BUTTON_Y
},
169 {k_input_type_gamepad_button
, "gp-rb", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
},
170 {k_input_type_gamepad_button
, "gp-lb", SDL_CONTROLLER_BUTTON_LEFTSHOULDER
},
171 {k_input_type_gamepad_button
, "gp-rs", SDL_CONTROLLER_BUTTON_RIGHTSTICK
},
172 {k_input_type_gamepad_button
, "gp-ls", SDL_CONTROLLER_BUTTON_LEFTSTICK
},
173 {k_input_type_gamepad_button
, "gp-dpad-down", SDL_CONTROLLER_BUTTON_DPAD_DOWN
},
174 {k_input_type_gamepad_button
, "gp-dpad-left", SDL_CONTROLLER_BUTTON_DPAD_LEFT
},
175 {k_input_type_gamepad_button
,"gp-dpad-right",SDL_CONTROLLER_BUTTON_DPAD_RIGHT
},
176 {k_input_type_gamepad_button
, "gp-dpad-up", SDL_CONTROLLER_BUTTON_DPAD_UP
},
177 {k_input_type_gamepad_button
, "\2gp-menu", SDL_CONTROLLER_BUTTON_BACK
},
179 {k_input_type_mouse_button
, "mouse1", SDL_BUTTON_LEFT
},
180 {k_input_type_mouse_button
, "mouse2", SDL_BUTTON_RIGHT
}
183 VG_STATIC
const char *vg_input_to_str( u32 input
, enum input_type input_type
)
188 if( input_type
== k_input_type_keyboard_key
){
189 if( (input
>= SDLK_a
) && (input
<= SDLK_z
) ){
190 return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
191 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input
-SDLK_a
)*2];
194 if( (input
>= SDLK_0
) && (input
<= SDLK_9
) ){
195 return &"0\0" "1\0" "2\0" "3\0" "4\0"
196 "5\0" "6\0" "7\0" "8\0" "9\0"[(input
-SDLK_0
)*2];
200 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ ){
201 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
203 if( (desc
->type
== input_type
) && (desc
->id
== input
) )
210 VG_STATIC
enum input_type
vg_str_to_input( const char *str
, u32
*input
)
214 return k_input_type_unknown
;
217 u32 len
= strlen(str
);
221 return k_input_type_unknown
;
227 if( (uch
>= (u8
)'a') && (uch
<= (u8
)'z') ){
228 *input
= SDLK_a
+ (uch
-(u8
)'a');
229 return k_input_type_keyboard_key
;
232 if( (uch
>= (u8
)'0') && (uch
<= (u8
)'9') ){
233 *input
= SDLK_0
+ (uch
-(u8
)'0');
234 return k_input_type_keyboard_key
;
238 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ ){
239 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
241 if( !strcmp( desc
->alias
, str
) ){
248 return k_input_type_unknown
;
251 VG_STATIC
void vg_print_binding_info( struct input_binding
*bind
)
253 vg_info( " name: %s\n", bind
->name
);
254 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
256 vg_info( " save this? %d\n", bind
->save_this
);
258 if( (bind
->type
== k_input_type_axis
) ||
259 (bind
->type
== k_input_type_axis_norm
) )
261 vg_info( " gamepad_axis: %s\n",
262 vg_input_to_str(bind
->axis
.gamepad_axis
, k_input_type_gamepad_axis
));
264 vg_info( " keyboard_positive: %s\n",
265 vg_input_to_str(bind
->axis
.keyboard_positive
,
266 k_input_type_keyboard_key
));
268 vg_info( " keyboard_negative: %s\n",
269 vg_input_to_str(bind
->axis
.keyboard_negative
,
270 k_input_type_keyboard_key
));
273 vg_info( " gamepad_id: %s\n",
274 vg_input_to_str(bind
->button
.gamepad_id
, k_input_type_gamepad_button
));
275 vg_info( " keyboard_id: %s\n",
276 vg_input_to_str(bind
->button
.keyboard_id
,
277 k_input_type_keyboard_key
));
278 vg_info( " mouse_id: %s\n",
279 vg_input_to_str(bind
->button
.mouse_id
,
280 k_input_type_mouse_button
));
284 VG_STATIC
void vg_apply_bind_str( struct input_binding
*bind
,
290 if( (mod
[0] == '-') || (mod
[0] == '+') ){
297 if( (str
[0] == '-' ) ){
303 enum input_type type
= vg_str_to_input( str
, &id
);
305 if( bind
->type
== k_input_type_button
){
307 vg_error( "Cannot use axis modifiers on button input!\n" );
312 vg_error( "Cannot invert button input!\n" );
316 if( type
== k_input_type_keyboard_key
)
317 bind
->button
.keyboard_id
= id
;
318 else if( type
== k_input_type_mouse_button
)
319 bind
->button
.mouse_id
= id
;
320 else if( type
== k_input_type_gamepad_button
)
321 bind
->button
.gamepad_id
= id
;
323 vg_error( "Unknown button or key '%s'\n", str
);
327 else if( (bind
->type
== k_input_type_axis
) ||
328 (bind
->type
== k_input_type_axis_norm
))
331 if( type
== k_input_type_keyboard_key
){
333 vg_error( "Cannot invert a keyboard key!\n" );
338 bind
->axis
.keyboard_positive
= id
;
340 bind
->axis
.keyboard_negative
= id
;
343 vg_error( "You can only bind keyboard keys to +- axises\n" );
348 if( type
== k_input_type_gamepad_axis
){
349 bind
->axis
.gamepad_inverted
= invert
;
350 bind
->axis
.gamepad_axis
= id
;
353 vg_error( "You can only bind gamepad axises to this\n" );
364 * bind horizontal -gp-ls-h
367 VG_STATIC
int vg_rebind_input_cmd( int argc
, const char *argv
[] )
370 vg_info( "Usage: bind jump x\n" );
371 vg_info( " bind -steerh j\n" );
372 vg_info( " bind steerh gp-ls-h\n" );
376 const char *str_bind_name
= argv
[0];
377 struct input_binding
*bind
= vg_get_named_input( str_bind_name
);
380 vg_error( "There is no bind with that name '%s'\n", str_bind_name
);
385 vg_print_binding_info( bind
);
390 const char *str_input_id
= argv
[1];
392 vg_apply_bind_str( bind
, str_bind_name
, str_input_id
);
399 VG_STATIC
void vg_rebind_input_cmd_poll( int argc
, const char *argv
[] )
404 const char *str_bind_name
= argv
[0];
407 for( u32 i
=0; i
<vg_input
.named_input_count
; i
++ ){
408 struct input_binding
*bind
= &vg_input
.named_inputs
[i
];
409 console_suggest_score_text( bind
->name
, argv
[argc
-1], 0 );
412 else if( argc
== 2 ){
413 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ ){
414 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
415 console_suggest_score_text( desc
->alias
, argv
[argc
-1], 0 );
420 VG_STATIC u8
vg_getkey( SDL_Keycode kc
)
422 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
423 return vg_input
.sdl_keys
[sc
];
426 VG_STATIC
void vg_input_update( u32 num
, struct input_binding
*binds
)
428 if( vg_console
.enabled
){
429 for( i32 i
=0; i
<num
; i
++ ){
430 struct input_binding
*bind
= &binds
[i
];
432 if( bind
->type
== k_input_type_button
){
433 bind
->button
.prev
= bind
->button
.value
;
434 bind
->button
.value
= 0;
441 for( i32 i
=0; i
<num
; i
++ ){
442 struct input_binding
*bind
= &binds
[i
];
444 if( bind
->type
== k_input_type_button
){
445 bind
->button
.prev
= bind
->button
.value
;
446 bind
->button
.value
= 0;
448 if( bind
->button
.gamepad_id
!= -1 )
449 bind
->button
.value
|=
450 vg_input
.controller_buttons
[ bind
->button
.gamepad_id
];
452 if( bind
->button
.keyboard_id
!= -1 ){
453 bind
->button
.value
|= vg_getkey( bind
->button
.keyboard_id
);
456 if( bind
->button
.mouse_id
!= -1 ){
457 if( SDL_GetMouseState(NULL
, NULL
) &
458 SDL_BUTTON( bind
->button
.mouse_id
) )
459 bind
->button
.value
|= 1;
462 else if( bind
->type
== k_input_type_axis
){
463 float keyboard_value
= 0.0f
,
464 gamepad_value
= 0.0f
;
466 if( bind
->axis
.keyboard_positive
!= -1 )
467 if( vg_getkey( bind
->axis
.keyboard_positive
) )
468 keyboard_value
+= 1.0f
;
470 if( bind
->axis
.keyboard_negative
!= -1 )
471 if( vg_getkey( bind
->axis
.keyboard_negative
) )
472 keyboard_value
-= 1.0f
;
474 if( bind
->axis
.gamepad_axis
!= -1 ){
476 vg_input
.controller_axises
[ bind
->axis
.gamepad_axis
];
478 if( bind
->axis
.gamepad_inverted
)
479 gamepad_value
*= -1.0f
;
482 float deadz
= vg_clampf( controller_deadzone
, 0.0f
, 0.999f
),
483 high
= vg_maxf( 0.0f
, fabsf(gamepad_value
) - deadz
),
484 norm
= high
/ (1.0f
-deadz
);
486 gamepad_value
= vg_signf( gamepad_value
) * norm
;
488 if( fabsf(keyboard_value
) > fabsf(gamepad_value
) )
489 bind
->axis
.value
= keyboard_value
;
491 bind
->axis
.value
= gamepad_value
;
493 else if( bind
->type
== k_input_type_axis_norm
){
495 if( bind
->axis
.keyboard_positive
!= -1 )
496 if( vg_getkey( bind
->axis
.keyboard_positive
))
499 if( bind
->axis
.gamepad_axis
!= -1 )
500 value
= vg_maxf( value
,
501 vg_input
.controller_axises
[bind
->axis
.gamepad_axis
] );
503 bind
->axis
.value
= value
;
508 VG_STATIC
void vg_input_controller_event( SDL_Event
*ev
)
510 if( ev
->type
== SDL_CONTROLLERAXISMOTION
){
511 if( ev
->caxis
.which
== vg_input
.controller_joystick_id
){
512 vg_input
.controller_axises
[ ev
->caxis
.axis
] =
513 (float)ev
->caxis
.value
/ 32767.0f
;
516 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
){
517 if( ev
->cbutton
.which
== vg_input
.controller_joystick_id
)
518 vg_input
.controller_buttons
[ ev
->cbutton
.button
] = 1;
520 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
){
521 if( ev
->cbutton
.which
== vg_input
.controller_joystick_id
)
522 vg_input
.controller_buttons
[ ev
->cbutton
.button
] = 0;
526 VG_STATIC
void vg_try_attach_controller(void)
528 int joy_count
= SDL_NumJoysticks();
529 for( int i
=0; i
<joy_count
; i
++ ) {
530 if( SDL_IsGameController(i
) ) {
531 vg_input
.controller_handle
= SDL_GameControllerOpen(i
);
532 vg_input
.controller_joystick_id
= i
;
533 vg_success( "Attached game controller with joystick ID %d\n", i
);
539 VG_STATIC
void vg_update_inputs(void)
541 vg_input
.sdl_keys
= SDL_GetKeyboardState(NULL
);
543 if( vg_input
.controller_handle
){
544 if( !SDL_GameControllerGetAttached( vg_input
.controller_handle
) ){
545 SDL_GameControllerClose( vg_input
.controller_handle
);
546 vg_input
.controller_handle
= NULL
;
550 if( !vg_input
.controller_handle
){
551 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
552 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
553 vg_try_attach_controller();
556 /* update all inputs */
557 vg_input_update( vg_input
.named_input_count
, vg_input
.named_inputs
);
560 VG_STATIC
int vg_console_enabled(void);
561 VG_STATIC
int vg_input_button_down( struct input_binding
*bind
)
563 if( bind
->button
.value
&& !bind
->button
.prev
)
568 VG_STATIC
void vg_input_init(void)
570 vg_acquire_thread_sync();
572 vg_console_reg_cmd( "bind", vg_rebind_input_cmd
, vg_rebind_input_cmd_poll
);
574 VG_VAR_F32( controller_deadzone
, flags
=VG_VAR_PERSISTENT
);
575 vg_info( "Checking for controller\n" );
576 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
578 int joy_count
= SDL_NumJoysticks();
579 for( int i
=0; i
<joy_count
; i
++ )
581 vg_info( "joystick %d: %s [gamecontroller: %d]\n",
582 i
, SDL_JoystickNameForIndex( i
),
583 SDL_IsGameController(i
) );
586 vg_try_attach_controller();
588 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
589 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
591 vg_release_thread_sync();
594 VG_STATIC
void vg_input_free(void)
596 if( vg_input
.controller_handle
){
597 SDL_GameControllerClose( vg_input
.controller_handle
);
598 vg_input
.controller_handle
= NULL
;