simplify
[vg.git] / vg_input.h
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
2 #ifndef VG_INPUT_H
3 #define VG_INPUT_H
4
5 #include "common.h"
6 #include "vg/vg_loader.h"
7
8 VG_STATIC inline float vg_get_axis( const char *axis );
9 VG_STATIC inline int vg_get_button( const char *button );
10
11 /*
12 * Cannot be used in fixed update
13 */
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;
17
18 enum vg_button_state{
19 k_button_state_down = 1,
20 k_button_state_up = 3,
21 k_button_state_pressed = 2,
22 k_button_state_none = 0
23 };
24
25 struct input_binding{
26 const char *name;
27
28 enum input_type{
29 k_input_type_button,
30 k_input_type_axis,
31 k_input_type_axis_norm,
32
33 k_input_type_unknown,
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
38 }
39 type;
40
41 union{
42 struct input_axis{
43 SDL_GameControllerAxis gamepad_axis;
44 SDL_Keycode keyboard_positive,
45 keyboard_negative;
46
47 int gamepad_inverted;
48 float value;
49 }
50 axis;
51
52 struct{
53 SDL_GameControllerButton gamepad_id;
54 SDL_Keycode keyboard_id;
55 int mouse_id;
56 int value, prev;
57 }
58 button;
59 };
60
61 int save_this;
62 };
63
64 struct
65 {
66 const u8 *sdl_keys;
67 struct input_binding named_inputs[ 32 ];
68 u32 named_input_count;
69
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;
74
75 float controller_axises[ SDL_CONTROLLER_AXIS_MAX ];
76 int controller_buttons[ SDL_CONTROLLER_BUTTON_MAX ];
77 }
78 VG_STATIC vg_input;
79
80 VG_STATIC void vg_create_unnamed_input( struct input_binding *bind,
81 enum input_type type )
82 {
83 memset( bind, 0, sizeof(struct input_binding) );
84
85 bind->name = "API DEFINED";
86 bind->save_this = 0;
87 bind->type = type;
88
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;
95 }
96
97 VG_STATIC struct input_binding *vg_create_named_input( const char *name,
98 enum input_type type )
99 {
100 struct input_binding *bind =
101 &vg_input.named_inputs[ vg_input.named_input_count ++ ];
102 memset( bind, 0, sizeof(struct input_binding) );
103
104 bind->name = name;
105 bind->save_this = 0;
106 bind->type = type;
107
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;
114
115 return bind;
116 }
117
118 VG_STATIC struct input_binding *vg_get_named_input( const char *name )
119 {
120 if( name[0] == '+' || name[0] == '-' )
121 name ++;
122
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 ) )
126 return bind;
127 }
128
129 return NULL;
130 }
131
132 struct input_en
133 {
134 enum input_type type;
135
136 const char *alias;
137 int id;
138 }
139 vg_all_bindable_inputs[] =
140 {
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 },
157
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},
164
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},
178
179 {k_input_type_mouse_button, "mouse1", SDL_BUTTON_LEFT },
180 {k_input_type_mouse_button, "mouse2", SDL_BUTTON_RIGHT }
181 };
182
183 VG_STATIC const char *vg_input_to_str( u32 input, enum input_type input_type )
184 {
185 if( input == -1 )
186 return NULL;
187
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];
192 }
193
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];
197 }
198 }
199
200 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ ){
201 struct input_en *desc = &vg_all_bindable_inputs[i];
202
203 if( (desc->type == input_type) && (desc->id == input) )
204 return desc->alias;
205 }
206
207 return NULL;
208 }
209
210 VG_STATIC enum input_type vg_str_to_input( const char *str, u32 *input )
211 {
212 if( !str ){
213 *input = -1;
214 return k_input_type_unknown;
215 }
216
217 u32 len = strlen(str);
218
219 if( len == 0 ){
220 *input = -1;
221 return k_input_type_unknown;
222 }
223
224 if( len == 1 ){
225 u8 uch = str[0];
226
227 if( (uch >= (u8)'a') && (uch <= (u8)'z') ){
228 *input = SDLK_a + (uch-(u8)'a');
229 return k_input_type_keyboard_key;
230 }
231
232 if( (uch >= (u8)'0') && (uch <= (u8)'9') ){
233 *input = SDLK_0 + (uch-(u8)'0');
234 return k_input_type_keyboard_key;
235 }
236 }
237
238 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ ){
239 struct input_en *desc = &vg_all_bindable_inputs[i];
240
241 if( !strcmp( desc->alias, str ) ){
242 *input = desc->id;
243 return desc->type;
244 }
245 }
246
247 *input = -1;
248 return k_input_type_unknown;
249 }
250
251 VG_STATIC void vg_print_binding_info( struct input_binding *bind )
252 {
253 vg_info( " name: %s\n", bind->name );
254 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
255 [ bind->type ] );
256 vg_info( " save this? %d\n", bind->save_this );
257
258 if( (bind->type == k_input_type_axis) ||
259 (bind->type == k_input_type_axis_norm) )
260 {
261 vg_info( " gamepad_axis: %s\n",
262 vg_input_to_str(bind->axis.gamepad_axis, k_input_type_gamepad_axis));
263
264 vg_info( " keyboard_positive: %s\n",
265 vg_input_to_str(bind->axis.keyboard_positive,
266 k_input_type_keyboard_key ));
267
268 vg_info( " keyboard_negative: %s\n",
269 vg_input_to_str(bind->axis.keyboard_negative,
270 k_input_type_keyboard_key ));
271 }
272 else{
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));
281 }
282 }
283
284 VG_STATIC void vg_apply_bind_str( struct input_binding *bind,
285 const char *mod,
286 const char *str )
287 {
288 int axis_mod = 0;
289 char modch = ' ';
290 if( (mod[0] == '-') || (mod[0] == '+') ){
291 axis_mod = 1;
292 modch = mod[0];
293 mod ++;
294 }
295
296 int invert = 0;
297 if( (str[0] == '-' ) ){
298 invert = 1;
299 str ++;
300 }
301
302 u32 id;
303 enum input_type type = vg_str_to_input( str, &id );
304
305 if( bind->type == k_input_type_button ){
306 if( axis_mod ){
307 vg_error( "Cannot use axis modifiers on button input!\n" );
308 return;
309 }
310
311 if( invert ){
312 vg_error( "Cannot invert button input!\n" );
313 return;
314 }
315
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;
322 else{
323 vg_error( "Unknown button or key '%s'\n", str );
324 return;
325 }
326 }
327 else if( (bind->type == k_input_type_axis ) ||
328 (bind->type == k_input_type_axis_norm))
329 {
330 if( axis_mod ){
331 if( type == k_input_type_keyboard_key ){
332 if( invert ){
333 vg_error( "Cannot invert a keyboard key!\n" );
334 return;
335 }
336
337 if( modch == '+' )
338 bind->axis.keyboard_positive = id;
339 else
340 bind->axis.keyboard_negative = id;
341 }
342 else{
343 vg_error( "You can only bind keyboard keys to +- axises\n" );
344 return;
345 }
346 }
347 else{
348 if( type == k_input_type_gamepad_axis ){
349 bind->axis.gamepad_inverted = invert;
350 bind->axis.gamepad_axis = id;
351 }
352 else{
353 vg_error( "You can only bind gamepad axises to this\n" );
354 return;
355 }
356 }
357 }
358 }
359
360 /*
361 * bind jump x
362 * bind -horizontal a
363 * bind +horizontal d
364 * bind horizontal -gp-ls-h
365 */
366
367 VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] )
368 {
369 if( argc == 0 ){
370 vg_info( "Usage: bind jump x\n" );
371 vg_info( " bind -steerh j\n" );
372 vg_info( " bind steerh gp-ls-h\n" );
373 return 0;
374 }
375
376 const char *str_bind_name = argv[0];
377 struct input_binding *bind = vg_get_named_input( str_bind_name );
378
379 if( !bind ){
380 vg_error( "There is no bind with that name '%s'\n", str_bind_name );
381 return 0;
382 }
383
384 if( argc == 1 ){
385 vg_print_binding_info( bind );
386 return 0;
387 }
388
389 if( argc == 2 ){
390 const char *str_input_id = argv[1];
391
392 vg_apply_bind_str( bind, str_bind_name, str_input_id );
393 return 0;
394 }
395
396 return 0;
397 }
398
399 VG_STATIC void vg_rebind_input_cmd_poll( int argc, const char *argv[] )
400 {
401 if( argc == 0 )
402 return;
403
404 const char *str_bind_name = argv[0];
405
406 if( argc == 1 ){
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 );
410 }
411 }
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 );
416 }
417 }
418 }
419
420 VG_STATIC u8 vg_getkey( SDL_Keycode kc )
421 {
422 SDL_Scancode sc = SDL_GetScancodeFromKey( kc );
423 return vg_input.sdl_keys[sc];
424 }
425
426 VG_STATIC void vg_input_update( u32 num, struct input_binding *binds )
427 {
428 if( vg_console.enabled ){
429 for( i32 i=0; i<num; i++ ){
430 struct input_binding *bind = &binds[i];
431
432 if( bind->type == k_input_type_button ){
433 bind->button.prev = bind->button.value;
434 bind->button.value = 0;
435 }
436 }
437
438 return;
439 }
440
441 for( i32 i=0; i<num; i++ ){
442 struct input_binding *bind = &binds[i];
443
444 if( bind->type == k_input_type_button ){
445 bind->button.prev = bind->button.value;
446 bind->button.value = 0;
447
448 if( bind->button.gamepad_id != -1 )
449 bind->button.value |=
450 vg_input.controller_buttons[ bind->button.gamepad_id ];
451
452 if( bind->button.keyboard_id != -1 ){
453 bind->button.value |= vg_getkey( bind->button.keyboard_id );
454 }
455
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;
460 }
461 }
462 else if( bind->type == k_input_type_axis ){
463 float keyboard_value = 0.0f,
464 gamepad_value = 0.0f;
465
466 if( bind->axis.keyboard_positive != -1 )
467 if( vg_getkey( bind->axis.keyboard_positive ) )
468 keyboard_value += 1.0f;
469
470 if( bind->axis.keyboard_negative != -1 )
471 if( vg_getkey( bind->axis.keyboard_negative ) )
472 keyboard_value -= 1.0f;
473
474 if( bind->axis.gamepad_axis != -1 ){
475 gamepad_value =
476 vg_input.controller_axises[ bind->axis.gamepad_axis ];
477
478 if( bind->axis.gamepad_inverted )
479 gamepad_value *= -1.0f;
480 }
481
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);
485
486 gamepad_value = vg_signf( gamepad_value ) * norm;
487
488 if( fabsf(keyboard_value) > fabsf(gamepad_value) )
489 bind->axis.value = keyboard_value;
490 else
491 bind->axis.value = gamepad_value;
492 }
493 else if( bind->type == k_input_type_axis_norm ){
494 float value = 0.0f;
495 if( bind->axis.keyboard_positive != -1 )
496 if( vg_getkey( bind->axis.keyboard_positive ))
497 value = 1.0f;
498
499 if( bind->axis.gamepad_axis != -1 )
500 value = vg_maxf( value,
501 vg_input.controller_axises[bind->axis.gamepad_axis] );
502
503 bind->axis.value = value;
504 }
505 }
506 }
507
508 VG_STATIC void vg_input_controller_event( SDL_Event *ev )
509 {
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;
514 }
515 }
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;
519 }
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;
523 }
524 }
525
526 VG_STATIC void vg_try_attach_controller(void)
527 {
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 );
534 return;
535 }
536 }
537 }
538
539 VG_STATIC void vg_update_inputs(void)
540 {
541 vg_input.sdl_keys = SDL_GetKeyboardState(NULL);
542
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;
547 }
548 }
549
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();
554 }
555
556 /* update all inputs */
557 vg_input_update( vg_input.named_input_count, vg_input.named_inputs );
558 }
559
560 VG_STATIC int vg_console_enabled(void);
561 VG_STATIC int vg_input_button_down( struct input_binding *bind )
562 {
563 if( bind->button.value && !bind->button.prev )
564 return 1;
565 return 0;
566 }
567
568 VG_STATIC void async_vg_input_init( void *payload, u32 size )
569 {
570 vg_console_reg_cmd( "bind", vg_rebind_input_cmd, vg_rebind_input_cmd_poll );
571
572 VG_VAR_F32( controller_deadzone, flags=VG_VAR_PERSISTENT );
573 vg_info( "Checking for controller\n" );
574 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
575
576 int joy_count = SDL_NumJoysticks();
577 for( int i=0; i<joy_count; i++ )
578 {
579 vg_info( "joystick %d: %s [gamecontroller: %d]\n",
580 i, SDL_JoystickNameForIndex( i ),
581 SDL_IsGameController(i) );
582 }
583
584 vg_try_attach_controller();
585
586 vg_input.controller_axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f;
587 vg_input.controller_axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f;
588 }
589
590 VG_STATIC void vg_input_init(void)
591 {
592 vg_async_call( async_vg_input_init, NULL, 0 );
593 }
594
595 VG_STATIC void vg_input_free(void)
596 {
597 if( vg_input.controller_handle ){
598 SDL_GameControllerClose( vg_input.controller_handle );
599 vg_input.controller_handle = NULL;
600 }
601 }
602
603 #endif