1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
6 #include "vg/vg_loader.h"
8 #define VG_MAX_CONTROLLERS 4
10 VG_STATIC
inline float vg_get_axis( const char *axis
);
11 VG_STATIC
inline int vg_get_button( const char *button
);
14 * Cannot be used in fixed update
16 VG_STATIC
inline int vg_get_button_down( const char *button
);
17 VG_STATIC
inline int vg_get_button_up( const char *button
);
18 VG_STATIC
float 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
33 k_input_type_axis_norm
,
36 k_input_type_keyboard_key
,
37 k_input_type_mouse_button
, /* ? TODO */
38 k_input_type_gamepad_axis
,
39 k_input_type_gamepad_button
45 SDL_GameControllerAxis gamepad_axis
;
46 SDL_Keycode keyboard_positive
,
55 SDL_GameControllerButton gamepad_id
;
56 SDL_Keycode keyboard_id
;
69 struct input_binding named_inputs
[ 32 ];
70 u32 named_input_count
;
73 SDL_GameController
*handle
; /* handle for controller. NULL if unused */
74 SDL_JoystickID instance_id
; /* uid used in events */
76 enum evg_controller_type
{
77 k_vg_controller_type_standard
,
78 k_vg_controller_type_trackpads
82 float axises
[ SDL_CONTROLLER_AXIS_MAX
];
83 int buttons
[ SDL_CONTROLLER_BUTTON_MAX
];
87 int active_controller_index
; /* most recent controller (by button press)
88 will be -1 if no controllers active */
90 /* what the user is currently using. the keyboard and controller are still
91 * active simultaneously, but this reflects what the UI should show */
92 enum userinput_method
{
93 k_userinput_method_xbox
,
94 k_userinput_method_playstation
,
95 k_userinput_method_steamgeneric
,
96 k_userinput_method_kbm
102 VG_STATIC
void vg_create_unnamed_input( struct input_binding
*bind
,
103 enum input_type type
)
105 memset( bind
, 0, sizeof(struct input_binding
) );
107 bind
->name
= "API DEFINED";
111 bind
->axis
.gamepad_axis
= -1;
112 bind
->axis
.keyboard_positive
= -1;
113 bind
->axis
.keyboard_negative
= -1;
114 bind
->button
.gamepad_id
= -1;
115 bind
->button
.keyboard_id
= -1;
116 bind
->button
.mouse_id
= -1;
119 VG_STATIC
struct input_binding
*vg_create_named_input( const char *name
,
120 enum input_type type
)
122 struct input_binding
*bind
=
123 &vg_input
.named_inputs
[ vg_input
.named_input_count
++ ];
124 memset( bind
, 0, sizeof(struct input_binding
) );
130 bind
->axis
.gamepad_axis
= -1;
131 bind
->axis
.keyboard_positive
= -1;
132 bind
->axis
.keyboard_negative
= -1;
133 bind
->button
.gamepad_id
= -1;
134 bind
->button
.keyboard_id
= -1;
135 bind
->button
.mouse_id
= -1;
140 VG_STATIC
struct input_binding
*vg_get_named_input( const char *name
)
142 if( name
[0] == '+' || name
[0] == '-' )
145 for( u32 i
=0; i
<vg_input
.named_input_count
; i
++ ){
146 struct input_binding
*bind
= &vg_input
.named_inputs
[i
];
147 if( !strcmp( bind
->name
, name
) )
156 enum input_type type
;
161 vg_all_bindable_inputs
[] =
163 {k_input_type_keyboard_key
, "space", SDLK_SPACE
},
164 {k_input_type_keyboard_key
, ";", SDLK_SEMICOLON
},
165 {k_input_type_keyboard_key
, "-", SDLK_MINUS
},
166 {k_input_type_keyboard_key
, ".", SDLK_PERIOD
},
167 {k_input_type_keyboard_key
, ",", SDLK_COMMA
},
168 {k_input_type_keyboard_key
, "=", SDLK_EQUALS
},
169 {k_input_type_keyboard_key
, "[", SDLK_LEFTBRACKET
},
170 {k_input_type_keyboard_key
, "]", SDLK_RIGHTBRACKET
},
171 {k_input_type_keyboard_key
, "left", SDLK_LEFT
},
172 {k_input_type_keyboard_key
, "right", SDLK_RIGHT
},
173 {k_input_type_keyboard_key
, "up", SDLK_UP
},
174 {k_input_type_keyboard_key
, "down", SDLK_DOWN
},
175 {k_input_type_keyboard_key
, "shift", SDLK_LSHIFT
},
176 {k_input_type_keyboard_key
, "control", SDLK_LCTRL
},
177 {k_input_type_keyboard_key
, "\2enter", SDLK_RETURN
},
178 {k_input_type_keyboard_key
, "\2escape", SDLK_ESCAPE
},
180 {k_input_type_gamepad_axis
, "gp-lt", SDL_CONTROLLER_AXIS_TRIGGERLEFT
},
181 {k_input_type_gamepad_axis
, "gp-rt", SDL_CONTROLLER_AXIS_TRIGGERRIGHT
},
182 {k_input_type_gamepad_axis
, "gp-ls-h", SDL_CONTROLLER_AXIS_LEFTX
},
183 {k_input_type_gamepad_axis
, "gp-ls-v", SDL_CONTROLLER_AXIS_LEFTY
},
184 {k_input_type_gamepad_axis
, "gp-rs-h", SDL_CONTROLLER_AXIS_RIGHTX
},
185 {k_input_type_gamepad_axis
, "gp-rs-v", SDL_CONTROLLER_AXIS_RIGHTY
},
187 {k_input_type_gamepad_button
, "gp-a", SDL_CONTROLLER_BUTTON_A
},
188 {k_input_type_gamepad_button
, "gp-b", SDL_CONTROLLER_BUTTON_B
},
189 {k_input_type_gamepad_button
, "gp-x", SDL_CONTROLLER_BUTTON_X
},
190 {k_input_type_gamepad_button
, "gp-y", SDL_CONTROLLER_BUTTON_Y
},
191 {k_input_type_gamepad_button
, "gp-rb", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
},
192 {k_input_type_gamepad_button
, "gp-lb", SDL_CONTROLLER_BUTTON_LEFTSHOULDER
},
193 {k_input_type_gamepad_button
, "gp-rs", SDL_CONTROLLER_BUTTON_RIGHTSTICK
},
194 {k_input_type_gamepad_button
, "gp-ls", SDL_CONTROLLER_BUTTON_LEFTSTICK
},
195 {k_input_type_gamepad_button
, "gp-dpad-down", SDL_CONTROLLER_BUTTON_DPAD_DOWN
},
196 {k_input_type_gamepad_button
, "gp-dpad-left", SDL_CONTROLLER_BUTTON_DPAD_LEFT
},
197 {k_input_type_gamepad_button
,"gp-dpad-right",SDL_CONTROLLER_BUTTON_DPAD_RIGHT
},
198 {k_input_type_gamepad_button
, "gp-dpad-up", SDL_CONTROLLER_BUTTON_DPAD_UP
},
199 {k_input_type_gamepad_button
, "\2gp-menu", SDL_CONTROLLER_BUTTON_BACK
},
201 {k_input_type_mouse_button
, "mouse1", SDL_BUTTON_LEFT
},
202 {k_input_type_mouse_button
, "mouse2", SDL_BUTTON_RIGHT
}
205 VG_STATIC
const char *vg_input_to_str( u32 input
, enum input_type input_type
)
210 if( input_type
== k_input_type_keyboard_key
){
211 if( (input
>= SDLK_a
) && (input
<= SDLK_z
) ){
212 return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
213 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input
-SDLK_a
)*2];
216 if( (input
>= SDLK_0
) && (input
<= SDLK_9
) ){
217 return &"0\0" "1\0" "2\0" "3\0" "4\0"
218 "5\0" "6\0" "7\0" "8\0" "9\0"[(input
-SDLK_0
)*2];
222 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ ){
223 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
225 if( (desc
->type
== input_type
) && (desc
->id
== input
) )
232 VG_STATIC
enum input_type
vg_str_to_input( const char *str
, u32
*input
)
236 return k_input_type_unknown
;
239 u32 len
= strlen(str
);
243 return k_input_type_unknown
;
249 if( (uch
>= (u8
)'a') && (uch
<= (u8
)'z') ){
250 *input
= SDLK_a
+ (uch
-(u8
)'a');
251 return k_input_type_keyboard_key
;
254 if( (uch
>= (u8
)'0') && (uch
<= (u8
)'9') ){
255 *input
= SDLK_0
+ (uch
-(u8
)'0');
256 return k_input_type_keyboard_key
;
260 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ ){
261 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
263 if( !strcmp( desc
->alias
, str
) ){
270 return k_input_type_unknown
;
273 VG_STATIC
void vg_print_binding_info( struct input_binding
*bind
)
275 vg_info( " name: %s\n", bind
->name
);
276 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
278 vg_info( " save this? %d\n", bind
->save_this
);
280 if( (bind
->type
== k_input_type_axis
) ||
281 (bind
->type
== k_input_type_axis_norm
) )
283 vg_info( " gamepad_axis: %s\n",
284 vg_input_to_str(bind
->axis
.gamepad_axis
, k_input_type_gamepad_axis
));
286 vg_info( " keyboard_positive: %s\n",
287 vg_input_to_str(bind
->axis
.keyboard_positive
,
288 k_input_type_keyboard_key
));
290 vg_info( " keyboard_negative: %s\n",
291 vg_input_to_str(bind
->axis
.keyboard_negative
,
292 k_input_type_keyboard_key
));
295 vg_info( " gamepad_id: %s\n",
296 vg_input_to_str(bind
->button
.gamepad_id
, k_input_type_gamepad_button
));
297 vg_info( " keyboard_id: %s\n",
298 vg_input_to_str(bind
->button
.keyboard_id
,
299 k_input_type_keyboard_key
));
300 vg_info( " mouse_id: %s\n",
301 vg_input_to_str(bind
->button
.mouse_id
,
302 k_input_type_mouse_button
));
306 VG_STATIC
void vg_apply_bind_str( struct input_binding
*bind
,
312 if( (mod
[0] == '-') || (mod
[0] == '+') ){
319 if( (str
[0] == '-' ) ){
325 enum input_type type
= vg_str_to_input( str
, &id
);
327 if( bind
->type
== k_input_type_button
){
329 vg_error( "Cannot use axis modifiers on button input!\n" );
334 vg_error( "Cannot invert button input!\n" );
338 if( type
== k_input_type_keyboard_key
)
339 bind
->button
.keyboard_id
= id
;
340 else if( type
== k_input_type_mouse_button
)
341 bind
->button
.mouse_id
= id
;
342 else if( type
== k_input_type_gamepad_button
)
343 bind
->button
.gamepad_id
= id
;
345 vg_error( "Unknown button or key '%s'\n", str
);
349 else if( (bind
->type
== k_input_type_axis
) ||
350 (bind
->type
== k_input_type_axis_norm
))
353 if( type
== k_input_type_keyboard_key
){
355 vg_error( "Cannot invert a keyboard key!\n" );
360 bind
->axis
.keyboard_positive
= id
;
362 bind
->axis
.keyboard_negative
= id
;
365 vg_error( "You can only bind keyboard keys to +- axises\n" );
370 if( type
== k_input_type_gamepad_axis
){
371 bind
->axis
.gamepad_inverted
= invert
;
372 bind
->axis
.gamepad_axis
= id
;
375 vg_error( "You can only bind gamepad axises to this\n" );
386 * bind horizontal -gp-ls-h
389 VG_STATIC
int vg_rebind_input_cmd( int argc
, const char *argv
[] )
392 vg_info( "Usage: bind jump x\n" );
393 vg_info( " bind -steerh j\n" );
394 vg_info( " bind steerh gp-ls-h\n" );
398 const char *str_bind_name
= argv
[0];
399 struct input_binding
*bind
= vg_get_named_input( str_bind_name
);
402 vg_error( "There is no bind with that name '%s'\n", str_bind_name
);
407 vg_print_binding_info( bind
);
412 const char *str_input_id
= argv
[1];
414 vg_apply_bind_str( bind
, str_bind_name
, str_input_id
);
421 VG_STATIC
void vg_rebind_input_cmd_poll( int argc
, const char *argv
[] )
426 const char *str_bind_name
= argv
[0];
429 for( u32 i
=0; i
<vg_input
.named_input_count
; i
++ ){
430 struct input_binding
*bind
= &vg_input
.named_inputs
[i
];
431 console_suggest_score_text( bind
->name
, argv
[argc
-1], 0 );
434 else if( argc
== 2 ){
435 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ ){
436 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
437 console_suggest_score_text( desc
->alias
, argv
[argc
-1], 0 );
442 VG_STATIC u8
vg_getkey( SDL_Keycode kc
)
444 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
445 return vg_input
.sdl_keys
[sc
];
448 VG_STATIC
void vg_input_update( u32 num
, struct input_binding
*binds
)
450 if( vg_console
.enabled
){
451 for( i32 i
=0; i
<num
; i
++ ){
452 struct input_binding
*bind
= &binds
[i
];
454 if( bind
->type
== k_input_type_button
){
455 bind
->button
.prev
= bind
->button
.value
;
456 bind
->button
.value
= 0;
463 struct vg_controller
*acontroller
= NULL
;
465 if( vg_input
.active_controller_index
!= -1 )
466 acontroller
= &vg_input
.controllers
[vg_input
.active_controller_index
];
468 for( i32 i
=0; i
<num
; i
++ ){
469 struct input_binding
*bind
= &binds
[i
];
471 if( bind
->type
== k_input_type_button
){
472 bind
->button
.prev
= bind
->button
.value
;
473 bind
->button
.value
= 0;
475 if( acontroller
&& (bind
->button
.gamepad_id
!= -1) )
476 bind
->button
.value
|= acontroller
->buttons
[bind
->button
.gamepad_id
];
478 if( bind
->button
.keyboard_id
!= -1 )
479 bind
->button
.value
|= vg_getkey( bind
->button
.keyboard_id
);
481 if( bind
->button
.mouse_id
!= -1 ){
482 if(SDL_GetMouseState(NULL
,NULL
) & SDL_BUTTON(bind
->button
.mouse_id
))
483 bind
->button
.value
|= 1;
486 else if( bind
->type
== k_input_type_axis
){
487 float keyboard_value
= 0.0f
,
488 gamepad_value
= 0.0f
;
490 if( bind
->axis
.keyboard_positive
!= -1 )
491 if( vg_getkey( bind
->axis
.keyboard_positive
) )
492 keyboard_value
+= 1.0f
;
494 if( bind
->axis
.keyboard_negative
!= -1 )
495 if( vg_getkey( bind
->axis
.keyboard_negative
) )
496 keyboard_value
-= 1.0f
;
498 if( acontroller
&& (bind
->axis
.gamepad_axis
!= -1) ){
499 gamepad_value
= acontroller
->axises
[ bind
->axis
.gamepad_axis
];
501 if( bind
->axis
.gamepad_inverted
)
502 gamepad_value
*= -1.0f
;
505 float deadz
= vg_clampf( controller_deadzone
, 0.0f
, 0.999f
),
506 high
= vg_maxf( 0.0f
, fabsf(gamepad_value
) - deadz
),
507 norm
= high
/ (1.0f
-deadz
);
509 gamepad_value
= vg_signf( gamepad_value
) * norm
;
511 if( fabsf(keyboard_value
) > fabsf(gamepad_value
) )
512 bind
->axis
.value
= keyboard_value
;
514 bind
->axis
.value
= gamepad_value
;
516 else if( bind
->type
== k_input_type_axis_norm
){
518 if( bind
->axis
.keyboard_positive
!= -1 )
519 if( vg_getkey( bind
->axis
.keyboard_positive
))
522 if( acontroller
&& (bind
->axis
.gamepad_axis
!= -1) ){
523 float value1
= acontroller
->axises
[bind
->axis
.gamepad_axis
];
524 value
= vg_maxf( value
, value1
);
527 bind
->axis
.value
= value
;
533 * takes SDL device index, and tries to open that on any free channel
535 VG_STATIC
void vg_open_gamecontroller( Sint32 index
)
537 struct vg_controller
*controller
= NULL
;
539 const char *name
= SDL_GameControllerNameForIndex( index
);
540 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
542 if( instance_id
== -1 ){
543 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
547 for( int j
=0; j
<VG_MAX_CONTROLLERS
; j
++ ){
548 struct vg_controller
*esta
= &vg_input
.controllers
[j
];
551 if( esta
->instance_id
== instance_id
){
552 vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n",
553 esta
->instance_id
, j
);
559 controller
= &vg_input
.controllers
[j
];
566 controller
->handle
= SDL_GameControllerOpen( index
);
567 controller
->instance_id
= instance_id
;
569 if( controller
->handle
){
571 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
572 instance_id
, name
, vg_id
);
574 controller
->axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
575 controller
->axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
578 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
579 name
, SDL_GetError() );
583 vg_error( ". Too many controllers open! ignoring '%s'\n", name
);
588 VG_STATIC
void vg_input_device_event( SDL_Event
*ev
)
590 if( ev
->type
== SDL_CONTROLLERDEVICEADDED
){
591 int is_controller
= SDL_IsGameController( ev
->cdevice
.which
);
592 const char *name
= SDL_JoystickNameForIndex( ev
->cdevice
.which
);
594 Sint32 index
= ev
->cdevice
.which
;
595 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
596 vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n",
600 vg_open_gamecontroller( index
);
603 else if( ev
->type
== SDL_CONTROLLERDEVICEREMOVED
){
604 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
607 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
608 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
610 if( controller
->handle
){
611 if( controller
->instance_id
== ev
->cdevice
.which
){
612 vg_info( " . closing controller at index #%d\n", i
);
613 SDL_GameControllerClose( controller
->handle
);
614 controller
->handle
= NULL
;
615 controller
->instance_id
= -1;
617 if( vg_input
.active_controller_index
== i
){
618 vg_input
.active_controller_index
= -1;
619 vg_info( " . active controller is now keyboard and mouse\n" );
628 VG_STATIC
void vg_input_controller_event( SDL_Event
*ev
)
630 if( ev
->type
== SDL_CONTROLLERAXISMOTION
){
631 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
632 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
634 if( ev
->caxis
.which
== esta
->instance_id
){
635 float value
= (float)ev
->caxis
.value
/ 32767.0f
;
636 esta
->axises
[ ev
->caxis
.axis
] = value
;
641 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
){
642 struct vg_controller
*active
= NULL
;
644 if( vg_input
.active_controller_index
!= -1 )
645 active
= &vg_input
.controllers
[vg_input
.active_controller_index
];
647 if( !active
|| (ev
->cbutton
.which
!= active
->instance_id
) ){
649 vg_input
.active_controller_index
= -1;
651 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
652 if( vg_input
.controllers
[i
].instance_id
== ev
->cbutton
.which
){
653 active
= &vg_input
.controllers
[i
];
654 vg_input
.active_controller_index
= i
;
660 vg_info( "Switching active controller index to #%d\n",
661 vg_input
.active_controller_index
);
664 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
670 active
->buttons
[ ev
->cbutton
.button
] = 1;
672 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
){
673 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
674 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
676 if( ev
->cbutton
.which
== esta
->instance_id
){
677 esta
->buttons
[ ev
->cbutton
.button
] = 0;
684 VG_STATIC
void vg_process_inputs(void)
687 vg_input
.sdl_keys
= SDL_GetKeyboardState( &count
);
689 if( vg_input
.input_method
!= k_userinput_method_kbm
){
690 /* check for giving keyboard priority */
691 for( int i
=0; i
<count
; i
++ ){
692 if( vg_input
.sdl_keys
[i
] ){
693 vg_input
.input_method
= k_userinput_method_kbm
;
698 /* check for giving mouse priority */
699 if( SDL_GetMouseState(NULL
,NULL
) &
700 (SDL_BUTTON(SDL_BUTTON_LEFT
)|SDL_BUTTON(SDL_BUTTON_RIGHT
)) )
702 vg_input
.input_method
= k_userinput_method_kbm
;
706 /* update all inputs */
707 vg_input_update( vg_input
.named_input_count
, vg_input
.named_inputs
);
710 VG_STATIC
int vg_console_enabled(void);
711 VG_STATIC
int vg_input_button_down( struct input_binding
*bind
)
713 if( bind
->button
.value
&& !bind
->button
.prev
)
718 VG_STATIC
void async_vg_input_init( void *payload
, u32 size
)
720 vg_console_reg_cmd( "bind", vg_rebind_input_cmd
, vg_rebind_input_cmd_poll
);
722 VG_VAR_F32( controller_deadzone
, flags
=VG_VAR_PERSISTENT
);
724 vg_info( "Checking for controllers\n" );
725 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
727 int joy_count
= SDL_NumJoysticks();
728 for( int i
=0; i
<joy_count
; i
++ ) {
729 const char *name
= SDL_JoystickNameForIndex( i
);
730 int is_controller
= SDL_IsGameController(i
);
732 vg_info( "%d: %s [controller: %d]\n", i
, name
, is_controller
);
735 vg_open_gamecontroller( i
);
740 VG_STATIC
void vg_input_init(void)
742 vg_async_call( async_vg_input_init
, NULL
, 0 );
745 VG_STATIC
void vg_input_free(void)
747 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
748 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
750 if( controller
->handle
){
751 SDL_GameControllerClose( controller
->handle
);
752 controller
->handle
= NULL
;