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 static void vg_input_set_active_controller( int index
, const char *why
)
133 if( vg_input
.active_controller_index
!= index
)
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
);
141 if( vg_input
.display_input_method
!= k_input_method_controller
)
143 vg_input
.display_input_method
= k_input_method_controller
;
144 vg_info( "Switching input method to controller. (%s)\n", why
);
148 void vg_input_controller_event( SDL_Event
*ev
)
150 if( ev
->type
== SDL_CONTROLLERAXISMOTION
)
152 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ )
154 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
156 if( ev
->caxis
.which
== esta
->instance_id
)
158 float value
= (float)ev
->caxis
.value
/ 32767.0f
;
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
)
165 float deadz
= vg_clampf( controller_deadzone
, 0.0f
, 0.999f
),
166 high
= vg_maxf( 0.0f
, fabsf(value
) - deadz
);
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|" );
173 esta
->axises
[ ev
->caxis
.axis
] = value
;
178 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
)
180 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ )
182 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
183 if( esta
->instance_id
== ev
->cbutton
.which
)
185 vg_input_set_active_controller( i
, "Button press" );
186 esta
->buttons
[ ev
->cbutton
.button
] = 1;
191 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
)
193 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ )
195 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
196 if( ev
->cbutton
.which
== esta
->instance_id
)
198 esta
->buttons
[ ev
->cbutton
.button
] = 0;
205 void vg_process_inputs(void)
208 vg_input
.sdl_keys
= SDL_GetKeyboardState( &count
);
209 vg_input
.sdl_mouse
= SDL_GetMouseState(NULL
,NULL
);
211 if( vg_input
.display_input_method
!= k_input_method_kbm
)
213 /* check for giving keyboard priority */
214 for( int i
=0; i
<count
; i
++ )
216 if( vg_input
.sdl_keys
[i
] )
218 vg_input
.display_input_method
= k_input_method_kbm
;
219 vg_info( "display_input: k_input_method_kbm (keyboard %d)\n", i
);
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
)) )
229 vg_input
.display_input_method
= k_input_method_kbm
;
230 vg_info( "display_input: k_input_method_kbm (mouse click)\n" );
233 vg_input
.hidden_mouse_travel
+= v2_length( vg
.mouse_delta
);
234 if( vg_input
.hidden_mouse_travel
> 64.0f
)
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" );
242 vg_input
.hidden_mouse_travel
= 0.0f
;
245 void async_vg_input_init( void *payload
, u32 size
)
247 vg_info( "Checking for controllers\n" );
248 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
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
);
255 vg_info( "%d: %s [controller: %d]\n", i
, name
, is_controller
);
258 vg_open_gamecontroller( i
);
263 void vg_input_init(void)
265 VG_VAR_F32( controller_deadzone
, flags
=VG_VAR_PERSISTENT
);
266 vg_async_call( async_vg_input_init
, NULL
, 0 );
269 void vg_input_free(void)
271 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
272 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
274 if( controller
->handle
){
275 SDL_GameControllerClose( controller
->handle
);
276 controller
->handle
= NULL
;
281 struct vg_controller
*vg_active_controller(void)
283 if( vg_input
.active_controller_index
>= 0 )
284 return &vg_input
.controllers
[vg_input
.active_controller_index
];
289 u8
vg_controller_button( SDL_GameControllerButton button
)
291 struct vg_controller
*c
= vg_active_controller();
292 if( c
) return c
->buttons
[ button
];
296 f32
vg_controller_axis( SDL_GameControllerAxis axis
)
298 struct vg_controller
*c
= vg_active_controller();
299 if( c
) return c
->axises
[ axis
];
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
);
309 static void vg_input_apply_to_f32( vg_input_op mode
, f32 data
,
311 if ( mode
== vg_mode_absmax
){
312 if( fabsf(data
) > fabsf(*inout_result
) )
313 *inout_result
= data
;
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
);
323 * Run an input program. out_result must point to memory with sufficient
324 * storage respective to the size set by type.
326 void vg_exec_input_program( enum vg_input_type type
, vg_input_op
*ops
,
328 u8
*out_button
= NULL
;
331 if( type
== k_vg_input_type_button_u8
){
332 out_button
= out_result
;
335 else if( type
== k_vg_input_type_axis_f32
){
336 out_joy
= out_result
;
339 else if( type
== k_vg_input_type_joy_v2f
){
340 out_joy
= out_result
;
346 vg_input_op mode
= vg_mode_absmax
;
347 u32 pc
= 0, index
= 0;
350 vg_input_op op
= ops
[ pc
++ ];
352 if( (op
>= vg_mode_mul
) && (op
<= vg_mode_max
) )
354 else if( (op
== vg_keyboard
) || (op
== vg_mouse
) || (op
== vg_joy_button
) ){
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;
362 state
= vg_controller_button(ops
[pc
++]);
364 if( type
== k_vg_input_type_button_u8
)
365 vg_input_apply_to_u8( mode
, state
, out_button
);
367 vg_input_apply_to_f32( mode
, (f32
)state
, &out_joy
[index
] );
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
);
374 vg_input_apply_to_f32( mode
, state
, &out_joy
[index
] );
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
),
382 vg_input_apply_to_f32( mode
,
383 vg_controller_axis( op
==vg_joy_ls
? SDL_CONTROLLER_AXIS_LEFTY
:
384 SDL_CONTROLLER_AXIS_RIGHTY
),
388 else if( op
== vg_index
)
390 else if( op
== vg_end
)
392 else if( op
== vg_normalize
)
393 v2_normalize( out_joy
);
394 else if( op
== vg_gui_visible
)
397 vg_fatal_error( "unknown op\n" );
403 * Get vendor specific button glyphs based on SDL button ID
405 const char *controller_button_str( SDL_GameControllerButton button
)
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" },
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
)
428 return controller_glyphs
[ button
][ 1 ];
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
)
442 return controller_glyphs
[ button
][ 0 ];
446 * Cat keyboard key string. special_glyphs include SR glyphs
448 void vg_keyboard_key_string( vg_str
*str
, u32 key
, int special_glyphs
)
450 if( (key
>= SDLK_a
) && (key
<= SDLK_z
) ){
451 key
= (key
-SDLK_a
)+(u32
)'A';
452 vg_strcatch( str
, key
);
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" );
475 vg_strcat( str
, "keyboard key #" );
476 vg_strcati32( str
, key
);
481 * Cat mouse button string. special_glyphs include SR glyphs
483 void vg_mouse_button_string( vg_str
*str
, u32 button
, int special_glyphs
)
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" );
492 vg_strcat( str
, "mouse button #" );
493 vg_strcati32( str
, button
);
498 * Cat string represeinting single axis
500 void vg_joy_axis_string( vg_str
*str
, SDL_GameControllerAxis axis
,
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" );
516 vg_strcat( str
, "axis " );
517 vg_strcati32( str
, axis
);
522 * Cat string represeinting whole joystick
524 void vg_joy_string( vg_str
*str
, vg_input_op op
, int special_glyphs
)
526 if( op
== vg_joy_ls
)
527 vg_strcat( str
, special_glyphs
? "\x87": "left stick" );
529 vg_strcat( str
, special_glyphs
? "\x8b": "right stick" );
533 * Convert an input program into a readable string
535 void vg_input_string( vg_str
*str
, vg_input_op
*ops
, int glyphs
)
538 int applicable
= 0, visible
= 1;
541 vg_input_op op
= ops
[ pc
++ ];
543 if( (op
== vg_keyboard
) || (op
== vg_mouse
) ){
544 if( (vg_input
.display_input_method
== k_input_method_kbm
) && visible
){
547 if( op
== vg_keyboard
)
548 vg_keyboard_key_string( str
, ops
[pc
], glyphs
);
550 vg_mouse_button_string( str
, ops
[pc
], glyphs
);
555 else if( (op
== vg_joy_button
) || (op
== vg_joy_axis
) ){
556 if( (vg_input
.display_input_method
== k_input_method_controller
)
560 if( op
== vg_joy_button
)
561 vg_strcat( str
, controller_button_str(ops
[pc
]) );
563 vg_joy_axis_string( str
, ops
[pc
], glyphs
);
568 else if( (op
== vg_joy_ls
) || (op
== vg_joy_rs
) ){
569 if( (vg_input
.display_input_method
== k_input_method_controller
)
572 vg_joy_string( str
, op
, glyphs
);
576 else if( op
== vg_mode_mul
){
577 if( applicable
&& visible
)
578 vg_strcat( str
, " + " );
580 else if( op
== vg_index
)
582 else if( op
== vg_gui_visible
)
584 else if( op
== vg_end
)