bad char
[vg.git] / vg_input.c
1 /* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */
2
3 #include "vg_input.h"
4 #include "vg_loader.h"
5 #include "vg_engine.h"
6 #include "vg_async.h"
7 #include "vg_string.h"
8
9 f32 controller_deadzone = 0.05f;
10
11 struct vg_input vg_input = {
12 .active_controller_index = -2
13 };
14
15 u8 vg_getkey( SDL_Keycode kc )
16 {
17 SDL_Scancode sc = SDL_GetScancodeFromKey( kc );
18 return vg_input.sdl_keys[sc];
19 }
20
21 /*
22 * takes SDL device index, and tries to open that on any free channel
23 */
24 static int vg_open_gamecontroller( Sint32 index )
25 {
26 struct vg_controller *controller = NULL;
27 int vg_id = 0;
28 const char *name = SDL_GameControllerNameForIndex( index );
29 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
30
31 if( instance_id == -1 ){
32 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
33 return -1;
34 }
35
36 for( int j=0; j<VG_MAX_CONTROLLERS; j++ ){
37 struct vg_controller *esta = &vg_input.controllers[j];
38
39 if( esta->handle ){
40 if( esta->instance_id == instance_id ){
41 vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n",
42 esta->instance_id, j );
43 return -1;
44 }
45 }
46 else{
47 if( !controller ){
48 controller = &vg_input.controllers[j];
49 vg_id = j;
50 }
51 }
52 }
53
54 if( controller ){
55 controller->handle = SDL_GameControllerOpen( index );
56 controller->instance_id = instance_id;
57
58 if( controller->handle ){
59 vg_success(
60 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
61 instance_id, name, vg_id );
62
63 for( u32 i=0; i< SDL_CONTROLLER_BUTTON_MAX; i++ )
64 controller->buttons[i] = 0;
65
66 for( u32 i=0; i< SDL_CONTROLLER_AXIS_MAX; i++ )
67 controller->axises[i] = 0.0f;
68
69 if( vg_input.active_controller_index == -2 ){
70 vg_input.active_controller_index = vg_id;
71 vg_input.display_input_method = k_input_method_controller;
72 vg_input.display_input_type =
73 SDL_GameControllerGetType( controller->handle );
74 }
75
76 return vg_id;
77 }
78 else{
79 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
80 name, SDL_GetError() );
81 return -1;
82 }
83 }
84 else{
85 vg_error( ". Too many controllers open! ignoring '%s'\n", name );
86 return -1;
87 }
88 }
89
90 void vg_input_device_event( SDL_Event *ev )
91 {
92 if( ev->type == SDL_CONTROLLERDEVICEADDED ){
93 int is_controller = SDL_IsGameController( ev->cdevice.which );
94 const char *name = SDL_JoystickNameForIndex( ev->cdevice.which );
95
96 Sint32 index = ev->cdevice.which;
97 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
98 vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n",
99 index, name );
100
101 if( is_controller ){
102 vg_open_gamecontroller( index );
103 }
104 }
105 else if( ev->type == SDL_CONTROLLERDEVICEREMOVED ){
106 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
107 ev->cdevice.which );
108
109 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
110 struct vg_controller *controller = &vg_input.controllers[i];
111
112 if( controller->handle ){
113 if( controller->instance_id == ev->cdevice.which ){
114 vg_info( " . closing controller at index #%d\n", i );
115 SDL_GameControllerClose( controller->handle );
116 controller->handle = NULL;
117 controller->instance_id = -1;
118
119 if( vg_input.active_controller_index == i ){
120 vg_input.active_controller_index = -1;
121 vg_input.display_input_method = k_input_method_kbm;
122 vg_info( "display_input: k_input_method_kbm\n" );
123 }
124 break;
125 }
126 }
127 }
128 }
129 }
130
131 static void vg_input_set_active_controller( int index, const char *why )
132 {
133 if( vg_input.active_controller_index != index )
134 {
135 vg_input.display_input_type =
136 SDL_GameControllerGetType( vg_input.controllers[index].handle );
137 vg_input.active_controller_index = index;
138 vg_info( "Switching controller index to #%d. (%s)\n", index, why );
139 }
140
141 if( vg_input.display_input_method != k_input_method_controller )
142 {
143 vg_input.display_input_method = k_input_method_controller;
144 vg_info( "Switching input method to controller. (%s)\n", why );
145 }
146 }
147
148 void vg_input_controller_event( SDL_Event *ev )
149 {
150 if( ev->type == SDL_CONTROLLERAXISMOTION )
151 {
152 for( int i=0; i<VG_MAX_CONTROLLERS; i++ )
153 {
154 struct vg_controller *esta = &vg_input.controllers[i];
155
156 if( ev->caxis.which == esta->instance_id )
157 {
158 float value = (float)ev->caxis.value / 32767.0f;
159
160 if( ev->caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ||
161 ev->caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ||
162 ev->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX ||
163 ev->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY )
164 {
165 float deadz = vg_clampf( controller_deadzone, 0.0f, 0.999f ),
166 high = vg_maxf( 0.0f, fabsf(value) - deadz );
167
168 value = vg_signf(value) * (high / (1.0f-deadz));
169 if( fabsf(value) > 0.5f )
170 vg_input_set_active_controller( i, "Stick pushed >|0.5|" );
171 }
172
173 esta->axises[ ev->caxis.axis ] = value;
174 break;
175 }
176 }
177 }
178 else if( ev->type == SDL_CONTROLLERBUTTONDOWN )
179 {
180 for( int i=0; i<VG_MAX_CONTROLLERS; i++ )
181 {
182 struct vg_controller *esta = &vg_input.controllers[i];
183 if( esta->instance_id == ev->cbutton.which )
184 {
185 vg_input_set_active_controller( i, "Button press" );
186 esta->buttons[ ev->cbutton.button ] = 1;
187 break;
188 }
189 }
190 }
191 else if( ev->type == SDL_CONTROLLERBUTTONUP )
192 {
193 for( int i=0; i<VG_MAX_CONTROLLERS; i++ )
194 {
195 struct vg_controller *esta = &vg_input.controllers[i];
196 if( ev->cbutton.which == esta->instance_id )
197 {
198 esta->buttons[ ev->cbutton.button ] = 0;
199 break;
200 }
201 }
202 }
203 }
204
205 void vg_process_inputs(void)
206 {
207 int count;
208 vg_input.sdl_keys = SDL_GetKeyboardState( &count );
209 vg_input.sdl_mouse = SDL_GetMouseState(NULL,NULL);
210
211 if( vg_input.display_input_method != k_input_method_kbm )
212 {
213 /* check for giving keyboard priority */
214 for( int i=0; i<count; i++ )
215 {
216 if( vg_input.sdl_keys[i] )
217 {
218 vg_input.display_input_method = k_input_method_kbm;
219 vg_info( "display_input: k_input_method_kbm (keyboard %d)\n", i );
220 break;
221 }
222 }
223
224 /* check for giving mouse priority */
225 if( vg_input.sdl_mouse &
226 (SDL_BUTTON(SDL_BUTTON_LEFT)|SDL_BUTTON(SDL_BUTTON_RIGHT)|
227 SDL_BUTTON(SDL_BUTTON_MIDDLE)) )
228 {
229 vg_input.display_input_method = k_input_method_kbm;
230 vg_info( "display_input: k_input_method_kbm (mouse click)\n" );
231 }
232
233 vg_input.hidden_mouse_travel += v2_length( vg.mouse_delta );
234 if( vg_input.hidden_mouse_travel > 64.0f )
235 {
236 vg_input.display_input_method = k_input_method_kbm;
237 vg_input.hidden_mouse_travel = 0.0f;
238 vg_info( "display_input: k_input_method_kbm (mouse move)\n" );
239 }
240 }
241 else
242 vg_input.hidden_mouse_travel = 0.0f;
243 }
244
245 void async_vg_input_init( void *payload, u32 size )
246 {
247 vg_info( "Checking for controllers\n" );
248 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
249
250 int joy_count = SDL_NumJoysticks();
251 for( int i=0; i<joy_count; i++ ) {
252 const char *name = SDL_JoystickNameForIndex( i );
253 int is_controller = SDL_IsGameController(i);
254
255 vg_info( "%d: %s [controller: %d]\n", i, name, is_controller );
256
257 if( is_controller ){
258 vg_open_gamecontroller( i );
259 }
260 }
261 }
262
263 void vg_input_init(void)
264 {
265 VG_VAR_F32( controller_deadzone, flags=VG_VAR_PERSISTENT );
266 vg_async_call( async_vg_input_init, NULL, 0 );
267 }
268
269 void vg_input_free(void)
270 {
271 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
272 struct vg_controller *controller = &vg_input.controllers[i];
273
274 if( controller->handle ){
275 SDL_GameControllerClose( controller->handle );
276 controller->handle = NULL;
277 }
278 }
279 }
280
281 struct vg_controller *vg_active_controller(void)
282 {
283 if( vg_input.active_controller_index >= 0 )
284 return &vg_input.controllers[vg_input.active_controller_index];
285 else
286 return NULL;
287 }
288
289 u8 vg_controller_button( SDL_GameControllerButton button )
290 {
291 struct vg_controller *c = vg_active_controller();
292 if( c ) return c->buttons[ button ];
293 else return 0;
294 }
295
296 f32 vg_controller_axis( SDL_GameControllerAxis axis )
297 {
298 struct vg_controller *c = vg_active_controller();
299 if( c ) return c->axises[ axis ];
300 else return 0;
301 }
302
303 static void vg_input_apply_to_u8( vg_input_op mode, u8 data, u8 *inout_result ){
304 if ( mode == vg_mode_absmax ) *inout_result |= data;
305 else if( mode == vg_mode_mul ) *inout_result &= data;
306 else vg_fatal_error( "mode not supported for destination type (%d)", mode );
307 }
308
309 static void vg_input_apply_to_f32( vg_input_op mode, f32 data,
310 f32 *inout_result ){
311 if ( mode == vg_mode_absmax ){
312 if( fabsf(data) > fabsf(*inout_result) )
313 *inout_result = data;
314 }
315 else if( mode == vg_mode_max ) *inout_result = vg_maxf(*inout_result,data);
316 else if( mode == vg_mode_mul ) *inout_result *= (f32)data;
317 else if( mode == vg_mode_sub ) *inout_result -= (f32)data;
318 else if( mode == vg_mode_add ) *inout_result += (f32)data;
319 else vg_fatal_error( "mode not supported for destination type (%d)", mode );
320 }
321
322 /*
323 * Run an input program. out_result must point to memory with sufficient
324 * storage respective to the size set by type.
325 */
326 void vg_exec_input_program( enum vg_input_type type, vg_input_op *ops,
327 void *out_result ){
328 u8 *out_button = NULL;
329 f32 *out_joy = NULL;
330
331 if( type == k_vg_input_type_button_u8 ){
332 out_button = out_result;
333 *out_button = 0;
334 }
335 else if( type == k_vg_input_type_axis_f32 ){
336 out_joy = out_result;
337 out_joy[0] = 0.0f;
338 }
339 else if( type == k_vg_input_type_joy_v2f ){
340 out_joy = out_result;
341 out_joy[0] = 0.0f;
342 out_joy[1] = 0.0f;
343 }
344
345 /* computer state */
346 vg_input_op mode = vg_mode_absmax;
347 u32 pc = 0, index = 0;
348
349 next_code:;
350 vg_input_op op = ops[ pc ++ ];
351
352 if( (op >= vg_mode_mul) && (op <= vg_mode_max) )
353 mode = op;
354 else if( (op == vg_keyboard) || (op == vg_mouse) || (op == vg_joy_button) ){
355 u8 state = 0;
356
357 if( op == vg_keyboard )
358 state = vg_getkey(ops[pc ++]);
359 else if( op == vg_mouse )
360 state = (vg_input.sdl_mouse & SDL_BUTTON(ops[pc ++]))?1:0;
361 else
362 state = vg_controller_button(ops[pc ++]);
363
364 if( type == k_vg_input_type_button_u8 )
365 vg_input_apply_to_u8( mode, state, out_button );
366 else
367 vg_input_apply_to_f32( mode, (f32)state, &out_joy[index] );
368 }
369 else if( op == vg_joy_axis ){
370 f32 state = vg_controller_axis( ops[pc ++] );
371 if( type == k_vg_input_type_button_u8 )
372 vg_input_apply_to_u8( mode, state>0.5f?1:0, out_button );
373 else
374 vg_input_apply_to_f32( mode, state, &out_joy[index] );
375 }
376 else if( (op == vg_joy_ls) || (op == vg_joy_rs) ){
377 if( type == k_vg_input_type_joy_v2f ){
378 vg_input_apply_to_f32( mode,
379 vg_controller_axis( op==vg_joy_ls? SDL_CONTROLLER_AXIS_LEFTX:
380 SDL_CONTROLLER_AXIS_RIGHTX),
381 &out_joy[0] );
382 vg_input_apply_to_f32( mode,
383 vg_controller_axis( op==vg_joy_ls? SDL_CONTROLLER_AXIS_LEFTY:
384 SDL_CONTROLLER_AXIS_RIGHTY),
385 &out_joy[1] );
386 }
387 }
388 else if( op == vg_index )
389 index = ops[pc ++];
390 else if( op == vg_end )
391 return;
392 else if( op == vg_normalize )
393 v2_normalize( out_joy );
394 else if( op == vg_gui_visible )
395 pc ++;
396 else
397 vg_fatal_error( "unknown op\n" );
398
399 goto next_code;
400 }
401
402 /*
403 * Get vendor specific button glyphs based on SDL button ID
404 */
405 const char *controller_button_str( SDL_GameControllerButton button )
406 {
407 static const char *controller_glyphs[ SDL_CONTROLLER_BUTTON_MAX ][2] = {
408 /* xbox/generic playstation */
409 [ SDL_CONTROLLER_BUTTON_A ] = { KGRN "\x06\x02\x85",KBLU "\x06\x02\x82" },
410 [ SDL_CONTROLLER_BUTTON_B ] = { KRED "\x06\x02\x86",KRED "\x06\x02\x81" },
411 [ SDL_CONTROLLER_BUTTON_X ] = { KBLU "\x06\x02\x83",KMAG "\x06\x02\x7f" },
412 [ SDL_CONTROLLER_BUTTON_Y ] = { KYEL "\x06\x02\x84",KGRN "\x06\x02\x80" },
413 [ SDL_CONTROLLER_BUTTON_LEFTSTICK ] = { "\x87","\x87" },
414 [ SDL_CONTROLLER_BUTTON_RIGHTSTICK ] = { "\x8b","\x8b" },
415 [ SDL_CONTROLLER_BUTTON_LEFTSHOULDER ] = { "\x91","\x91" },
416 [ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ]= { "\x92","\x92" },
417 [ SDL_CONTROLLER_BUTTON_DPAD_LEFT ] = { "\x93","\x93" },
418 [ SDL_CONTROLLER_BUTTON_DPAD_UP ] = { "\x94","\x94" },
419 [ SDL_CONTROLLER_BUTTON_DPAD_RIGHT ] = { "\x95","\x95" },
420 [ SDL_CONTROLLER_BUTTON_DPAD_DOWN ] = { "\x96","\x96" },
421 [ SDL_CONTROLLER_BUTTON_GUIDE ] = { "\x91","\x91" },
422 };
423
424 if( vg_input.display_input_type == SDL_CONTROLLER_TYPE_PS3 ||
425 vg_input.display_input_type == SDL_CONTROLLER_TYPE_PS4 ||
426 vg_input.display_input_type == SDL_CONTROLLER_TYPE_PS5 )
427 {
428 return controller_glyphs[ button ][ 1 ];
429 }
430 else if( vg_input.display_input_type ==
431 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO ||
432 vg_input.display_input_type ==
433 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
434 vg_input.display_input_type ==
435 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR ||
436 vg_input.display_input_type ==
437 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT )
438 {
439 return NULL;
440 }
441 else
442 return controller_glyphs[ button ][ 0 ];
443 }
444
445 /*
446 * Cat keyboard key string. special_glyphs include SR glyphs
447 */
448 void vg_keyboard_key_string( vg_str *str, u32 key, int special_glyphs )
449 {
450 if( (key >= SDLK_a) && (key <= SDLK_z) ){
451 key = (key-SDLK_a)+(u32)'A';
452 vg_strcatch( str, key );
453 }
454 else if( (key == SDLK_LSHIFT) || (key == SDLK_RSHIFT) )
455 vg_strcat( str, special_glyphs? "\x9e": "shift" );
456 else if( (key == SDLK_LCTRL) || (key == SDLK_RCTRL) )
457 vg_strcat( str, special_glyphs? "\x9f": "ctrl" );
458 else if( (key == SDLK_LALT) || (key == SDLK_RALT) )
459 vg_strcat( str, special_glyphs? "\xa0": "alt" );
460 else if( key == SDLK_SPACE )
461 vg_strcat( str, special_glyphs? "\xa1": "space" );
462 else if( (key == SDLK_RETURN) || (key == SDLK_RETURN2) )
463 vg_strcat( str, special_glyphs? "\xa2": "return" );
464 else if( key == SDLK_ESCAPE )
465 vg_strcat( str, special_glyphs? "\xa3": "escape" );
466 else if( key == SDLK_RIGHT )
467 vg_strcat( str, special_glyphs? "\x95 ": "right" );
468 else if( key == SDLK_LEFT )
469 vg_strcat( str, special_glyphs? "\x93 ": "left" );
470 else if( key == SDLK_UP )
471 vg_strcat( str, special_glyphs? "\x94 ": "up" );
472 else if( key == SDLK_DOWN )
473 vg_strcat( str, special_glyphs? "\x96 ": "down" );
474 else {
475 vg_strcat( str, "keyboard key #" );
476 vg_strcati32( str, key );
477 }
478 }
479
480 /*
481 * Cat mouse button string. special_glyphs include SR glyphs
482 */
483 void vg_mouse_button_string( vg_str *str, u32 button, int special_glyphs )
484 {
485 if ( button == SDL_BUTTON_LEFT )
486 vg_strcat( str, special_glyphs? "\x99": "left mouse" );
487 else if( button == SDL_BUTTON_RIGHT )
488 vg_strcat( str, special_glyphs? "\x9a": "right mouse" );
489 else if( button == SDL_BUTTON_MIDDLE )
490 vg_strcat( str, special_glyphs? "\x9c": "middle mouse" );
491 else{
492 vg_strcat( str, "mouse button #" );
493 vg_strcati32( str, button );
494 }
495 }
496
497 /*
498 * Cat string represeinting single axis
499 */
500 void vg_joy_axis_string( vg_str *str, SDL_GameControllerAxis axis,
501 int special_glyphs )
502 {
503 if( axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT )
504 vg_strcat( str, special_glyphs?"\x8f":"left trigger" );
505 else if( axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT )
506 vg_strcat( str, special_glyphs?"\x90":"right trigger" );
507 else if( axis == SDL_CONTROLLER_AXIS_LEFTX )
508 vg_strcat( str, special_glyphs?"\x88":"left stick horizontal" );
509 else if( axis == SDL_CONTROLLER_AXIS_LEFTY )
510 vg_strcat( str, special_glyphs?"\x89":"left stick vertical" );
511 else if( axis == SDL_CONTROLLER_AXIS_RIGHTX )
512 vg_strcat( str, special_glyphs?"\x8c":"right stick horizontal" );
513 else if( axis == SDL_CONTROLLER_AXIS_RIGHTY )
514 vg_strcat( str, special_glyphs?"\x8d":"right stick vertical" );
515 else{
516 vg_strcat( str, "axis " );
517 vg_strcati32( str, axis );
518 }
519 }
520
521 /*
522 * Cat string represeinting whole joystick
523 */
524 void vg_joy_string( vg_str *str, vg_input_op op, int special_glyphs )
525 {
526 if( op == vg_joy_ls )
527 vg_strcat( str, special_glyphs? "\x87": "left stick" );
528 else
529 vg_strcat( str, special_glyphs? "\x8b": "right stick" );
530 }
531
532 /*
533 * Convert an input program into a readable string
534 */
535 void vg_input_string( vg_str *str, vg_input_op *ops, int glyphs )
536 {
537 u32 pc = 0;
538 int applicable = 0, visible = 1;
539
540 next_code:;
541 vg_input_op op = ops[ pc ++ ];
542
543 if( (op == vg_keyboard) || (op == vg_mouse) ){
544 if( (vg_input.display_input_method == k_input_method_kbm) && visible ){
545 applicable = 1;
546
547 if( op == vg_keyboard )
548 vg_keyboard_key_string( str, ops[pc], glyphs );
549 else
550 vg_mouse_button_string( str, ops[pc], glyphs );
551 }
552 else applicable = 0;
553 pc ++;
554 }
555 else if( (op == vg_joy_button) || (op == vg_joy_axis) ){
556 if( (vg_input.display_input_method == k_input_method_controller)
557 && visible ){
558 applicable = 1;
559
560 if( op == vg_joy_button )
561 vg_strcat( str, controller_button_str(ops[pc]) );
562 else
563 vg_joy_axis_string( str, ops[pc], glyphs );
564 }
565 else applicable = 0;
566 pc ++;
567 }
568 else if( (op == vg_joy_ls) || (op == vg_joy_rs) ){
569 if( (vg_input.display_input_method == k_input_method_controller)
570 && visible ){
571 applicable = 1;
572 vg_joy_string( str, op, glyphs );
573 }
574 else applicable = 0;
575 }
576 else if( op == vg_mode_mul ){
577 if( applicable && visible )
578 vg_strcat( str, " + " );
579 }
580 else if( op == vg_index )
581 pc ++;
582 else if( op == vg_gui_visible )
583 visible = ops[pc++];
584 else if( op == vg_end )
585 return;
586
587 goto next_code;
588 }