1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
6 #include "vg/vg_loader.h"
8 #define VG_MAX_CONTROLLERS 4
10 VG_STATIC
float controller_deadzone
= 0.05f
;
17 SDL_GameController
*handle
; /* handle for controller. NULL if unused */
18 SDL_JoystickID instance_id
; /* uid used in events */
20 float axises
[ SDL_CONTROLLER_AXIS_MAX
];
21 u32 buttons
[ SDL_CONTROLLER_BUTTON_MAX
];
25 int active_controller_index
; /* most recent controller (by button press)
26 will be -1 if no controllers active */
28 /* what the user is currently using. the keyboard and controller are still
29 * active simultaneously, but this reflects what the UI should show */
32 k_input_method_controller
35 SDL_GameControllerType display_input_type
;
37 static vg_input
= { .active_controller_index
= -2 };
39 VG_STATIC u8
vg_getkey( SDL_Keycode kc
)
41 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
42 return vg_input
.sdl_keys
[sc
];
46 * takes SDL device index, and tries to open that on any free channel
48 VG_STATIC
int vg_open_gamecontroller( Sint32 index
)
50 struct vg_controller
*controller
= NULL
;
52 const char *name
= SDL_GameControllerNameForIndex( index
);
53 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
55 if( instance_id
== -1 ){
56 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
60 for( int j
=0; j
<VG_MAX_CONTROLLERS
; j
++ ){
61 struct vg_controller
*esta
= &vg_input
.controllers
[j
];
64 if( esta
->instance_id
== instance_id
){
65 vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n",
66 esta
->instance_id
, j
);
72 controller
= &vg_input
.controllers
[j
];
79 controller
->handle
= SDL_GameControllerOpen( index
);
80 controller
->instance_id
= instance_id
;
82 if( controller
->handle
){
84 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
85 instance_id
, name
, vg_id
);
87 for( u32 i
=0; i
< SDL_CONTROLLER_BUTTON_MAX
; i
++ )
88 controller
->buttons
[i
] = 0;
90 for( u32 i
=0; i
< SDL_CONTROLLER_AXIS_MAX
; i
++ )
91 controller
->axises
[i
] = 0.0f
;
93 controller
->axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
94 controller
->axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
96 if( vg_input
.active_controller_index
== -2 ){
97 vg_input
.active_controller_index
= vg_id
;
98 vg_input
.display_input_method
= k_input_method_controller
;
99 vg_input
.display_input_type
=
100 SDL_GameControllerGetType( controller
->handle
);
106 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
107 name
, SDL_GetError() );
112 vg_error( ". Too many controllers open! ignoring '%s'\n", name
);
117 VG_STATIC
void vg_input_device_event( SDL_Event
*ev
)
119 if( ev
->type
== SDL_CONTROLLERDEVICEADDED
){
120 int is_controller
= SDL_IsGameController( ev
->cdevice
.which
);
121 const char *name
= SDL_JoystickNameForIndex( ev
->cdevice
.which
);
123 Sint32 index
= ev
->cdevice
.which
;
124 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
125 vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n",
129 vg_open_gamecontroller( index
);
132 else if( ev
->type
== SDL_CONTROLLERDEVICEREMOVED
){
133 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
136 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
137 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
139 if( controller
->handle
){
140 if( controller
->instance_id
== ev
->cdevice
.which
){
141 vg_info( " . closing controller at index #%d\n", i
);
142 SDL_GameControllerClose( controller
->handle
);
143 controller
->handle
= NULL
;
144 controller
->instance_id
= -1;
146 if( vg_input
.active_controller_index
== i
){
147 vg_input
.active_controller_index
= -1;
148 vg_input
.display_input_method
= k_input_method_kbm
;
149 vg_info( "display_input: k_input_method_kbm\n" );
158 VG_STATIC
void vg_input_controller_event( SDL_Event
*ev
)
160 if( ev
->type
== SDL_CONTROLLERAXISMOTION
){
161 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
162 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
164 if( ev
->caxis
.which
== esta
->instance_id
){
165 float value
= (float)ev
->caxis
.value
/ 32767.0f
;
167 if( ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_LEFTX
||
168 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_LEFTY
||
169 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_RIGHTX
||
170 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_RIGHTY
)
172 float deadz
= vg_clampf( controller_deadzone
, 0.0f
, 0.999f
),
173 high
= vg_maxf( 0.0f
, fabsf(value
) - deadz
);
175 value
= vg_signf(value
) * (high
/ (1.0f
-deadz
));
178 esta
->axises
[ ev
->caxis
.axis
] = value
;
183 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
){
184 struct vg_controller
*active
= NULL
;
186 if( vg_input
.active_controller_index
>= 0 )
187 active
= &vg_input
.controllers
[vg_input
.active_controller_index
];
189 if( !active
|| (ev
->cbutton
.which
!= active
->instance_id
) ){
191 vg_input
.active_controller_index
= -1;
192 vg_input
.display_input_method
= k_input_method_kbm
;
194 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
195 if( vg_input
.controllers
[i
].instance_id
== ev
->cbutton
.which
){
196 active
= &vg_input
.controllers
[i
];
197 vg_input
.active_controller_index
= i
;
198 vg_input
.display_input_type
=
199 SDL_GameControllerGetType(active
->handle
);
205 vg_info( "Switching active controller index to #%d\n",
206 vg_input
.active_controller_index
);
209 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
215 if( vg_input
.display_input_method
!= k_input_method_controller
){
216 vg_input
.display_input_method
= k_input_method_controller
;
217 vg_info( "display_input: k_input_method_controller\n" );
219 active
->buttons
[ ev
->cbutton
.button
] = 1;
222 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
){
223 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
224 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
226 if( ev
->cbutton
.which
== esta
->instance_id
){
227 esta
->buttons
[ ev
->cbutton
.button
] = 0;
234 VG_STATIC
void vg_process_inputs(void)
237 vg_input
.sdl_keys
= SDL_GetKeyboardState( &count
);
239 if( vg_input
.display_input_method
!= k_input_method_kbm
){
240 /* check for giving keyboard priority */
241 for( int i
=0; i
<count
; i
++ ){
242 if( vg_input
.sdl_keys
[i
] ){
243 vg_input
.display_input_method
= k_input_method_kbm
;
244 vg_info( "display_input: k_input_method_kbm (keyboard %d)\n", i
);
249 /* check for giving mouse priority */
250 if( SDL_GetMouseState(NULL
,NULL
) &
251 (SDL_BUTTON(SDL_BUTTON_LEFT
)|SDL_BUTTON(SDL_BUTTON_RIGHT
)|
252 SDL_BUTTON(SDL_BUTTON_MIDDLE
)) )
254 vg_input
.display_input_method
= k_input_method_kbm
;
255 vg_info( "display_input: k_input_method_kbm (mouse)\n" );
260 VG_STATIC
void async_vg_input_init( void *payload
, u32 size
)
262 VG_VAR_F32( controller_deadzone
, flags
=VG_VAR_PERSISTENT
);
264 vg_info( "Checking for controllers\n" );
265 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
267 int joy_count
= SDL_NumJoysticks();
268 for( int i
=0; i
<joy_count
; i
++ ) {
269 const char *name
= SDL_JoystickNameForIndex( i
);
270 int is_controller
= SDL_IsGameController(i
);
272 vg_info( "%d: %s [controller: %d]\n", i
, name
, is_controller
);
275 vg_open_gamecontroller( i
);
280 VG_STATIC
void vg_input_init(void)
282 vg_async_call( async_vg_input_init
, NULL
, 0 );
285 VG_STATIC
void vg_input_free(void)
287 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
288 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
290 if( controller
->handle
){
291 SDL_GameControllerClose( controller
->handle
);
292 controller
->handle
= NULL
;