way better controller handling
[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 #define VG_MAX_CONTROLLERS 4
9
10 VG_STATIC inline float vg_get_axis( const char *axis );
11 VG_STATIC inline int vg_get_button( const char *button );
12
13 /*
14 * Cannot be used in fixed update
15 */
16 VG_STATIC inline int vg_get_button_down( const char *button );
17 VG_STATIC inline int vg_get_button_up( const char *button );
18 VG_STATIC float controller_deadzone = 0.05f;
19
20 enum vg_button_state{
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 const char *name;
29
30 enum input_type{
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 struct input_axis{
45 SDL_GameControllerAxis gamepad_axis;
46 SDL_Keycode keyboard_positive,
47 keyboard_negative;
48
49 int gamepad_inverted;
50 float value;
51 }
52 axis;
53
54 struct{
55 SDL_GameControllerButton gamepad_id;
56 SDL_Keycode keyboard_id;
57 int mouse_id;
58 int value, prev;
59 }
60 button;
61 };
62
63 int save_this;
64 };
65
66 struct
67 {
68 const u8 *sdl_keys;
69 struct input_binding named_inputs[ 32 ];
70 u32 named_input_count;
71
72 struct vg_controller{
73 SDL_GameController *handle; /* handle for controller. NULL if unused */
74 SDL_JoystickID instance_id; /* uid used in events */
75
76 enum evg_controller_type{
77 k_vg_controller_type_standard,
78 k_vg_controller_type_trackpads
79 }
80 type;
81
82 float axises[ SDL_CONTROLLER_AXIS_MAX ];
83 int buttons[ SDL_CONTROLLER_BUTTON_MAX ];
84 }
85 controllers[4];
86
87 int active_controller_index; /* most recent controller (by button press)
88 will be -1 if no controllers active */
89
90 /* what the user is currently using. the keyboard and controller are still
91 * active simultaneously, but this reflects what the UI should show */
92 enum userinput_method{
93 k_userinput_method_xbox,
94 k_userinput_method_playstation,
95 k_userinput_method_steamgeneric,
96 k_userinput_method_kbm
97 }
98 input_method;
99 }
100 static vg_input;
101
102 VG_STATIC void vg_create_unnamed_input( struct input_binding *bind,
103 enum input_type type )
104 {
105 memset( bind, 0, sizeof(struct input_binding) );
106
107 bind->name = "API DEFINED";
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 bind->button.mouse_id = -1;
117 }
118
119 VG_STATIC struct input_binding *vg_create_named_input( const char *name,
120 enum input_type type )
121 {
122 struct input_binding *bind =
123 &vg_input.named_inputs[ vg_input.named_input_count ++ ];
124 memset( bind, 0, sizeof(struct input_binding) );
125
126 bind->name = name;
127 bind->save_this = 0;
128 bind->type = type;
129
130 bind->axis.gamepad_axis = -1;
131 bind->axis.keyboard_positive = -1;
132 bind->axis.keyboard_negative = -1;
133 bind->button.gamepad_id = -1;
134 bind->button.keyboard_id = -1;
135 bind->button.mouse_id = -1;
136
137 return bind;
138 }
139
140 VG_STATIC struct input_binding *vg_get_named_input( const char *name )
141 {
142 if( name[0] == '+' || name[0] == '-' )
143 name ++;
144
145 for( u32 i=0; i<vg_input.named_input_count; i++ ){
146 struct input_binding *bind = &vg_input.named_inputs[i];
147 if( !strcmp( bind->name, name ) )
148 return bind;
149 }
150
151 return NULL;
152 }
153
154 struct input_en
155 {
156 enum input_type type;
157
158 const char *alias;
159 int id;
160 }
161 vg_all_bindable_inputs[] =
162 {
163 {k_input_type_keyboard_key, "space", SDLK_SPACE},
164 {k_input_type_keyboard_key, ";", SDLK_SEMICOLON},
165 {k_input_type_keyboard_key, "-", SDLK_MINUS},
166 {k_input_type_keyboard_key, ".", SDLK_PERIOD},
167 {k_input_type_keyboard_key, ",", SDLK_COMMA},
168 {k_input_type_keyboard_key, "=", SDLK_EQUALS},
169 {k_input_type_keyboard_key, "[", SDLK_LEFTBRACKET},
170 {k_input_type_keyboard_key, "]", SDLK_RIGHTBRACKET},
171 {k_input_type_keyboard_key, "left", SDLK_LEFT},
172 {k_input_type_keyboard_key, "right", SDLK_RIGHT},
173 {k_input_type_keyboard_key, "up", SDLK_UP},
174 {k_input_type_keyboard_key, "down", SDLK_DOWN},
175 {k_input_type_keyboard_key, "shift", SDLK_LSHIFT},
176 {k_input_type_keyboard_key, "control", SDLK_LCTRL},
177 {k_input_type_keyboard_key, "\2enter", SDLK_RETURN},
178 {k_input_type_keyboard_key, "\2escape", SDLK_ESCAPE },
179
180 {k_input_type_gamepad_axis, "gp-lt", SDL_CONTROLLER_AXIS_TRIGGERLEFT},
181 {k_input_type_gamepad_axis, "gp-rt", SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
182 {k_input_type_gamepad_axis, "gp-ls-h", SDL_CONTROLLER_AXIS_LEFTX},
183 {k_input_type_gamepad_axis, "gp-ls-v", SDL_CONTROLLER_AXIS_LEFTY},
184 {k_input_type_gamepad_axis, "gp-rs-h", SDL_CONTROLLER_AXIS_RIGHTX},
185 {k_input_type_gamepad_axis, "gp-rs-v", SDL_CONTROLLER_AXIS_RIGHTY},
186
187 {k_input_type_gamepad_button, "gp-a", SDL_CONTROLLER_BUTTON_A},
188 {k_input_type_gamepad_button, "gp-b", SDL_CONTROLLER_BUTTON_B},
189 {k_input_type_gamepad_button, "gp-x", SDL_CONTROLLER_BUTTON_X},
190 {k_input_type_gamepad_button, "gp-y", SDL_CONTROLLER_BUTTON_Y},
191 {k_input_type_gamepad_button, "gp-rb", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
192 {k_input_type_gamepad_button, "gp-lb", SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
193 {k_input_type_gamepad_button, "gp-rs", SDL_CONTROLLER_BUTTON_RIGHTSTICK},
194 {k_input_type_gamepad_button, "gp-ls", SDL_CONTROLLER_BUTTON_LEFTSTICK},
195 {k_input_type_gamepad_button, "gp-dpad-down", SDL_CONTROLLER_BUTTON_DPAD_DOWN},
196 {k_input_type_gamepad_button, "gp-dpad-left", SDL_CONTROLLER_BUTTON_DPAD_LEFT},
197 {k_input_type_gamepad_button,"gp-dpad-right",SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
198 {k_input_type_gamepad_button, "gp-dpad-up", SDL_CONTROLLER_BUTTON_DPAD_UP},
199 {k_input_type_gamepad_button, "\2gp-menu", SDL_CONTROLLER_BUTTON_BACK},
200
201 {k_input_type_mouse_button, "mouse1", SDL_BUTTON_LEFT },
202 {k_input_type_mouse_button, "mouse2", SDL_BUTTON_RIGHT }
203 };
204
205 VG_STATIC const char *vg_input_to_str( u32 input, enum input_type input_type )
206 {
207 if( input == -1 )
208 return NULL;
209
210 if( input_type == k_input_type_keyboard_key ){
211 if( (input >= SDLK_a) && (input <= SDLK_z) ){
212 return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
213 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input-SDLK_a)*2];
214 }
215
216 if( (input >= SDLK_0) && (input <= SDLK_9) ){
217 return &"0\0" "1\0" "2\0" "3\0" "4\0"
218 "5\0" "6\0" "7\0" "8\0" "9\0"[(input-SDLK_0)*2];
219 }
220 }
221
222 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ ){
223 struct input_en *desc = &vg_all_bindable_inputs[i];
224
225 if( (desc->type == input_type) && (desc->id == input) )
226 return desc->alias;
227 }
228
229 return NULL;
230 }
231
232 VG_STATIC enum input_type vg_str_to_input( const char *str, u32 *input )
233 {
234 if( !str ){
235 *input = -1;
236 return k_input_type_unknown;
237 }
238
239 u32 len = strlen(str);
240
241 if( len == 0 ){
242 *input = -1;
243 return k_input_type_unknown;
244 }
245
246 if( len == 1 ){
247 u8 uch = str[0];
248
249 if( (uch >= (u8)'a') && (uch <= (u8)'z') ){
250 *input = SDLK_a + (uch-(u8)'a');
251 return k_input_type_keyboard_key;
252 }
253
254 if( (uch >= (u8)'0') && (uch <= (u8)'9') ){
255 *input = SDLK_0 + (uch-(u8)'0');
256 return k_input_type_keyboard_key;
257 }
258 }
259
260 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ ){
261 struct input_en *desc = &vg_all_bindable_inputs[i];
262
263 if( !strcmp( desc->alias, str ) ){
264 *input = desc->id;
265 return desc->type;
266 }
267 }
268
269 *input = -1;
270 return k_input_type_unknown;
271 }
272
273 VG_STATIC void vg_print_binding_info( struct input_binding *bind )
274 {
275 vg_info( " name: %s\n", bind->name );
276 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
277 [ bind->type ] );
278 vg_info( " save this? %d\n", bind->save_this );
279
280 if( (bind->type == k_input_type_axis) ||
281 (bind->type == k_input_type_axis_norm) )
282 {
283 vg_info( " gamepad_axis: %s\n",
284 vg_input_to_str(bind->axis.gamepad_axis, k_input_type_gamepad_axis));
285
286 vg_info( " keyboard_positive: %s\n",
287 vg_input_to_str(bind->axis.keyboard_positive,
288 k_input_type_keyboard_key ));
289
290 vg_info( " keyboard_negative: %s\n",
291 vg_input_to_str(bind->axis.keyboard_negative,
292 k_input_type_keyboard_key ));
293 }
294 else{
295 vg_info( " gamepad_id: %s\n",
296 vg_input_to_str(bind->button.gamepad_id, k_input_type_gamepad_button));
297 vg_info( " keyboard_id: %s\n",
298 vg_input_to_str(bind->button.keyboard_id,
299 k_input_type_keyboard_key));
300 vg_info( " mouse_id: %s\n",
301 vg_input_to_str(bind->button.mouse_id,
302 k_input_type_mouse_button));
303 }
304 }
305
306 VG_STATIC void vg_apply_bind_str( struct input_binding *bind,
307 const char *mod,
308 const char *str )
309 {
310 int axis_mod = 0;
311 char modch = ' ';
312 if( (mod[0] == '-') || (mod[0] == '+') ){
313 axis_mod = 1;
314 modch = mod[0];
315 mod ++;
316 }
317
318 int invert = 0;
319 if( (str[0] == '-' ) ){
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 if( axis_mod ){
329 vg_error( "Cannot use axis modifiers on button input!\n" );
330 return;
331 }
332
333 if( invert ){
334 vg_error( "Cannot invert button input!\n" );
335 return;
336 }
337
338 if( type == k_input_type_keyboard_key )
339 bind->button.keyboard_id = id;
340 else if( type == k_input_type_mouse_button )
341 bind->button.mouse_id = id;
342 else if( type == k_input_type_gamepad_button )
343 bind->button.gamepad_id = id;
344 else{
345 vg_error( "Unknown button or key '%s'\n", str );
346 return;
347 }
348 }
349 else if( (bind->type == k_input_type_axis ) ||
350 (bind->type == k_input_type_axis_norm))
351 {
352 if( axis_mod ){
353 if( type == k_input_type_keyboard_key ){
354 if( invert ){
355 vg_error( "Cannot invert a keyboard key!\n" );
356 return;
357 }
358
359 if( modch == '+' )
360 bind->axis.keyboard_positive = id;
361 else
362 bind->axis.keyboard_negative = id;
363 }
364 else{
365 vg_error( "You can only bind keyboard keys to +- axises\n" );
366 return;
367 }
368 }
369 else{
370 if( type == k_input_type_gamepad_axis ){
371 bind->axis.gamepad_inverted = invert;
372 bind->axis.gamepad_axis = id;
373 }
374 else{
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 vg_info( "Usage: bind jump x\n" );
393 vg_info( " bind -steerh j\n" );
394 vg_info( " bind steerh gp-ls-h\n" );
395 return 0;
396 }
397
398 const char *str_bind_name = argv[0];
399 struct input_binding *bind = vg_get_named_input( str_bind_name );
400
401 if( !bind ){
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 vg_print_binding_info( bind );
408 return 0;
409 }
410
411 if( argc == 2 ){
412 const char *str_input_id = argv[1];
413
414 vg_apply_bind_str( bind, str_bind_name, str_input_id );
415 return 0;
416 }
417
418 return 0;
419 }
420
421 VG_STATIC void vg_rebind_input_cmd_poll( int argc, const char *argv[] )
422 {
423 if( argc == 0 )
424 return;
425
426 const char *str_bind_name = argv[0];
427
428 if( argc == 1 ){
429 for( u32 i=0; i<vg_input.named_input_count; i++ ){
430 struct input_binding *bind = &vg_input.named_inputs[i];
431 console_suggest_score_text( bind->name, argv[argc-1], 0 );
432 }
433 }
434 else if( argc == 2 ){
435 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ ){
436 struct input_en *desc = &vg_all_bindable_inputs[i];
437 console_suggest_score_text( desc->alias, argv[argc-1], 0 );
438 }
439 }
440 }
441
442 VG_STATIC u8 vg_getkey( SDL_Keycode kc )
443 {
444 SDL_Scancode sc = SDL_GetScancodeFromKey( kc );
445 return vg_input.sdl_keys[sc];
446 }
447
448 VG_STATIC void vg_input_update( u32 num, struct input_binding *binds )
449 {
450 if( vg_console.enabled ){
451 for( i32 i=0; i<num; i++ ){
452 struct input_binding *bind = &binds[i];
453
454 if( bind->type == k_input_type_button ){
455 bind->button.prev = bind->button.value;
456 bind->button.value = 0;
457 }
458 }
459
460 return;
461 }
462
463 struct vg_controller *acontroller = NULL;
464
465 if( vg_input.active_controller_index != -1 )
466 acontroller = &vg_input.controllers[vg_input.active_controller_index];
467
468 for( i32 i=0; i<num; i++ ){
469 struct input_binding *bind = &binds[i];
470
471 if( bind->type == k_input_type_button ){
472 bind->button.prev = bind->button.value;
473 bind->button.value = 0;
474
475 if( acontroller && (bind->button.gamepad_id != -1) )
476 bind->button.value |= acontroller->buttons[bind->button.gamepad_id];
477
478 if( bind->button.keyboard_id != -1 )
479 bind->button.value |= vg_getkey( bind->button.keyboard_id );
480
481 if( bind->button.mouse_id != -1 ){
482 if(SDL_GetMouseState(NULL,NULL) & SDL_BUTTON(bind->button.mouse_id))
483 bind->button.value |= 1;
484 }
485 }
486 else if( bind->type == k_input_type_axis ){
487 float keyboard_value = 0.0f,
488 gamepad_value = 0.0f;
489
490 if( bind->axis.keyboard_positive != -1 )
491 if( vg_getkey( bind->axis.keyboard_positive ) )
492 keyboard_value += 1.0f;
493
494 if( bind->axis.keyboard_negative != -1 )
495 if( vg_getkey( bind->axis.keyboard_negative ) )
496 keyboard_value -= 1.0f;
497
498 if( acontroller && (bind->axis.gamepad_axis != -1) ){
499 gamepad_value = acontroller->axises[ bind->axis.gamepad_axis ];
500
501 if( bind->axis.gamepad_inverted )
502 gamepad_value *= -1.0f;
503 }
504
505 float deadz = vg_clampf( controller_deadzone, 0.0f, 0.999f ),
506 high = vg_maxf( 0.0f, fabsf(gamepad_value) - deadz ),
507 norm = high / (1.0f-deadz);
508
509 gamepad_value = vg_signf( gamepad_value ) * norm;
510
511 if( fabsf(keyboard_value) > fabsf(gamepad_value) )
512 bind->axis.value = keyboard_value;
513 else
514 bind->axis.value = gamepad_value;
515 }
516 else if( bind->type == k_input_type_axis_norm ){
517 float value = 0.0f;
518 if( bind->axis.keyboard_positive != -1 )
519 if( vg_getkey( bind->axis.keyboard_positive ))
520 value = 1.0f;
521
522 if( acontroller && (bind->axis.gamepad_axis != -1) ){
523 float value1 = acontroller->axises[bind->axis.gamepad_axis];
524 value = vg_maxf( value, value1 );
525 }
526
527 bind->axis.value = value;
528 }
529 }
530 }
531
532 /*
533 * takes SDL device index, and tries to open that on any free channel
534 */
535 VG_STATIC void vg_open_gamecontroller( Sint32 index )
536 {
537 struct vg_controller *controller = NULL;
538 int vg_id = 0;
539 const char *name = SDL_GameControllerNameForIndex( index );
540 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
541
542 if( instance_id == -1 ){
543 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
544 return;
545 }
546
547 for( int j=0; j<VG_MAX_CONTROLLERS; j++ ){
548 struct vg_controller *esta = &vg_input.controllers[j];
549
550 if( esta->handle ){
551 if( esta->instance_id == instance_id ){
552 vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n",
553 esta->instance_id, j );
554 return;
555 }
556 }
557 else{
558 if( !controller ){
559 controller = &vg_input.controllers[j];
560 vg_id = j;
561 }
562 }
563 }
564
565 if( controller ){
566 controller->handle = SDL_GameControllerOpen( index );
567 controller->instance_id = instance_id;
568
569 if( controller->handle ){
570 vg_success(
571 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
572 instance_id, name, vg_id );
573
574 controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f;
575 controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f;
576 }
577 else{
578 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
579 name, SDL_GetError() );
580 }
581 }
582 else{
583 vg_error( ". Too many controllers open! ignoring '%s'\n", name );
584
585 }
586 }
587
588 VG_STATIC void vg_input_device_event( SDL_Event *ev )
589 {
590 if( ev->type == SDL_CONTROLLERDEVICEADDED ){
591 int is_controller = SDL_IsGameController( ev->cdevice.which );
592 const char *name = SDL_JoystickNameForIndex( ev->cdevice.which );
593
594 Sint32 index = ev->cdevice.which;
595 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
596 vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n",
597 index, name );
598
599 if( is_controller ){
600 vg_open_gamecontroller( index );
601 }
602 }
603 else if( ev->type == SDL_CONTROLLERDEVICEREMOVED ){
604 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
605 ev->cdevice.which );
606
607 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
608 struct vg_controller *controller = &vg_input.controllers[i];
609
610 if( controller->handle ){
611 if( controller->instance_id == ev->cdevice.which ){
612 vg_info( " . closing controller at index #%d\n", i );
613 SDL_GameControllerClose( controller->handle );
614 controller->handle = NULL;
615 controller->instance_id = -1;
616
617 if( vg_input.active_controller_index == i ){
618 vg_input.active_controller_index = -1;
619 vg_info( " . active controller is now keyboard and mouse\n" );
620 }
621 break;
622 }
623 }
624 }
625 }
626 }
627
628 VG_STATIC void vg_input_controller_event( SDL_Event *ev )
629 {
630 if( ev->type == SDL_CONTROLLERAXISMOTION ){
631 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
632 struct vg_controller *esta = &vg_input.controllers[i];
633
634 if( ev->caxis.which == esta->instance_id ){
635 float value = (float)ev->caxis.value / 32767.0f;
636 esta->axises[ ev->caxis.axis ] = value;
637 break;
638 }
639 }
640 }
641 else if( ev->type == SDL_CONTROLLERBUTTONDOWN ){
642 struct vg_controller *active = NULL;
643
644 if( vg_input.active_controller_index != -1 )
645 active = &vg_input.controllers[vg_input.active_controller_index];
646
647 if( !active || (ev->cbutton.which != active->instance_id) ){
648 active = NULL;
649 vg_input.active_controller_index = -1;
650
651 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
652 if( vg_input.controllers[i].instance_id == ev->cbutton.which ){
653 active = &vg_input.controllers[i];
654 vg_input.active_controller_index = i;
655 break;
656 }
657 }
658
659 if( active ){
660 vg_info( "Switching active controller index to #%d\n",
661 vg_input.active_controller_index );
662 }
663 else{
664 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
665 ev->cbutton.which );
666 }
667 }
668
669 if( active )
670 active->buttons[ ev->cbutton.button ] = 1;
671 }
672 else if( ev->type == SDL_CONTROLLERBUTTONUP ){
673 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
674 struct vg_controller *esta = &vg_input.controllers[i];
675
676 if( ev->cbutton.which == esta->instance_id ){
677 esta->buttons[ ev->cbutton.button ] = 0;
678 break;
679 }
680 }
681 }
682 }
683
684 VG_STATIC void vg_process_inputs(void)
685 {
686 int count;
687 vg_input.sdl_keys = SDL_GetKeyboardState( &count );
688
689 if( vg_input.input_method != k_userinput_method_kbm ){
690 /* check for giving keyboard priority */
691 for( int i=0; i<count; i++ ){
692 if( vg_input.sdl_keys[i] ){
693 vg_input.input_method = k_userinput_method_kbm;
694 break;
695 }
696 }
697
698 /* check for giving mouse priority */
699 if( SDL_GetMouseState(NULL,NULL) &
700 (SDL_BUTTON(SDL_BUTTON_LEFT)|SDL_BUTTON(SDL_BUTTON_RIGHT)) )
701 {
702 vg_input.input_method = k_userinput_method_kbm;
703 }
704 }
705
706 /* update all inputs */
707 vg_input_update( vg_input.named_input_count, vg_input.named_inputs );
708 }
709
710 VG_STATIC int vg_console_enabled(void);
711 VG_STATIC int vg_input_button_down( struct input_binding *bind )
712 {
713 if( bind->button.value && !bind->button.prev )
714 return 1;
715 return 0;
716 }
717
718 VG_STATIC void async_vg_input_init( void *payload, u32 size )
719 {
720 vg_console_reg_cmd( "bind", vg_rebind_input_cmd, vg_rebind_input_cmd_poll );
721
722 VG_VAR_F32( controller_deadzone, flags=VG_VAR_PERSISTENT );
723
724 vg_info( "Checking for controllers\n" );
725 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
726
727 int joy_count = SDL_NumJoysticks();
728 for( int i=0; i<joy_count; i++ ) {
729 const char *name = SDL_JoystickNameForIndex( i );
730 int is_controller = SDL_IsGameController(i);
731
732 vg_info( "%d: %s [controller: %d]\n", i, name, is_controller );
733
734 if( is_controller ){
735 vg_open_gamecontroller( i );
736 }
737 }
738 }
739
740 VG_STATIC void vg_input_init(void)
741 {
742 vg_async_call( async_vg_input_init, NULL, 0 );
743 }
744
745 VG_STATIC void vg_input_free(void)
746 {
747 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
748 struct vg_controller *controller = &vg_input.controllers[i];
749
750 if( controller->handle ){
751 SDL_GameControllerClose( controller->handle );
752 controller->handle = NULL;
753 }
754 }
755 }
756
757 #endif