poll functions
[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 value, prev;
63 }
64 button;
65 };
66
67 int save_this;
68 };
69
70 struct
71 {
72 const u8 *sdl_keys;
73 struct input_binding named_inputs[ 32 ];
74 u32 named_input_count;
75
76 const char *controller_name;
77 SDL_GameController *controller_handle; /* null if unplugged */
78 SDL_JoystickID controller_joystick_id;
79 int controller_should_use_trackpad_look;
80
81 float controller_axises[ SDL_CONTROLLER_AXIS_MAX ];
82 int controller_buttons[ SDL_CONTROLLER_BUTTON_MAX ];
83 }
84 VG_STATIC vg_input;
85
86 VG_STATIC void vg_create_unnamed_input( struct input_binding *bind,
87 enum input_type type )
88 {
89 memset( bind, 0, sizeof(struct input_binding) );
90
91 bind->name = "API DEFINED";
92 bind->save_this = 0;
93 bind->type = type;
94
95 bind->axis.gamepad_axis = -1;
96 bind->axis.keyboard_positive = -1;
97 bind->axis.keyboard_negative = -1;
98 bind->button.gamepad_id = -1;
99 bind->button.keyboard_id = -1;
100 }
101
102 VG_STATIC struct input_binding *vg_create_named_input( const char *name,
103 enum input_type type )
104 {
105 struct input_binding *bind =
106 &vg_input.named_inputs[ vg_input.named_input_count ++ ];
107 memset( bind, 0, sizeof(struct input_binding) );
108
109 bind->name = name;
110 bind->save_this = 0;
111 bind->type = type;
112
113 bind->axis.gamepad_axis = -1;
114 bind->axis.keyboard_positive = -1;
115 bind->axis.keyboard_negative = -1;
116 bind->button.gamepad_id = -1;
117 bind->button.keyboard_id = -1;
118
119 return bind;
120 }
121
122 VG_STATIC struct input_binding *vg_get_named_input( const char *name )
123 {
124 if( name[0] == '+' || name[0] == '-' )
125 name ++;
126
127 for( u32 i=0; i<vg_input.named_input_count; i++ )
128 {
129 struct input_binding *bind = &vg_input.named_inputs[i];
130 if( !strcmp( bind->name, name ) )
131 return bind;
132 }
133
134 return NULL;
135 }
136
137 struct input_en
138 {
139 enum input_type type;
140
141 const char *alias;
142 int id;
143 }
144 vg_all_bindable_inputs[] =
145 {
146 {k_input_type_keyboard_key, "space", SDLK_SPACE},
147 {k_input_type_keyboard_key, ";", SDLK_SEMICOLON},
148 {k_input_type_keyboard_key, "-", SDLK_MINUS},
149 {k_input_type_keyboard_key, ".", SDLK_PERIOD},
150 {k_input_type_keyboard_key, ",", SDLK_COMMA},
151 {k_input_type_keyboard_key, "=", SDLK_EQUALS},
152 {k_input_type_keyboard_key, "[", SDLK_LEFTBRACKET},
153 {k_input_type_keyboard_key, "]", SDLK_RIGHTBRACKET},
154 {k_input_type_keyboard_key, "left", SDLK_LEFT},
155 {k_input_type_keyboard_key, "right", SDLK_RIGHT},
156 {k_input_type_keyboard_key, "up", SDLK_UP},
157 {k_input_type_keyboard_key, "down", SDLK_DOWN},
158 {k_input_type_keyboard_key, "shift", SDLK_LSHIFT},
159 {k_input_type_keyboard_key, "control", SDLK_LCTRL},
160 {k_input_type_keyboard_key, "\2enter", SDLK_RETURN},
161 {k_input_type_keyboard_key, "\2escape", SDLK_ESCAPE },
162
163 {k_input_type_gamepad_axis, "gp-lt", SDL_CONTROLLER_AXIS_TRIGGERLEFT},
164 {k_input_type_gamepad_axis, "gp-rt", SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
165 {k_input_type_gamepad_axis, "gp-ls-h", SDL_CONTROLLER_AXIS_LEFTX},
166 {k_input_type_gamepad_axis, "gp-ls-v", SDL_CONTROLLER_AXIS_LEFTY},
167 {k_input_type_gamepad_axis, "gp-rs-h", SDL_CONTROLLER_AXIS_RIGHTX},
168 {k_input_type_gamepad_axis, "gp-rs-v", SDL_CONTROLLER_AXIS_RIGHTY},
169
170 {k_input_type_gamepad_button, "gp-a", SDL_CONTROLLER_BUTTON_A},
171 {k_input_type_gamepad_button, "gp-b", SDL_CONTROLLER_BUTTON_B},
172 {k_input_type_gamepad_button, "gp-x", SDL_CONTROLLER_BUTTON_X},
173 {k_input_type_gamepad_button, "gp-y", SDL_CONTROLLER_BUTTON_Y},
174 {k_input_type_gamepad_button, "gp-rb", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
175 {k_input_type_gamepad_button, "gp-lb", SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
176 {k_input_type_gamepad_button, "gp-rs", SDL_CONTROLLER_BUTTON_RIGHTSTICK},
177 {k_input_type_gamepad_button, "gp-ls", SDL_CONTROLLER_BUTTON_LEFTSTICK},
178 {k_input_type_gamepad_button, "gp-dpad-down", SDL_CONTROLLER_BUTTON_DPAD_DOWN},
179 {k_input_type_gamepad_button, "gp-dpad-left", SDL_CONTROLLER_BUTTON_DPAD_LEFT},
180 {k_input_type_gamepad_button,"gp-dpad-right",SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
181 {k_input_type_gamepad_button, "gp-dpad-up", SDL_CONTROLLER_BUTTON_DPAD_UP},
182 {k_input_type_gamepad_button, "\2gp-menu", SDL_CONTROLLER_BUTTON_BACK}
183 };
184
185 VG_STATIC const char *vg_input_to_str( u32 input, enum input_type input_type )
186 {
187 if( input == -1 )
188 return NULL;
189
190 if( input_type == k_input_type_keyboard_key )
191 {
192 if( (input >= SDLK_a) && (input <= SDLK_z) )
193 {
194 return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
195 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input-SDLK_a)*2];
196 }
197
198 if( (input >= SDLK_0) && (input <= SDLK_9) )
199 {
200 return &"0\0" "1\0" "2\0" "3\0" "4\0"
201 "5\0" "6\0" "7\0" "8\0" "9\0"[(input-SDLK_0)*2];
202 }
203 }
204
205 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
206 {
207 struct input_en *desc = &vg_all_bindable_inputs[i];
208
209 if( (desc->type == input_type) && (desc->id == input) )
210 return desc->alias;
211 }
212
213 return NULL;
214 }
215
216 VG_STATIC enum input_type vg_str_to_input( const char *str, u32 *input )
217 {
218 if( !str )
219 {
220 *input = -1;
221 return k_input_type_unknown;
222 }
223
224 u32 len = strlen(str);
225
226 if( len == 0 )
227 {
228 *input = -1;
229 return k_input_type_unknown;
230 }
231
232 if( len == 1 )
233 {
234 u8 uch = str[0];
235
236 if( (uch >= (u8)'a') && (uch <= (u8)'z') )
237 {
238 *input = SDLK_a + (uch-(u8)'a');
239 return k_input_type_keyboard_key;
240 }
241
242 if( (uch >= (u8)'0') && (uch <= (u8)'9') )
243 {
244 *input = SDLK_0 + (uch-(u8)'0');
245 return k_input_type_keyboard_key;
246 }
247 }
248
249 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
250 {
251 struct input_en *desc = &vg_all_bindable_inputs[i];
252
253 if( !strcmp( desc->alias, str ) )
254 {
255 *input = desc->id;
256 return desc->type;
257 }
258 }
259
260 *input = -1;
261 return k_input_type_unknown;
262 }
263
264 VG_STATIC void vg_print_binding_info( struct input_binding *bind )
265 {
266 vg_info( " name: %s\n", bind->name );
267 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
268 [ bind->type ] );
269 vg_info( " save this? %d\n", bind->save_this );
270
271 if( (bind->type == k_input_type_axis) ||
272 (bind->type == k_input_type_axis_norm) )
273 {
274 vg_info( " gamepad_axis: %s\n",
275 vg_input_to_str(bind->axis.gamepad_axis, k_input_type_gamepad_axis));
276
277 vg_info( " keyboard_positive: %s\n",
278 vg_input_to_str(bind->axis.keyboard_positive,
279 k_input_type_keyboard_key ));
280
281 vg_info( " keyboard_negative: %s\n",
282 vg_input_to_str(bind->axis.keyboard_negative,
283 k_input_type_keyboard_key ));
284 }
285 else
286 {
287 vg_info( " gamepad_id: %s\n",
288 vg_input_to_str(bind->button.gamepad_id, k_input_type_gamepad_button));
289 vg_info( " keyboard_id: %s\n",
290 vg_input_to_str(bind->button.keyboard_id,
291 k_input_type_keyboard_key));
292 }
293 }
294
295 VG_STATIC void vg_apply_bind_str( struct input_binding *bind,
296 const char *mod,
297 const char *str )
298 {
299 int axis_mod = 0;
300 char modch = ' ';
301 if( (mod[0] == '-') || (mod[0] == '+') )
302 {
303 axis_mod = 1;
304 modch = mod[0];
305 mod ++;
306 }
307
308 int invert = 0;
309 if( (str[0] == '-' ) )
310 {
311 invert = 1;
312 str ++;
313 }
314
315 u32 id;
316 enum input_type type = vg_str_to_input( str, &id );
317
318 if( bind->type == k_input_type_button )
319 {
320 if( axis_mod )
321 {
322 vg_error( "Cannot use axis modifiers on button input!\n" );
323 return;
324 }
325
326 if( invert )
327 {
328 vg_error( "Cannot invert button input!\n" );
329 return;
330 }
331
332 if( type == k_input_type_keyboard_key )
333 bind->button.keyboard_id = id;
334 else if( type == k_input_type_gamepad_button )
335 bind->button.gamepad_id = id;
336 else
337 {
338 vg_error( "Unknown button or key '%s'\n", str );
339 return;
340 }
341 }
342 else if( (bind->type == k_input_type_axis ) ||
343 (bind->type == k_input_type_axis_norm))
344 {
345 if( axis_mod )
346 {
347 if( type == k_input_type_keyboard_key )
348 {
349 if( invert )
350 {
351 vg_error( "Cannot invert a keyboard key!\n" );
352 return;
353 }
354
355 if( modch == '+' )
356 bind->axis.keyboard_positive = id;
357 else
358 bind->axis.keyboard_negative = id;
359 }
360 else
361 {
362 vg_error( "You can only bind keyboard keys to +- axises\n" );
363 return;
364 }
365 }
366 else
367 {
368 if( type == k_input_type_gamepad_axis )
369 {
370 bind->axis.gamepad_inverted = invert;
371 bind->axis.gamepad_axis = id;
372 }
373 else
374 {
375 vg_error( "You can only bind gamepad axises to this\n" );
376 return;
377 }
378 }
379 }
380 }
381
382 /*
383 * bind jump x
384 * bind -horizontal a
385 * bind +horizontal d
386 * bind horizontal -gp-ls-h
387 */
388
389 VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] )
390 {
391 if( argc == 0 )
392 {
393 vg_info( "Usage: bind jump x\n" );
394 vg_info( " bind -steerh j\n" );
395 vg_info( " bind steerh gp-ls-h\n" );
396 return 0;
397 }
398
399 const char *str_bind_name = argv[0];
400 struct input_binding *bind = vg_get_named_input( str_bind_name );
401
402 if( !bind )
403 {
404 vg_error( "There is no bind with that name '%s'\n", str_bind_name );
405 return 0;
406 }
407
408 if( argc == 1 )
409 {
410 vg_print_binding_info( bind );
411 return 0;
412 }
413
414 if( argc == 2 )
415 {
416 const char *str_input_id = argv[1];
417
418 vg_apply_bind_str( bind, str_bind_name, str_input_id );
419 return 0;
420 }
421
422 return 0;
423 }
424
425 VG_STATIC void vg_rebind_input_cmd_poll( int argc, const char *argv[] )
426 {
427 if( argc == 0 )
428 return;
429
430 const char *str_bind_name = argv[0];
431
432 if( argc == 1 )
433 {
434 for( u32 i=0; i<vg_input.named_input_count; i++ )
435 {
436 struct input_binding *bind = &vg_input.named_inputs[i];
437 console_suggest_score_text( bind->name, argv[argc-1], 0 );
438 }
439 }
440
441 else if( argc == 2 )
442 {
443 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
444 {
445 struct input_en *desc = &vg_all_bindable_inputs[i];
446 console_suggest_score_text( desc->alias, argv[argc-1], 0 );
447 }
448 }
449 }
450
451 VG_STATIC u8 vg_getkey( SDL_Keycode kc )
452 {
453 SDL_Scancode sc = SDL_GetScancodeFromKey( kc );
454 return vg_input.sdl_keys[sc];
455 }
456
457 VG_STATIC void vg_input_update( u32 num, struct input_binding *binds )
458 {
459 if( vg_console.enabled )
460 {
461 for( i32 i=0; i<num; i++ )
462 {
463 struct input_binding *bind = &binds[i];
464
465 if( bind->type == k_input_type_button )
466 {
467 bind->button.prev = bind->button.value;
468 bind->button.value = 0;
469 }
470 }
471
472 return;
473 }
474
475 for( i32 i=0; i<num; i++ )
476 {
477 struct input_binding *bind = &binds[i];
478
479 if( bind->type == k_input_type_button )
480 {
481 bind->button.prev = bind->button.value;
482 bind->button.value = 0;
483
484 if( bind->button.gamepad_id != -1 )
485 bind->button.value |=
486 vg_input.controller_buttons[ bind->button.gamepad_id ];
487
488 if( bind->button.keyboard_id != -1 )
489 bind->button.value |= vg_getkey( bind->button.keyboard_id );
490 }
491 else if( bind->type == k_input_type_axis )
492 {
493 float keyboard_value = 0.0f,
494 gamepad_value = 0.0f;
495
496 if( bind->axis.keyboard_positive != -1 )
497 if( vg_getkey( bind->axis.keyboard_positive ) )
498 keyboard_value += 1.0f;
499
500 if( bind->axis.keyboard_negative != -1 )
501 if( vg_getkey( bind->axis.keyboard_negative ) )
502 keyboard_value -= 1.0f;
503
504 if( bind->axis.gamepad_axis != -1 )
505 {
506 gamepad_value =
507 vg_input.controller_axises[ bind->axis.gamepad_axis ];
508
509 if( bind->axis.gamepad_inverted )
510 gamepad_value *= -1.0f;
511 }
512
513 float deadz = vg_clampf( g_controller_deadzone, 0.0f, 0.999f ),
514 high = vg_maxf( 0.0f, fabsf(gamepad_value) - deadz ),
515 norm = high / (1.0f-deadz);
516
517 gamepad_value = vg_signf( gamepad_value ) * norm;
518
519 if( fabsf(keyboard_value) > fabsf(gamepad_value) )
520 bind->axis.value = keyboard_value;
521 else
522 bind->axis.value = gamepad_value;
523 }
524 else if( bind->type == k_input_type_axis_norm )
525 {
526 float value = 0.0f;
527 if( bind->axis.keyboard_positive != -1 )
528 if( vg_getkey( bind->axis.keyboard_positive ))
529 value = 1.0f;
530
531 if( bind->axis.gamepad_axis != -1 )
532 value = vg_maxf( value,
533 vg_input.controller_axises[bind->axis.gamepad_axis] );
534
535 bind->axis.value = value;
536 }
537 }
538 }
539
540 VG_STATIC void vg_input_controller_event( SDL_Event *ev )
541 {
542 if( ev->type == SDL_CONTROLLERAXISMOTION )
543 {
544 if( ev->caxis.which == vg_input.controller_joystick_id )
545 {
546 vg_input.controller_axises[ ev->caxis.axis ] =
547 (float)ev->caxis.value / 32767.0f;
548 }
549 }
550 else if( ev->type == SDL_CONTROLLERBUTTONDOWN )
551 {
552 if( ev->cbutton.which == vg_input.controller_joystick_id )
553 vg_input.controller_buttons[ ev->cbutton.button ] = 1;
554 }
555 else if( ev->type == SDL_CONTROLLERBUTTONUP )
556 {
557 if( ev->cbutton.which == vg_input.controller_joystick_id )
558 vg_input.controller_buttons[ ev->cbutton.button ] = 0;
559 }
560 }
561
562 VG_STATIC void vg_try_attach_controller(void)
563 {
564 int joy_count = SDL_NumJoysticks();
565 for( int i=0; i<joy_count; i++ )
566 {
567 if( SDL_IsGameController(i) )
568 {
569 vg_input.controller_handle = SDL_GameControllerOpen(i);
570 vg_input.controller_joystick_id = i;
571 vg_success( "Attached game controller with joystick ID %d\n", i );
572 return;
573 }
574 }
575 }
576
577
578 VG_STATIC void vg_update_inputs(void)
579 {
580 vg_input.sdl_keys = SDL_GetKeyboardState(NULL);
581
582 if( vg_input.controller_handle )
583 {
584 if( !SDL_GameControllerGetAttached( vg_input.controller_handle ) )
585 {
586 SDL_GameControllerClose( vg_input.controller_handle );
587 vg_input.controller_handle = NULL;
588 }
589 }
590
591 if( !vg_input.controller_handle )
592 {
593 vg_input.controller_axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f;
594 vg_input.controller_axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f;
595 vg_try_attach_controller();
596 }
597
598 /* update all inputs */
599 vg_input_update( vg_input.named_input_count, vg_input.named_inputs );
600 }
601
602 VG_STATIC int vg_console_enabled(void);
603 VG_STATIC int vg_input_button_down( struct input_binding *bind )
604 {
605 if( bind->button.value && !bind->button.prev )
606 return 1;
607 return 0;
608 }
609
610 VG_STATIC void vg_input_init(void)
611 {
612 vg_acquire_thread_sync();
613
614 vg_function_push( (struct vg_cmd)
615 {
616 .name = "bind",
617 .function = vg_rebind_input_cmd,
618 .poll_suggest = vg_rebind_input_cmd_poll
619 });
620
621 vg_var_push( (struct vg_var){
622 .name = "controller_deadzone",
623 .data = &g_controller_deadzone,
624 .data_type = k_var_dtype_f32,
625 .opt_f32 = { .clamp = 0 },
626 .persistent = 1
627 });
628
629 vg_info( "Checking for controller\n" );
630 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
631
632 int joy_count = SDL_NumJoysticks();
633 for( int i=0; i<joy_count; i++ )
634 {
635 vg_info( "joystick %d: %s [gamecontroller: %d]\n",
636 i, SDL_JoystickNameForIndex( i ),
637 SDL_IsGameController(i) );
638 }
639
640 vg_try_attach_controller();
641
642 vg_input.controller_axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f;
643 vg_input.controller_axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f;
644
645 vg_release_thread_sync();
646 }
647
648 VG_STATIC void vg_input_free(void)
649 {
650 if( vg_input.controller_handle )
651 {
652 SDL_GameControllerClose( vg_input.controller_handle );
653 vg_input.controller_handle = NULL;
654 }
655 }
656
657 #endif