1 /* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */
9 f32 controller_deadzone
= 0.05f
;
11 struct vg_input vg_input
= {
12 .active_controller_index
= -2
15 u8
vg_getkey( SDL_Keycode kc
)
17 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
18 return vg_input
.sdl_keys
[sc
];
22 * takes SDL device index, and tries to open that on any free channel
24 static int vg_open_gamecontroller( Sint32 index
)
26 struct vg_controller
*controller
= NULL
;
28 const char *name
= SDL_GameControllerNameForIndex( index
);
29 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
31 if( instance_id
== -1 ){
32 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
36 for( int j
=0; j
<VG_MAX_CONTROLLERS
; j
++ ){
37 struct vg_controller
*esta
= &vg_input
.controllers
[j
];
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
);
48 controller
= &vg_input
.controllers
[j
];
55 controller
->handle
= SDL_GameControllerOpen( index
);
56 controller
->instance_id
= instance_id
;
58 if( controller
->handle
){
60 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
61 instance_id
, name
, vg_id
);
63 for( u32 i
=0; i
< SDL_CONTROLLER_BUTTON_MAX
; i
++ )
64 controller
->buttons
[i
] = 0;
66 for( u32 i
=0; i
< SDL_CONTROLLER_AXIS_MAX
; i
++ )
67 controller
->axises
[i
] = 0.0f
;
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
);
79 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
80 name
, SDL_GetError() );
85 vg_error( ". Too many controllers open! ignoring '%s'\n", name
);
90 void vg_input_device_event( SDL_Event
*ev
)
92 if( ev
->type
== SDL_CONTROLLERDEVICEADDED
){
93 int is_controller
= SDL_IsGameController( ev
->cdevice
.which
);
94 const char *name
= SDL_JoystickNameForIndex( ev
->cdevice
.which
);
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",
102 vg_open_gamecontroller( index
);
105 else if( ev
->type
== SDL_CONTROLLERDEVICEREMOVED
){
106 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
109 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
110 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
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;
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" );
131 void vg_input_controller_event( SDL_Event
*ev
)
133 if( ev
->type
== SDL_CONTROLLERAXISMOTION
){
134 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
135 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
137 if( ev
->caxis
.which
== esta
->instance_id
){
138 float value
= (float)ev
->caxis
.value
/ 32767.0f
;
140 if( ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_LEFTX
||
141 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_LEFTY
||
142 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_RIGHTX
||
143 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_RIGHTY
)
145 float deadz
= vg_clampf( controller_deadzone
, 0.0f
, 0.999f
),
146 high
= vg_maxf( 0.0f
, fabsf(value
) - deadz
);
148 value
= vg_signf(value
) * (high
/ (1.0f
-deadz
));
151 esta
->axises
[ ev
->caxis
.axis
] = value
;
156 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
){
157 struct vg_controller
*active
= NULL
;
159 if( vg_input
.active_controller_index
>= 0 )
160 active
= &vg_input
.controllers
[vg_input
.active_controller_index
];
162 if( !active
|| (ev
->cbutton
.which
!= active
->instance_id
) ){
164 vg_input
.active_controller_index
= -1;
165 vg_input
.display_input_method
= k_input_method_kbm
;
167 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
168 if( vg_input
.controllers
[i
].instance_id
== ev
->cbutton
.which
){
169 active
= &vg_input
.controllers
[i
];
170 vg_input
.active_controller_index
= i
;
171 vg_input
.display_input_type
=
172 SDL_GameControllerGetType(active
->handle
);
178 vg_info( "Switching active controller index to #%d\n",
179 vg_input
.active_controller_index
);
182 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
188 if( vg_input
.display_input_method
!= k_input_method_controller
){
189 vg_input
.display_input_method
= k_input_method_controller
;
190 vg_info( "display_input: k_input_method_controller\n" );
192 active
->buttons
[ ev
->cbutton
.button
] = 1;
195 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
){
196 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
197 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
199 if( ev
->cbutton
.which
== esta
->instance_id
){
200 esta
->buttons
[ ev
->cbutton
.button
] = 0;
207 void vg_process_inputs(void)
210 vg_input
.sdl_keys
= SDL_GetKeyboardState( &count
);
211 vg_input
.sdl_mouse
= SDL_GetMouseState(NULL
,NULL
);
213 if( vg_input
.display_input_method
!= k_input_method_kbm
)
215 /* check for giving keyboard priority */
216 for( int i
=0; i
<count
; i
++ )
218 if( vg_input
.sdl_keys
[i
] )
220 vg_input
.display_input_method
= k_input_method_kbm
;
221 vg_info( "display_input: k_input_method_kbm (keyboard %d)\n", i
);
226 /* check for giving mouse priority */
227 if( vg_input
.sdl_mouse
&
228 (SDL_BUTTON(SDL_BUTTON_LEFT
)|SDL_BUTTON(SDL_BUTTON_RIGHT
)|
229 SDL_BUTTON(SDL_BUTTON_MIDDLE
)) )
231 vg_input
.display_input_method
= k_input_method_kbm
;
232 vg_info( "display_input: k_input_method_kbm (mouse click)\n" );
235 vg_input
.hidden_mouse_travel
+= v2_length( vg
.mouse_delta
);
236 if( vg_input
.hidden_mouse_travel
> 64.0f
)
238 vg_input
.display_input_method
= k_input_method_kbm
;
239 vg_input
.hidden_mouse_travel
= 0.0f
;
240 vg_info( "display_input: k_input_method_kbm (mouse move)\n" );
244 vg_input
.hidden_mouse_travel
= 0.0f
;
247 void async_vg_input_init( void *payload
, u32 size
)
249 vg_info( "Checking for controllers\n" );
250 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
252 int joy_count
= SDL_NumJoysticks();
253 for( int i
=0; i
<joy_count
; i
++ ) {
254 const char *name
= SDL_JoystickNameForIndex( i
);
255 int is_controller
= SDL_IsGameController(i
);
257 vg_info( "%d: %s [controller: %d]\n", i
, name
, is_controller
);
260 vg_open_gamecontroller( i
);
265 void vg_input_init(void)
267 VG_VAR_F32( controller_deadzone
, flags
=VG_VAR_PERSISTENT
);
268 vg_async_call( async_vg_input_init
, NULL
, 0 );
271 void vg_input_free(void)
273 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
274 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
276 if( controller
->handle
){
277 SDL_GameControllerClose( controller
->handle
);
278 controller
->handle
= NULL
;
283 struct vg_controller
*vg_active_controller(void)
285 if( vg_input
.active_controller_index
>= 0 )
286 return &vg_input
.controllers
[vg_input
.active_controller_index
];
291 u8
vg_controller_button( SDL_GameControllerButton button
)
293 struct vg_controller
*c
= vg_active_controller();
294 if( c
) return c
->buttons
[ button
];
298 f32
vg_controller_axis( SDL_GameControllerAxis axis
)
300 struct vg_controller
*c
= vg_active_controller();
301 if( c
) return c
->axises
[ axis
];
305 static void vg_input_apply_to_u8( vg_input_op mode
, u8 data
, u8
*inout_result
){
306 if ( mode
== vg_mode_absmax
) *inout_result
|= data
;
307 else if( mode
== vg_mode_mul
) *inout_result
&= data
;
308 else vg_fatal_error( "mode not supported for destination type (%d)", mode
);
311 static void vg_input_apply_to_f32( vg_input_op mode
, f32 data
,
313 if ( mode
== vg_mode_absmax
){
314 if( fabsf(data
) > fabsf(*inout_result
) )
315 *inout_result
= data
;
317 else if( mode
== vg_mode_max
) *inout_result
= vg_maxf(*inout_result
,data
);
318 else if( mode
== vg_mode_mul
) *inout_result
*= (f32
)data
;
319 else if( mode
== vg_mode_sub
) *inout_result
-= (f32
)data
;
320 else if( mode
== vg_mode_add
) *inout_result
+= (f32
)data
;
321 else vg_fatal_error( "mode not supported for destination type (%d)", mode
);
325 * Run an input program. out_result must point to memory with sufficient
326 * storage respective to the size set by type.
328 void vg_exec_input_program( enum vg_input_type type
, vg_input_op
*ops
,
330 u8
*out_button
= NULL
;
333 if( type
== k_vg_input_type_button_u8
){
334 out_button
= out_result
;
337 else if( type
== k_vg_input_type_axis_f32
){
338 out_joy
= out_result
;
341 else if( type
== k_vg_input_type_joy_v2f
){
342 out_joy
= out_result
;
348 vg_input_op mode
= vg_mode_absmax
;
349 u32 pc
= 0, index
= 0;
352 vg_input_op op
= ops
[ pc
++ ];
354 if( (op
>= vg_mode_mul
) && (op
<= vg_mode_max
) )
356 else if( (op
== vg_keyboard
) || (op
== vg_mouse
) || (op
== vg_joy_button
) ){
359 if( op
== vg_keyboard
)
360 state
= vg_getkey(ops
[pc
++]);
361 else if( op
== vg_mouse
)
362 state
= (vg_input
.sdl_mouse
& SDL_BUTTON(ops
[pc
++]))?1:0;
364 state
= vg_controller_button(ops
[pc
++]);
366 if( type
== k_vg_input_type_button_u8
)
367 vg_input_apply_to_u8( mode
, state
, out_button
);
369 vg_input_apply_to_f32( mode
, (f32
)state
, &out_joy
[index
] );
371 else if( op
== vg_joy_axis
){
372 f32 state
= vg_controller_axis( ops
[pc
++] );
373 if( type
== k_vg_input_type_button_u8
)
374 vg_input_apply_to_u8( mode
, state
>0.5f
?1:0, out_button
);
376 vg_input_apply_to_f32( mode
, state
, &out_joy
[index
] );
378 else if( (op
== vg_joy_ls
) || (op
== vg_joy_rs
) ){
379 if( type
== k_vg_input_type_joy_v2f
){
380 vg_input_apply_to_f32( mode
,
381 vg_controller_axis( op
==vg_joy_ls
? SDL_CONTROLLER_AXIS_LEFTX
:
382 SDL_CONTROLLER_AXIS_RIGHTX
),
384 vg_input_apply_to_f32( mode
,
385 vg_controller_axis( op
==vg_joy_ls
? SDL_CONTROLLER_AXIS_LEFTY
:
386 SDL_CONTROLLER_AXIS_RIGHTY
),
390 else if( op
== vg_index
)
392 else if( op
== vg_end
)
394 else if( op
== vg_normalize
)
395 v2_normalize( out_joy
);
396 else if( op
== vg_gui_visible
)
399 vg_fatal_error( "unknown op\n" );
405 * Get vendor specific button glyphs based on SDL button ID
407 const char *controller_button_str( SDL_GameControllerButton button
)
409 static const char *controller_glyphs
[ SDL_CONTROLLER_BUTTON_MAX
][2] = {
410 /* xbox/generic playstation */
411 [ SDL_CONTROLLER_BUTTON_A
] = { KGRN
"\x06\x02\x85",KBLU
"\x06\x02\x82" },
412 [ SDL_CONTROLLER_BUTTON_B
] = { KRED
"\x06\x02\x86",KRED
"\x06\x02\x81" },
413 [ SDL_CONTROLLER_BUTTON_X
] = { KBLU
"\x06\x02\x83",KMAG
"\x06\x02\x7f" },
414 [ SDL_CONTROLLER_BUTTON_Y
] = { KYEL
"\x06\x02\x84",KGRN
"\x06\x02\x80" },
415 [ SDL_CONTROLLER_BUTTON_LEFTSTICK
] = { "\x87","\x87" },
416 [ SDL_CONTROLLER_BUTTON_RIGHTSTICK
] = { "\x8b","\x8b" },
417 [ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
] = { "\x91","\x91" },
418 [ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
]= { "\x92","\x92" },
419 [ SDL_CONTROLLER_BUTTON_DPAD_LEFT
] = { "\x93","\x93" },
420 [ SDL_CONTROLLER_BUTTON_DPAD_UP
] = { "\x94","\x94" },
421 [ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
] = { "\x95","\x95" },
422 [ SDL_CONTROLLER_BUTTON_DPAD_DOWN
] = { "\x96","\x96" },
423 [ SDL_CONTROLLER_BUTTON_GUIDE
] = { "\x91","\x91" },
426 if( vg_input
.display_input_type
== SDL_CONTROLLER_TYPE_PS3
||
427 vg_input
.display_input_type
== SDL_CONTROLLER_TYPE_PS4
||
428 vg_input
.display_input_type
== SDL_CONTROLLER_TYPE_PS5
)
430 return controller_glyphs
[ button
][ 1 ];
432 else if( vg_input
.display_input_type
==
433 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO
||
434 vg_input
.display_input_type
==
435 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT
||
436 vg_input
.display_input_type
==
437 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
||
438 vg_input
.display_input_type
==
439 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT
)
444 return controller_glyphs
[ button
][ 0 ];
448 * Cat keyboard key string. special_glyphs include SR glyphs
450 void vg_keyboard_key_string( vg_str
*str
, u32 key
, int special_glyphs
)
452 if( (key
>= SDLK_a
) && (key
<= SDLK_z
) ){
453 key
= (key
-SDLK_a
)+(u32
)'A';
454 vg_strcatch( str
, key
);
456 else if( (key
== SDLK_LSHIFT
) || (key
== SDLK_RSHIFT
) )
457 vg_strcat( str
, special_glyphs
? "\x9e": "shift" );
458 else if( (key
== SDLK_LCTRL
) || (key
== SDLK_RCTRL
) )
459 vg_strcat( str
, special_glyphs
? "\x9f": "ctrl" );
460 else if( (key
== SDLK_LALT
) || (key
== SDLK_RALT
) )
461 vg_strcat( str
, special_glyphs
? "\xa0": "alt" );
462 else if( key
== SDLK_SPACE
)
463 vg_strcat( str
, special_glyphs
? "\xa1": "space" );
464 else if( (key
== SDLK_RETURN
) || (key
== SDLK_RETURN2
) )
465 vg_strcat( str
, special_glyphs
? "\xa2": "return" );
466 else if( key
== SDLK_ESCAPE
)
467 vg_strcat( str
, special_glyphs
? "\xa3": "escape" );
468 else if( key
== SDLK_RIGHT
)
469 vg_strcat( str
, special_glyphs
? "\x95 ": "right" );
470 else if( key
== SDLK_LEFT
)
471 vg_strcat( str
, special_glyphs
? "\x93 ": "left" );
472 else if( key
== SDLK_UP
)
473 vg_strcat( str
, special_glyphs
? "\x94 ": "up" );
474 else if( key
== SDLK_DOWN
)
475 vg_strcat( str
, special_glyphs
? "\x96 ": "down" );
477 vg_strcat( str
, "keyboard key #" );
478 vg_strcati32( str
, key
);
483 * Cat mouse button string. special_glyphs include SR glyphs
485 void vg_mouse_button_string( vg_str
*str
, u32 button
, int special_glyphs
)
487 if ( button
== SDL_BUTTON_LEFT
)
488 vg_strcat( str
, special_glyphs
? "\x99": "left mouse" );
489 else if( button
== SDL_BUTTON_RIGHT
)
490 vg_strcat( str
, special_glyphs
? "\x9a": "right mouse" );
491 else if( button
== SDL_BUTTON_MIDDLE
)
492 vg_strcat( str
, special_glyphs
? "\x9c": "middle mouse" );
494 vg_strcat( str
, "mouse button #" );
495 vg_strcati32( str
, button
);
500 * Cat string represeinting single axis
502 void vg_joy_axis_string( vg_str
*str
, SDL_GameControllerAxis axis
,
505 if( axis
== SDL_CONTROLLER_AXIS_TRIGGERLEFT
)
506 vg_strcat( str
, special_glyphs
?"\x8f":"left trigger" );
507 else if( axis
== SDL_CONTROLLER_AXIS_TRIGGERRIGHT
)
508 vg_strcat( str
, special_glyphs
?"\x90":"right trigger" );
509 else if( axis
== SDL_CONTROLLER_AXIS_LEFTX
)
510 vg_strcat( str
, special_glyphs
?"\x88":"left stick horizontal" );
511 else if( axis
== SDL_CONTROLLER_AXIS_LEFTY
)
512 vg_strcat( str
, special_glyphs
?"\x89":"left stick vertical" );
513 else if( axis
== SDL_CONTROLLER_AXIS_RIGHTX
)
514 vg_strcat( str
, special_glyphs
?"\x8c":"right stick horizontal" );
515 else if( axis
== SDL_CONTROLLER_AXIS_RIGHTY
)
516 vg_strcat( str
, special_glyphs
?"\x8d":"right stick vertical" );
518 vg_strcat( str
, "axis " );
519 vg_strcati32( str
, axis
);
524 * Cat string represeinting whole joystick
526 void vg_joy_string( vg_str
*str
, vg_input_op op
, int special_glyphs
)
528 if( op
== vg_joy_ls
)
529 vg_strcat( str
, special_glyphs
? "\x87": "left stick" );
531 vg_strcat( str
, special_glyphs
? "\x8b": "right stick" );
535 * Convert an input program into a readable string
537 void vg_input_string( vg_str
*str
, vg_input_op
*ops
, int glyphs
)
540 int applicable
= 0, visible
= 1;
543 vg_input_op op
= ops
[ pc
++ ];
545 if( (op
== vg_keyboard
) || (op
== vg_mouse
) ){
546 if( (vg_input
.display_input_method
== k_input_method_kbm
) && visible
){
549 if( op
== vg_keyboard
)
550 vg_keyboard_key_string( str
, ops
[pc
], glyphs
);
552 vg_mouse_button_string( str
, ops
[pc
], glyphs
);
557 else if( (op
== vg_joy_button
) || (op
== vg_joy_axis
) ){
558 if( (vg_input
.display_input_method
== k_input_method_controller
)
562 if( op
== vg_joy_button
)
563 vg_strcat( str
, controller_button_str(ops
[pc
]) );
565 vg_joy_axis_string( str
, ops
[pc
], glyphs
);
570 else if( (op
== vg_joy_ls
) || (op
== vg_joy_rs
) ){
571 if( (vg_input
.display_input_method
== k_input_method_controller
)
574 vg_joy_string( str
, op
, glyphs
);
578 else if( op
== vg_mode_mul
){
579 if( applicable
&& visible
)
580 vg_strcat( str
, " + " );
582 else if( op
== vg_index
)
584 else if( op
== vg_gui_visible
)
586 else if( op
== vg_end
)