bad char
[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
17 VG_STATIC float g_controller_deadzone = 0.05f;
18
19 enum vg_button_state
20 {
21 k_button_state_down = 1,
22 k_button_state_up = 3,
23 k_button_state_pressed = 2,
24 k_button_state_none = 0
25 };
26
27 struct input_binding
28 {
29 const char *name;
30
31 enum input_type
32 {
33 k_input_type_button,
34 k_input_type_axis,
35 k_input_type_axis_norm,
36
37 k_input_type_unknown,
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
42 }
43 type;
44
45 union
46 {
47 struct input_axis
48 {
49 SDL_GameControllerAxis gamepad_axis;
50 SDL_Keycode keyboard_positive,
51 keyboard_negative;
52
53 int gamepad_inverted;
54 float value;
55 }
56 axis;
57
58 struct
59 {
60 SDL_GameControllerButton gamepad_id;
61 SDL_Keycode keyboard_id;
62 int mouse_id;
63 int value, prev;
64 }
65 button;
66 };
67
68 int save_this;
69 };
70
71 struct
72 {
73 const u8 *sdl_keys;
74 struct input_binding named_inputs[ 32 ];
75 u32 named_input_count;
76
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;
81
82 float controller_axises[ SDL_CONTROLLER_AXIS_MAX ];
83 int controller_buttons[ SDL_CONTROLLER_BUTTON_MAX ];
84 }
85 VG_STATIC vg_input;
86
87 VG_STATIC void vg_create_unnamed_input( struct input_binding *bind,
88 enum input_type type )
89 {
90 memset( bind, 0, sizeof(struct input_binding) );
91
92 bind->name = "API DEFINED";
93 bind->save_this = 0;
94 bind->type = type;
95
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;
102 }
103
104 VG_STATIC struct input_binding *vg_create_named_input( const char *name,
105 enum input_type type )
106 {
107 struct input_binding *bind =
108 &vg_input.named_inputs[ vg_input.named_input_count ++ ];
109 memset( bind, 0, sizeof(struct input_binding) );
110
111 bind->name = name;
112 bind->save_this = 0;
113 bind->type = type;
114
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;
121
122 return bind;
123 }
124
125 VG_STATIC struct input_binding *vg_get_named_input( const char *name )
126 {
127 if( name[0] == '+' || name[0] == '-' )
128 name ++;
129
130 for( u32 i=0; i<vg_input.named_input_count; i++ )
131 {
132 struct input_binding *bind = &vg_input.named_inputs[i];
133 if( !strcmp( bind->name, name ) )
134 return bind;
135 }
136
137 return NULL;
138 }
139
140 struct input_en
141 {
142 enum input_type type;
143
144 const char *alias;
145 int id;
146 }
147 vg_all_bindable_inputs[] =
148 {
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 },
165
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},
172
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},
186
187 {k_input_type_mouse_button, "mouse1", SDL_BUTTON_LEFT },
188 {k_input_type_mouse_button, "mouse2", SDL_BUTTON_RIGHT }
189 };
190
191 VG_STATIC const char *vg_input_to_str( u32 input, enum input_type input_type )
192 {
193 if( input == -1 )
194 return NULL;
195
196 if( input_type == k_input_type_keyboard_key )
197 {
198 if( (input >= SDLK_a) && (input <= SDLK_z) )
199 {
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];
202 }
203
204 if( (input >= SDLK_0) && (input <= SDLK_9) )
205 {
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];
208 }
209 }
210
211 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
212 {
213 struct input_en *desc = &vg_all_bindable_inputs[i];
214
215 if( (desc->type == input_type) && (desc->id == input) )
216 return desc->alias;
217 }
218
219 return NULL;
220 }
221
222 VG_STATIC enum input_type vg_str_to_input( const char *str, u32 *input )
223 {
224 if( !str )
225 {
226 *input = -1;
227 return k_input_type_unknown;
228 }
229
230 u32 len = strlen(str);
231
232 if( len == 0 )
233 {
234 *input = -1;
235 return k_input_type_unknown;
236 }
237
238 if( len == 1 )
239 {
240 u8 uch = str[0];
241
242 if( (uch >= (u8)'a') && (uch <= (u8)'z') )
243 {
244 *input = SDLK_a + (uch-(u8)'a');
245 return k_input_type_keyboard_key;
246 }
247
248 if( (uch >= (u8)'0') && (uch <= (u8)'9') )
249 {
250 *input = SDLK_0 + (uch-(u8)'0');
251 return k_input_type_keyboard_key;
252 }
253 }
254
255 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
256 {
257 struct input_en *desc = &vg_all_bindable_inputs[i];
258
259 if( !strcmp( desc->alias, str ) )
260 {
261 *input = desc->id;
262 return desc->type;
263 }
264 }
265
266 *input = -1;
267 return k_input_type_unknown;
268 }
269
270 VG_STATIC void vg_print_binding_info( struct input_binding *bind )
271 {
272 vg_info( " name: %s\n", bind->name );
273 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
274 [ bind->type ] );
275 vg_info( " save this? %d\n", bind->save_this );
276
277 if( (bind->type == k_input_type_axis) ||
278 (bind->type == k_input_type_axis_norm) )
279 {
280 vg_info( " gamepad_axis: %s\n",
281 vg_input_to_str(bind->axis.gamepad_axis, k_input_type_gamepad_axis));
282
283 vg_info( " keyboard_positive: %s\n",
284 vg_input_to_str(bind->axis.keyboard_positive,
285 k_input_type_keyboard_key ));
286
287 vg_info( " keyboard_negative: %s\n",
288 vg_input_to_str(bind->axis.keyboard_negative,
289 k_input_type_keyboard_key ));
290 }
291 else
292 {
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));
301 }
302 }
303
304 VG_STATIC void vg_apply_bind_str( struct input_binding *bind,
305 const char *mod,
306 const char *str )
307 {
308 int axis_mod = 0;
309 char modch = ' ';
310 if( (mod[0] == '-') || (mod[0] == '+') )
311 {
312 axis_mod = 1;
313 modch = mod[0];
314 mod ++;
315 }
316
317 int invert = 0;
318 if( (str[0] == '-' ) )
319 {
320 invert = 1;
321 str ++;
322 }
323
324 u32 id;
325 enum input_type type = vg_str_to_input( str, &id );
326
327 if( bind->type == k_input_type_button )
328 {
329 if( axis_mod )
330 {
331 vg_error( "Cannot use axis modifiers on button input!\n" );
332 return;
333 }
334
335 if( invert )
336 {
337 vg_error( "Cannot invert button input!\n" );
338 return;
339 }
340
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;
347 else
348 {
349 vg_error( "Unknown button or key '%s'\n", str );
350 return;
351 }
352 }
353 else if( (bind->type == k_input_type_axis ) ||
354 (bind->type == k_input_type_axis_norm))
355 {
356 if( axis_mod )
357 {
358 if( type == k_input_type_keyboard_key )
359 {
360 if( invert )
361 {
362 vg_error( "Cannot invert a keyboard key!\n" );
363 return;
364 }
365
366 if( modch == '+' )
367 bind->axis.keyboard_positive = id;
368 else
369 bind->axis.keyboard_negative = id;
370 }
371 else
372 {
373 vg_error( "You can only bind keyboard keys to +- axises\n" );
374 return;
375 }
376 }
377 else
378 {
379 if( type == k_input_type_gamepad_axis )
380 {
381 bind->axis.gamepad_inverted = invert;
382 bind->axis.gamepad_axis = id;
383 }
384 else
385 {
386 vg_error( "You can only bind gamepad axises to this\n" );
387 return;
388 }
389 }
390 }
391 }
392
393 /*
394 * bind jump x
395 * bind -horizontal a
396 * bind +horizontal d
397 * bind horizontal -gp-ls-h
398 */
399
400 VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] )
401 {
402 if( argc == 0 )
403 {
404 vg_info( "Usage: bind jump x\n" );
405 vg_info( " bind -steerh j\n" );
406 vg_info( " bind steerh gp-ls-h\n" );
407 return 0;
408 }
409
410 const char *str_bind_name = argv[0];
411 struct input_binding *bind = vg_get_named_input( str_bind_name );
412
413 if( !bind )
414 {
415 vg_error( "There is no bind with that name '%s'\n", str_bind_name );
416 return 0;
417 }
418
419 if( argc == 1 )
420 {
421 vg_print_binding_info( bind );
422 return 0;
423 }
424
425 if( argc == 2 )
426 {
427 const char *str_input_id = argv[1];
428
429 vg_apply_bind_str( bind, str_bind_name, str_input_id );
430 return 0;
431 }
432
433 return 0;
434 }
435
436 VG_STATIC void vg_rebind_input_cmd_poll( int argc, const char *argv[] )
437 {
438 if( argc == 0 )
439 return;
440
441 const char *str_bind_name = argv[0];
442
443 if( argc == 1 )
444 {
445 for( u32 i=0; i<vg_input.named_input_count; i++ )
446 {
447 struct input_binding *bind = &vg_input.named_inputs[i];
448 console_suggest_score_text( bind->name, argv[argc-1], 0 );
449 }
450 }
451
452 else if( argc == 2 )
453 {
454 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
455 {
456 struct input_en *desc = &vg_all_bindable_inputs[i];
457 console_suggest_score_text( desc->alias, argv[argc-1], 0 );
458 }
459 }
460 }
461
462 VG_STATIC u8 vg_getkey( SDL_Keycode kc )
463 {
464 SDL_Scancode sc = SDL_GetScancodeFromKey( kc );
465 return vg_input.sdl_keys[sc];
466 }
467
468 VG_STATIC void vg_input_update( u32 num, struct input_binding *binds )
469 {
470 if( vg_console.enabled )
471 {
472 for( i32 i=0; i<num; i++ )
473 {
474 struct input_binding *bind = &binds[i];
475
476 if( bind->type == k_input_type_button )
477 {
478 bind->button.prev = bind->button.value;
479 bind->button.value = 0;
480 }
481 }
482
483 return;
484 }
485
486 for( i32 i=0; i<num; i++ )
487 {
488 struct input_binding *bind = &binds[i];
489
490 if( bind->type == k_input_type_button )
491 {
492 bind->button.prev = bind->button.value;
493 bind->button.value = 0;
494
495 if( bind->button.gamepad_id != -1 )
496 bind->button.value |=
497 vg_input.controller_buttons[ bind->button.gamepad_id ];
498
499 if( bind->button.keyboard_id != -1 )
500 {
501 bind->button.value |= vg_getkey( bind->button.keyboard_id );
502 }
503
504 if( bind->button.mouse_id != -1 )
505 {
506 if( SDL_GetMouseState(NULL, NULL) &
507 SDL_BUTTON( bind->button.mouse_id ) )
508 bind->button.value |= 1;
509 }
510 }
511 else if( bind->type == k_input_type_axis )
512 {
513 float keyboard_value = 0.0f,
514 gamepad_value = 0.0f;
515
516 if( bind->axis.keyboard_positive != -1 )
517 if( vg_getkey( bind->axis.keyboard_positive ) )
518 keyboard_value += 1.0f;
519
520 if( bind->axis.keyboard_negative != -1 )
521 if( vg_getkey( bind->axis.keyboard_negative ) )
522 keyboard_value -= 1.0f;
523
524 if( bind->axis.gamepad_axis != -1 )
525 {
526 gamepad_value =
527 vg_input.controller_axises[ bind->axis.gamepad_axis ];
528
529 if( bind->axis.gamepad_inverted )
530 gamepad_value *= -1.0f;
531 }
532
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);
536
537 gamepad_value = vg_signf( gamepad_value ) * norm;
538
539 if( fabsf(keyboard_value) > fabsf(gamepad_value) )
540 bind->axis.value = keyboard_value;
541 else
542 bind->axis.value = gamepad_value;
543 }
544 else if( bind->type == k_input_type_axis_norm )
545 {
546 float value = 0.0f;
547 if( bind->axis.keyboard_positive != -1 )
548 if( vg_getkey( bind->axis.keyboard_positive ))
549 value = 1.0f;
550
551 if( bind->axis.gamepad_axis != -1 )
552 value = vg_maxf( value,
553 vg_input.controller_axises[bind->axis.gamepad_axis] );
554
555 bind->axis.value = value;
556 }
557 }
558 }
559
560 VG_STATIC void vg_input_controller_event( SDL_Event *ev )
561 {
562 if( ev->type == SDL_CONTROLLERAXISMOTION )
563 {
564 if( ev->caxis.which == vg_input.controller_joystick_id )
565 {
566 vg_input.controller_axises[ ev->caxis.axis ] =
567 (float)ev->caxis.value / 32767.0f;
568 }
569 }
570 else if( ev->type == SDL_CONTROLLERBUTTONDOWN )
571 {
572 if( ev->cbutton.which == vg_input.controller_joystick_id )
573 vg_input.controller_buttons[ ev->cbutton.button ] = 1;
574 }
575 else if( ev->type == SDL_CONTROLLERBUTTONUP )
576 {
577 if( ev->cbutton.which == vg_input.controller_joystick_id )
578 vg_input.controller_buttons[ ev->cbutton.button ] = 0;
579 }
580 }
581
582 VG_STATIC void vg_try_attach_controller(void)
583 {
584 int joy_count = SDL_NumJoysticks();
585 for( int i=0; i<joy_count; i++ )
586 {
587 if( SDL_IsGameController(i) )
588 {
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 );
592 return;
593 }
594 }
595 }
596
597
598 VG_STATIC void vg_update_inputs(void)
599 {
600 vg_input.sdl_keys = SDL_GetKeyboardState(NULL);
601
602 if( vg_input.controller_handle )
603 {
604 if( !SDL_GameControllerGetAttached( vg_input.controller_handle ) )
605 {
606 SDL_GameControllerClose( vg_input.controller_handle );
607 vg_input.controller_handle = NULL;
608 }
609 }
610
611 if( !vg_input.controller_handle )
612 {
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();
616 }
617
618 /* update all inputs */
619 vg_input_update( vg_input.named_input_count, vg_input.named_inputs );
620 }
621
622 VG_STATIC int vg_console_enabled(void);
623 VG_STATIC int vg_input_button_down( struct input_binding *bind )
624 {
625 if( bind->button.value && !bind->button.prev )
626 return 1;
627 return 0;
628 }
629
630 VG_STATIC void vg_input_init(void)
631 {
632 vg_acquire_thread_sync();
633
634 vg_function_push( (struct vg_cmd)
635 {
636 .name = "bind",
637 .function = vg_rebind_input_cmd,
638 .poll_suggest = vg_rebind_input_cmd_poll
639 });
640
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 },
646 .persistent = 1
647 });
648
649 vg_info( "Checking for controller\n" );
650 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
651
652 int joy_count = SDL_NumJoysticks();
653 for( int i=0; i<joy_count; i++ )
654 {
655 vg_info( "joystick %d: %s [gamecontroller: %d]\n",
656 i, SDL_JoystickNameForIndex( i ),
657 SDL_IsGameController(i) );
658 }
659
660 vg_try_attach_controller();
661
662 vg_input.controller_axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f;
663 vg_input.controller_axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f;
664
665 vg_release_thread_sync();
666 }
667
668 VG_STATIC void vg_input_free(void)
669 {
670 if( vg_input.controller_handle )
671 {
672 SDL_GameControllerClose( vg_input.controller_handle );
673 vg_input.controller_handle = NULL;
674 }
675 }
676
677 #endif