1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
6 #include "vg/vg_loader.h"
8 #define VG_MAX_CONTROLLERS 4
10 static float controller_deadzone
= 0.05f
;
16 SDL_GameController
*handle
; /* handle for controller. NULL if unused */
17 SDL_JoystickID instance_id
; /* uid used in events */
19 float axises
[ SDL_CONTROLLER_AXIS_MAX
];
20 u32 buttons
[ SDL_CONTROLLER_BUTTON_MAX
];
24 int active_controller_index
; /* most recent controller (by button press)
25 will be -1 if no controllers active */
27 /* what the user is currently using. the keyboard and controller are still
28 * active simultaneously, but this reflects what the UI should show */
31 k_input_method_controller
34 SDL_GameControllerType display_input_type
;
36 static vg_input
= { .active_controller_index
= -2 };
38 static u8
vg_getkey( SDL_Keycode kc
)
40 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
41 return vg_input
.sdl_keys
[sc
];
45 * takes SDL device index, and tries to open that on any free channel
47 static int vg_open_gamecontroller( Sint32 index
)
49 struct vg_controller
*controller
= NULL
;
51 const char *name
= SDL_GameControllerNameForIndex( index
);
52 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
54 if( instance_id
== -1 ){
55 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
59 for( int j
=0; j
<VG_MAX_CONTROLLERS
; j
++ ){
60 struct vg_controller
*esta
= &vg_input
.controllers
[j
];
63 if( esta
->instance_id
== instance_id
){
64 vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n",
65 esta
->instance_id
, j
);
71 controller
= &vg_input
.controllers
[j
];
78 controller
->handle
= SDL_GameControllerOpen( index
);
79 controller
->instance_id
= instance_id
;
81 if( controller
->handle
){
83 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
84 instance_id
, name
, vg_id
);
86 for( u32 i
=0; i
< SDL_CONTROLLER_BUTTON_MAX
; i
++ )
87 controller
->buttons
[i
] = 0;
89 for( u32 i
=0; i
< SDL_CONTROLLER_AXIS_MAX
; i
++ )
90 controller
->axises
[i
] = 0.0f
;
92 controller
->axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
93 controller
->axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
95 if( vg_input
.active_controller_index
== -2 ){
96 vg_input
.active_controller_index
= vg_id
;
97 vg_input
.display_input_method
= k_input_method_controller
;
98 vg_input
.display_input_type
=
99 SDL_GameControllerGetType( controller
->handle
);
105 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
106 name
, SDL_GetError() );
111 vg_error( ". Too many controllers open! ignoring '%s'\n", name
);
116 static void vg_input_device_event( SDL_Event
*ev
)
118 if( ev
->type
== SDL_CONTROLLERDEVICEADDED
){
119 int is_controller
= SDL_IsGameController( ev
->cdevice
.which
);
120 const char *name
= SDL_JoystickNameForIndex( ev
->cdevice
.which
);
122 Sint32 index
= ev
->cdevice
.which
;
123 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
124 vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n",
128 vg_open_gamecontroller( index
);
131 else if( ev
->type
== SDL_CONTROLLERDEVICEREMOVED
){
132 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
135 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
136 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
138 if( controller
->handle
){
139 if( controller
->instance_id
== ev
->cdevice
.which
){
140 vg_info( " . closing controller at index #%d\n", i
);
141 SDL_GameControllerClose( controller
->handle
);
142 controller
->handle
= NULL
;
143 controller
->instance_id
= -1;
145 if( vg_input
.active_controller_index
== i
){
146 vg_input
.active_controller_index
= -1;
147 vg_input
.display_input_method
= k_input_method_kbm
;
148 vg_info( "display_input: k_input_method_kbm\n" );
157 static void vg_input_controller_event( SDL_Event
*ev
)
159 if( ev
->type
== SDL_CONTROLLERAXISMOTION
){
160 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
161 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
163 if( ev
->caxis
.which
== esta
->instance_id
){
164 float value
= (float)ev
->caxis
.value
/ 32767.0f
;
166 if( ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_LEFTX
||
167 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_LEFTY
||
168 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_RIGHTX
||
169 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_RIGHTY
)
171 float deadz
= vg_clampf( controller_deadzone
, 0.0f
, 0.999f
),
172 high
= vg_maxf( 0.0f
, fabsf(value
) - deadz
);
174 value
= vg_signf(value
) * (high
/ (1.0f
-deadz
));
177 esta
->axises
[ ev
->caxis
.axis
] = value
;
182 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
){
183 struct vg_controller
*active
= NULL
;
185 if( vg_input
.active_controller_index
>= 0 )
186 active
= &vg_input
.controllers
[vg_input
.active_controller_index
];
188 if( !active
|| (ev
->cbutton
.which
!= active
->instance_id
) ){
190 vg_input
.active_controller_index
= -1;
191 vg_input
.display_input_method
= k_input_method_kbm
;
193 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
194 if( vg_input
.controllers
[i
].instance_id
== ev
->cbutton
.which
){
195 active
= &vg_input
.controllers
[i
];
196 vg_input
.active_controller_index
= i
;
197 vg_input
.display_input_type
=
198 SDL_GameControllerGetType(active
->handle
);
204 vg_info( "Switching active controller index to #%d\n",
205 vg_input
.active_controller_index
);
208 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
214 if( vg_input
.display_input_method
!= k_input_method_controller
){
215 vg_input
.display_input_method
= k_input_method_controller
;
216 vg_info( "display_input: k_input_method_controller\n" );
218 active
->buttons
[ ev
->cbutton
.button
] = 1;
221 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
){
222 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
223 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
225 if( ev
->cbutton
.which
== esta
->instance_id
){
226 esta
->buttons
[ ev
->cbutton
.button
] = 0;
233 static void vg_process_inputs(void)
236 vg_input
.sdl_keys
= SDL_GetKeyboardState( &count
);
238 if( vg_input
.display_input_method
!= k_input_method_kbm
){
239 /* check for giving keyboard priority */
240 for( int i
=0; i
<count
; i
++ ){
241 if( vg_input
.sdl_keys
[i
] ){
242 vg_input
.display_input_method
= k_input_method_kbm
;
243 vg_info( "display_input: k_input_method_kbm (keyboard %d)\n", i
);
248 /* check for giving mouse priority */
249 if( SDL_GetMouseState(NULL
,NULL
) &
250 (SDL_BUTTON(SDL_BUTTON_LEFT
)|SDL_BUTTON(SDL_BUTTON_RIGHT
)|
251 SDL_BUTTON(SDL_BUTTON_MIDDLE
)) )
253 vg_input
.display_input_method
= k_input_method_kbm
;
254 vg_info( "display_input: k_input_method_kbm (mouse)\n" );
259 static void async_vg_input_init( void *payload
, u32 size
)
261 VG_VAR_F32( controller_deadzone
, flags
=VG_VAR_PERSISTENT
);
263 vg_info( "Checking for controllers\n" );
264 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
266 int joy_count
= SDL_NumJoysticks();
267 for( int i
=0; i
<joy_count
; i
++ ) {
268 const char *name
= SDL_JoystickNameForIndex( i
);
269 int is_controller
= SDL_IsGameController(i
);
271 vg_info( "%d: %s [controller: %d]\n", i
, name
, is_controller
);
274 vg_open_gamecontroller( i
);
279 static void vg_input_init(void)
281 vg_async_call( async_vg_input_init
, NULL
, 0 );
284 static void vg_input_free(void)
286 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
287 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
289 if( controller
->handle
){
290 SDL_GameControllerClose( controller
->handle
);
291 controller
->handle
= NULL
;