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
;
74 struct input_binding named_inputs
[ 32 ];
75 u32 named_input_count
;
77 const char *controller_name
;
78 SDL_GameController
*controller_handle
; /* null if unplugged */
79 SDL_JoystickID controller_joystick_id
;
80 int controller_should_use_trackpad_look
;
82 float controller_axises
[ SDL_CONTROLLER_AXIS_MAX
];
83 int controller_buttons
[ SDL_CONTROLLER_BUTTON_MAX
];
87 VG_STATIC
void vg_create_unnamed_input( struct input_binding
*bind
,
88 enum input_type type
)
90 memset( bind
, 0, sizeof(struct input_binding
) );
92 bind
->name
= "API DEFINED";
96 bind
->axis
.gamepad_axis
= -1;
97 bind
->axis
.keyboard_positive
= -1;
98 bind
->axis
.keyboard_negative
= -1;
99 bind
->button
.gamepad_id
= -1;
100 bind
->button
.keyboard_id
= -1;
101 bind
->button
.mouse_id
= -1;
104 VG_STATIC
struct input_binding
*vg_create_named_input( const char *name
,
105 enum input_type type
)
107 struct input_binding
*bind
=
108 &vg_input
.named_inputs
[ vg_input
.named_input_count
++ ];
109 memset( bind
, 0, sizeof(struct input_binding
) );
115 bind
->axis
.gamepad_axis
= -1;
116 bind
->axis
.keyboard_positive
= -1;
117 bind
->axis
.keyboard_negative
= -1;
118 bind
->button
.gamepad_id
= -1;
119 bind
->button
.keyboard_id
= -1;
120 bind
->button
.mouse_id
= -1;
125 VG_STATIC
struct input_binding
*vg_get_named_input( const char *name
)
127 if( name
[0] == '+' || name
[0] == '-' )
130 for( u32 i
=0; i
<vg_input
.named_input_count
; i
++ )
132 struct input_binding
*bind
= &vg_input
.named_inputs
[i
];
133 if( !strcmp( bind
->name
, name
) )
142 enum input_type type
;
147 vg_all_bindable_inputs
[] =
149 {k_input_type_keyboard_key
, "space", SDLK_SPACE
},
150 {k_input_type_keyboard_key
, ";", SDLK_SEMICOLON
},
151 {k_input_type_keyboard_key
, "-", SDLK_MINUS
},
152 {k_input_type_keyboard_key
, ".", SDLK_PERIOD
},
153 {k_input_type_keyboard_key
, ",", SDLK_COMMA
},
154 {k_input_type_keyboard_key
, "=", SDLK_EQUALS
},
155 {k_input_type_keyboard_key
, "[", SDLK_LEFTBRACKET
},
156 {k_input_type_keyboard_key
, "]", SDLK_RIGHTBRACKET
},
157 {k_input_type_keyboard_key
, "left", SDLK_LEFT
},
158 {k_input_type_keyboard_key
, "right", SDLK_RIGHT
},
159 {k_input_type_keyboard_key
, "up", SDLK_UP
},
160 {k_input_type_keyboard_key
, "down", SDLK_DOWN
},
161 {k_input_type_keyboard_key
, "shift", SDLK_LSHIFT
},
162 {k_input_type_keyboard_key
, "control", SDLK_LCTRL
},
163 {k_input_type_keyboard_key
, "\2enter", SDLK_RETURN
},
164 {k_input_type_keyboard_key
, "\2escape", SDLK_ESCAPE
},
166 {k_input_type_gamepad_axis
, "gp-lt", SDL_CONTROLLER_AXIS_TRIGGERLEFT
},
167 {k_input_type_gamepad_axis
, "gp-rt", SDL_CONTROLLER_AXIS_TRIGGERRIGHT
},
168 {k_input_type_gamepad_axis
, "gp-ls-h", SDL_CONTROLLER_AXIS_LEFTX
},
169 {k_input_type_gamepad_axis
, "gp-ls-v", SDL_CONTROLLER_AXIS_LEFTY
},
170 {k_input_type_gamepad_axis
, "gp-rs-h", SDL_CONTROLLER_AXIS_RIGHTX
},
171 {k_input_type_gamepad_axis
, "gp-rs-v", SDL_CONTROLLER_AXIS_RIGHTY
},
173 {k_input_type_gamepad_button
, "gp-a", SDL_CONTROLLER_BUTTON_A
},
174 {k_input_type_gamepad_button
, "gp-b", SDL_CONTROLLER_BUTTON_B
},
175 {k_input_type_gamepad_button
, "gp-x", SDL_CONTROLLER_BUTTON_X
},
176 {k_input_type_gamepad_button
, "gp-y", SDL_CONTROLLER_BUTTON_Y
},
177 {k_input_type_gamepad_button
, "gp-rb", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
},
178 {k_input_type_gamepad_button
, "gp-lb", SDL_CONTROLLER_BUTTON_LEFTSHOULDER
},
179 {k_input_type_gamepad_button
, "gp-rs", SDL_CONTROLLER_BUTTON_RIGHTSTICK
},
180 {k_input_type_gamepad_button
, "gp-ls", SDL_CONTROLLER_BUTTON_LEFTSTICK
},
181 {k_input_type_gamepad_button
, "gp-dpad-down", SDL_CONTROLLER_BUTTON_DPAD_DOWN
},
182 {k_input_type_gamepad_button
, "gp-dpad-left", SDL_CONTROLLER_BUTTON_DPAD_LEFT
},
183 {k_input_type_gamepad_button
,"gp-dpad-right",SDL_CONTROLLER_BUTTON_DPAD_RIGHT
},
184 {k_input_type_gamepad_button
, "gp-dpad-up", SDL_CONTROLLER_BUTTON_DPAD_UP
},
185 {k_input_type_gamepad_button
, "\2gp-menu", SDL_CONTROLLER_BUTTON_BACK
},
187 {k_input_type_mouse_button
, "mouse1", SDL_BUTTON_LEFT
},
188 {k_input_type_mouse_button
, "mouse2", SDL_BUTTON_RIGHT
}
191 VG_STATIC
const char *vg_input_to_str( u32 input
, enum input_type input_type
)
196 if( input_type
== k_input_type_keyboard_key
)
198 if( (input
>= SDLK_a
) && (input
<= SDLK_z
) )
200 return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
201 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input
-SDLK_a
)*2];
204 if( (input
>= SDLK_0
) && (input
<= SDLK_9
) )
206 return &"0\0" "1\0" "2\0" "3\0" "4\0"
207 "5\0" "6\0" "7\0" "8\0" "9\0"[(input
-SDLK_0
)*2];
211 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ )
213 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
215 if( (desc
->type
== input_type
) && (desc
->id
== input
) )
222 VG_STATIC
enum input_type
vg_str_to_input( const char *str
, u32
*input
)
227 return k_input_type_unknown
;
230 u32 len
= strlen(str
);
235 return k_input_type_unknown
;
242 if( (uch
>= (u8
)'a') && (uch
<= (u8
)'z') )
244 *input
= SDLK_a
+ (uch
-(u8
)'a');
245 return k_input_type_keyboard_key
;
248 if( (uch
>= (u8
)'0') && (uch
<= (u8
)'9') )
250 *input
= SDLK_0
+ (uch
-(u8
)'0');
251 return k_input_type_keyboard_key
;
255 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ )
257 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
259 if( !strcmp( desc
->alias
, str
) )
267 return k_input_type_unknown
;
270 VG_STATIC
void vg_print_binding_info( struct input_binding
*bind
)
272 vg_info( " name: %s\n", bind
->name
);
273 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
275 vg_info( " save this? %d\n", bind
->save_this
);
277 if( (bind
->type
== k_input_type_axis
) ||
278 (bind
->type
== k_input_type_axis_norm
) )
280 vg_info( " gamepad_axis: %s\n",
281 vg_input_to_str(bind
->axis
.gamepad_axis
, k_input_type_gamepad_axis
));
283 vg_info( " keyboard_positive: %s\n",
284 vg_input_to_str(bind
->axis
.keyboard_positive
,
285 k_input_type_keyboard_key
));
287 vg_info( " keyboard_negative: %s\n",
288 vg_input_to_str(bind
->axis
.keyboard_negative
,
289 k_input_type_keyboard_key
));
293 vg_info( " gamepad_id: %s\n",
294 vg_input_to_str(bind
->button
.gamepad_id
, k_input_type_gamepad_button
));
295 vg_info( " keyboard_id: %s\n",
296 vg_input_to_str(bind
->button
.keyboard_id
,
297 k_input_type_keyboard_key
));
298 vg_info( " mouse_id: %s\n",
299 vg_input_to_str(bind
->button
.mouse_id
,
300 k_input_type_mouse_button
));
304 VG_STATIC
void vg_apply_bind_str( struct input_binding
*bind
,
310 if( (mod
[0] == '-') || (mod
[0] == '+') )
318 if( (str
[0] == '-' ) )
325 enum input_type type
= vg_str_to_input( str
, &id
);
327 if( bind
->type
== k_input_type_button
)
331 vg_error( "Cannot use axis modifiers on button input!\n" );
337 vg_error( "Cannot invert button input!\n" );
341 if( type
== k_input_type_keyboard_key
)
342 bind
->button
.keyboard_id
= id
;
343 else if( type
== k_input_type_mouse_button
)
344 bind
->button
.mouse_id
= id
;
345 else if( type
== k_input_type_gamepad_button
)
346 bind
->button
.gamepad_id
= id
;
349 vg_error( "Unknown button or key '%s'\n", str
);
353 else if( (bind
->type
== k_input_type_axis
) ||
354 (bind
->type
== k_input_type_axis_norm
))
358 if( type
== k_input_type_keyboard_key
)
362 vg_error( "Cannot invert a keyboard key!\n" );
367 bind
->axis
.keyboard_positive
= id
;
369 bind
->axis
.keyboard_negative
= id
;
373 vg_error( "You can only bind keyboard keys to +- axises\n" );
379 if( type
== k_input_type_gamepad_axis
)
381 bind
->axis
.gamepad_inverted
= invert
;
382 bind
->axis
.gamepad_axis
= id
;
386 vg_error( "You can only bind gamepad axises to this\n" );
397 * bind horizontal -gp-ls-h
400 VG_STATIC
int vg_rebind_input_cmd( int argc
, const char *argv
[] )
404 vg_info( "Usage: bind jump x\n" );
405 vg_info( " bind -steerh j\n" );
406 vg_info( " bind steerh gp-ls-h\n" );
410 const char *str_bind_name
= argv
[0];
411 struct input_binding
*bind
= vg_get_named_input( str_bind_name
);
415 vg_error( "There is no bind with that name '%s'\n", str_bind_name
);
421 vg_print_binding_info( bind
);
427 const char *str_input_id
= argv
[1];
429 vg_apply_bind_str( bind
, str_bind_name
, str_input_id
);
436 VG_STATIC
void vg_rebind_input_cmd_poll( int argc
, const char *argv
[] )
441 const char *str_bind_name
= argv
[0];
445 for( u32 i
=0; i
<vg_input
.named_input_count
; i
++ )
447 struct input_binding
*bind
= &vg_input
.named_inputs
[i
];
448 console_suggest_score_text( bind
->name
, argv
[argc
-1], 0 );
454 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ )
456 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
457 console_suggest_score_text( desc
->alias
, argv
[argc
-1], 0 );
462 VG_STATIC u8
vg_getkey( SDL_Keycode kc
)
464 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
465 return vg_input
.sdl_keys
[sc
];
468 VG_STATIC
void vg_input_update( u32 num
, struct input_binding
*binds
)
470 if( vg_console
.enabled
)
472 for( i32 i
=0; i
<num
; i
++ )
474 struct input_binding
*bind
= &binds
[i
];
476 if( bind
->type
== k_input_type_button
)
478 bind
->button
.prev
= bind
->button
.value
;
479 bind
->button
.value
= 0;
486 for( i32 i
=0; i
<num
; i
++ )
488 struct input_binding
*bind
= &binds
[i
];
490 if( bind
->type
== k_input_type_button
)
492 bind
->button
.prev
= bind
->button
.value
;
493 bind
->button
.value
= 0;
495 if( bind
->button
.gamepad_id
!= -1 )
496 bind
->button
.value
|=
497 vg_input
.controller_buttons
[ bind
->button
.gamepad_id
];
499 if( bind
->button
.keyboard_id
!= -1 )
501 bind
->button
.value
|= vg_getkey( bind
->button
.keyboard_id
);
504 if( bind
->button
.mouse_id
!= -1 )
506 if( SDL_GetMouseState(NULL
, NULL
) &
507 SDL_BUTTON( bind
->button
.mouse_id
) )
508 bind
->button
.value
|= 1;
511 else if( bind
->type
== k_input_type_axis
)
513 float keyboard_value
= 0.0f
,
514 gamepad_value
= 0.0f
;
516 if( bind
->axis
.keyboard_positive
!= -1 )
517 if( vg_getkey( bind
->axis
.keyboard_positive
) )
518 keyboard_value
+= 1.0f
;
520 if( bind
->axis
.keyboard_negative
!= -1 )
521 if( vg_getkey( bind
->axis
.keyboard_negative
) )
522 keyboard_value
-= 1.0f
;
524 if( bind
->axis
.gamepad_axis
!= -1 )
527 vg_input
.controller_axises
[ bind
->axis
.gamepad_axis
];
529 if( bind
->axis
.gamepad_inverted
)
530 gamepad_value
*= -1.0f
;
533 float deadz
= vg_clampf( g_controller_deadzone
, 0.0f
, 0.999f
),
534 high
= vg_maxf( 0.0f
, fabsf(gamepad_value
) - deadz
),
535 norm
= high
/ (1.0f
-deadz
);
537 gamepad_value
= vg_signf( gamepad_value
) * norm
;
539 if( fabsf(keyboard_value
) > fabsf(gamepad_value
) )
540 bind
->axis
.value
= keyboard_value
;
542 bind
->axis
.value
= gamepad_value
;
544 else if( bind
->type
== k_input_type_axis_norm
)
547 if( bind
->axis
.keyboard_positive
!= -1 )
548 if( vg_getkey( bind
->axis
.keyboard_positive
))
551 if( bind
->axis
.gamepad_axis
!= -1 )
552 value
= vg_maxf( value
,
553 vg_input
.controller_axises
[bind
->axis
.gamepad_axis
] );
555 bind
->axis
.value
= value
;
560 VG_STATIC
void vg_input_controller_event( SDL_Event
*ev
)
562 if( ev
->type
== SDL_CONTROLLERAXISMOTION
)
564 if( ev
->caxis
.which
== vg_input
.controller_joystick_id
)
566 vg_input
.controller_axises
[ ev
->caxis
.axis
] =
567 (float)ev
->caxis
.value
/ 32767.0f
;
570 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
)
572 if( ev
->cbutton
.which
== vg_input
.controller_joystick_id
)
573 vg_input
.controller_buttons
[ ev
->cbutton
.button
] = 1;
575 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
)
577 if( ev
->cbutton
.which
== vg_input
.controller_joystick_id
)
578 vg_input
.controller_buttons
[ ev
->cbutton
.button
] = 0;
582 VG_STATIC
void vg_try_attach_controller(void)
584 int joy_count
= SDL_NumJoysticks();
585 for( int i
=0; i
<joy_count
; i
++ )
587 if( SDL_IsGameController(i
) )
589 vg_input
.controller_handle
= SDL_GameControllerOpen(i
);
590 vg_input
.controller_joystick_id
= i
;
591 vg_success( "Attached game controller with joystick ID %d\n", i
);
598 VG_STATIC
void vg_update_inputs(void)
600 vg_input
.sdl_keys
= SDL_GetKeyboardState(NULL
);
602 if( vg_input
.controller_handle
)
604 if( !SDL_GameControllerGetAttached( vg_input
.controller_handle
) )
606 SDL_GameControllerClose( vg_input
.controller_handle
);
607 vg_input
.controller_handle
= NULL
;
611 if( !vg_input
.controller_handle
)
613 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
614 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
615 vg_try_attach_controller();
618 /* update all inputs */
619 vg_input_update( vg_input
.named_input_count
, vg_input
.named_inputs
);
622 VG_STATIC
int vg_console_enabled(void);
623 VG_STATIC
int vg_input_button_down( struct input_binding
*bind
)
625 if( bind
->button
.value
&& !bind
->button
.prev
)
630 VG_STATIC
void vg_input_init(void)
632 vg_acquire_thread_sync();
634 vg_function_push( (struct vg_cmd
)
637 .function
= vg_rebind_input_cmd
,
638 .poll_suggest
= vg_rebind_input_cmd_poll
641 vg_var_push( (struct vg_var
){
642 .name
= "controller_deadzone",
643 .data
= &g_controller_deadzone
,
644 .data_type
= k_var_dtype_f32
,
645 .opt_f32
= { .clamp
= 0 },
649 vg_info( "Checking for controller\n" );
650 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
652 int joy_count
= SDL_NumJoysticks();
653 for( int i
=0; i
<joy_count
; i
++ )
655 vg_info( "joystick %d: %s [gamecontroller: %d]\n",
656 i
, SDL_JoystickNameForIndex( i
),
657 SDL_IsGameController(i
) );
660 vg_try_attach_controller();
662 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
663 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
665 vg_release_thread_sync();
668 VG_STATIC
void vg_input_free(void)
670 if( vg_input
.controller_handle
)
672 SDL_GameControllerClose( vg_input
.controller_handle
);
673 vg_input
.controller_handle
= NULL
;