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