fixing input AGAIN
[vg.git] / vg_input.h
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
2 #ifndef VG_INPUT_H
3 #define VG_INPUT_H
4
5 #include "common.h"
6 #include "vg/vg_loader.h"
7
8 #define VG_MAX_CONTROLLERS 4
9
10 VG_STATIC float controller_deadzone = 0.05f;
11
12 struct
13 {
14 const u8 *sdl_keys;
15
16 struct vg_controller{
17 SDL_GameController *handle; /* handle for controller. NULL if unused */
18 SDL_JoystickID instance_id; /* uid used in events */
19
20 float axises[ SDL_CONTROLLER_AXIS_MAX ];
21 u32 buttons[ SDL_CONTROLLER_BUTTON_MAX ];
22 }
23 controllers[4];
24
25 int active_controller_index; /* most recent controller (by button press)
26 will be -1 if no controllers active */
27
28 /* what the user is currently using. the keyboard and controller are still
29 * active simultaneously, but this reflects what the UI should show */
30 enum input_method{
31 k_input_method_kbm,
32 k_input_method_controller
33 }
34 display_input_method;
35 SDL_GameControllerType display_input_type;
36 }
37 static vg_input = { .active_controller_index = -2 };
38
39 VG_STATIC u8 vg_getkey( SDL_Keycode kc )
40 {
41 SDL_Scancode sc = SDL_GetScancodeFromKey( kc );
42 return vg_input.sdl_keys[sc];
43 }
44
45 /*
46 * takes SDL device index, and tries to open that on any free channel
47 */
48 VG_STATIC int vg_open_gamecontroller( Sint32 index )
49 {
50 struct vg_controller *controller = NULL;
51 int vg_id = 0;
52 const char *name = SDL_GameControllerNameForIndex( index );
53 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
54
55 if( instance_id == -1 ){
56 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
57 return -1;
58 }
59
60 for( int j=0; j<VG_MAX_CONTROLLERS; j++ ){
61 struct vg_controller *esta = &vg_input.controllers[j];
62
63 if( esta->handle ){
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 );
67 return -1;
68 }
69 }
70 else{
71 if( !controller ){
72 controller = &vg_input.controllers[j];
73 vg_id = j;
74 }
75 }
76 }
77
78 if( controller ){
79 controller->handle = SDL_GameControllerOpen( index );
80 controller->instance_id = instance_id;
81
82 if( controller->handle ){
83 vg_success(
84 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
85 instance_id, name, vg_id );
86
87 for( u32 i=0; i< SDL_CONTROLLER_BUTTON_MAX; i++ )
88 controller->buttons[i] = 0;
89
90 for( u32 i=0; i< SDL_CONTROLLER_AXIS_MAX; i++ )
91 controller->axises[i] = 0.0f;
92
93 controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f;
94 controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f;
95
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 );
101 }
102
103 return vg_id;
104 }
105 else{
106 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
107 name, SDL_GetError() );
108 return -1;
109 }
110 }
111 else{
112 vg_error( ". Too many controllers open! ignoring '%s'\n", name );
113 return -1;
114 }
115 }
116
117 VG_STATIC void vg_input_device_event( SDL_Event *ev )
118 {
119 if( ev->type == SDL_CONTROLLERDEVICEADDED ){
120 int is_controller = SDL_IsGameController( ev->cdevice.which );
121 const char *name = SDL_JoystickNameForIndex( ev->cdevice.which );
122
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",
126 index, name );
127
128 if( is_controller ){
129 vg_open_gamecontroller( index );
130 }
131 }
132 else if( ev->type == SDL_CONTROLLERDEVICEREMOVED ){
133 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
134 ev->cdevice.which );
135
136 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
137 struct vg_controller *controller = &vg_input.controllers[i];
138
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;
145
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" );
150 }
151 break;
152 }
153 }
154 }
155 }
156 }
157
158 VG_STATIC void vg_input_controller_event( SDL_Event *ev )
159 {
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];
163
164 if( ev->caxis.which == esta->instance_id ){
165 float value = (float)ev->caxis.value / 32767.0f;
166
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 )
171 {
172 float deadz = vg_clampf( controller_deadzone, 0.0f, 0.999f ),
173 high = vg_maxf( 0.0f, fabsf(value) - deadz );
174
175 value = vg_signf(value) * (high / (1.0f-deadz));
176 }
177
178 esta->axises[ ev->caxis.axis ] = value;
179 break;
180 }
181 }
182 }
183 else if( ev->type == SDL_CONTROLLERBUTTONDOWN ){
184 struct vg_controller *active = NULL;
185
186 if( vg_input.active_controller_index >= 0 )
187 active = &vg_input.controllers[vg_input.active_controller_index];
188
189 if( !active || (ev->cbutton.which != active->instance_id) ){
190 active = NULL;
191 vg_input.active_controller_index = -1;
192 vg_input.display_input_method = k_input_method_kbm;
193
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);
200 break;
201 }
202 }
203
204 if( active ){
205 vg_info( "Switching active controller index to #%d\n",
206 vg_input.active_controller_index );
207 }
208 else{
209 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
210 ev->cbutton.which );
211 }
212 }
213
214 if( active ){
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" );
218 }
219 active->buttons[ ev->cbutton.button ] = 1;
220 }
221 }
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];
225
226 if( ev->cbutton.which == esta->instance_id ){
227 esta->buttons[ ev->cbutton.button ] = 0;
228 break;
229 }
230 }
231 }
232 }
233
234 VG_STATIC void vg_process_inputs(void)
235 {
236 int count;
237 vg_input.sdl_keys = SDL_GetKeyboardState( &count );
238
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 );
245 break;
246 }
247 }
248
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)) )
253 {
254 vg_input.display_input_method = k_input_method_kbm;
255 vg_info( "display_input: k_input_method_kbm (mouse)\n" );
256 }
257 }
258 }
259
260 VG_STATIC void async_vg_input_init( void *payload, u32 size )
261 {
262 VG_VAR_F32( controller_deadzone, flags=VG_VAR_PERSISTENT );
263
264 vg_info( "Checking for controllers\n" );
265 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
266
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);
271
272 vg_info( "%d: %s [controller: %d]\n", i, name, is_controller );
273
274 if( is_controller ){
275 vg_open_gamecontroller( i );
276 }
277 }
278 }
279
280 VG_STATIC void vg_input_init(void)
281 {
282 vg_async_call( async_vg_input_init, NULL, 0 );
283 }
284
285 VG_STATIC void vg_input_free(void)
286 {
287 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
288 struct vg_controller *controller = &vg_input.controllers[i];
289
290 if( controller->handle ){
291 SDL_GameControllerClose( controller->handle );
292 controller->handle = NULL;
293 }
294 }
295 }
296
297 #endif