1 /**********************************************************************
2 *   This file is part of Search and Rescue II (SaR2).                 *
3 *                                                                     *
4 *   SaR2 is free software: you can redistribute it and/or modify      *
5 *   it under the terms of the GNU General Public License v.2 as       *
6 *   published by the Free Software Foundation.                        *
7 *                                                                     *
8 *   SaR2 is distributed in the hope that it will be useful, but       *
9 *   WITHOUT ANY WARRANTY; without even the implied warranty of        *
10 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See          *
11 *   the GNU General Public License for more details.                  *
12 *                                                                     *
13 *   You should have received a copy of the GNU General Public License *
14 *   along with SaR2.  If not, see <http://www.gnu.org/licenses/>.     *
15 ***********************************************************************/
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <SDL/SDL.h>
21 #include "gw.h"		/* Need to know about GW key codes */
22 #include "gctl.h"
23 
24 
25 static char *last_gctl_error = NULL;
26 
27 
28 char *GCtlGetError(void);
29 gctl_struct *GCtlNew(gctl_values_struct *v);
30 void GCtlUpdate(
31 	gctl_struct *gc,
32 	Boolean heading_has_nz,	/* Include heading pitch nullzone */
33 	Boolean pitch_has_nz,	/* Include pitch nullzone */
34 	Boolean bank_has_nz,	/* Include bank nullzone */
35 	time_t cur_ms, time_t lapsed_ms,
36 	float time_compensation
37 );
38 void GCtlHandlePointer(
39 	gw_display_struct *display, gctl_struct *gc,
40 	gw_event_type type,
41 	int button,		/* Button number */
42 	int x, int y,
43 	time_t t,		/* Time stamp (in ms) */
44 	time_t lapsed_ms
45 );
46 void GCtlHandleKey(
47 	gw_display_struct *display, gctl_struct *gc,
48 	int k, Boolean state,	/* Key code and state */
49 	Boolean alt_state,	/* Modifier key states */
50 	Boolean ctrl_state,
51 	Boolean shift_state,
52 	time_t t,		/* Time stamp (in ms) */
53 	time_t lapsed_ms
54 );
55 void GCtlResetValues(gctl_struct *gc);
56 void GCtlResetTimmers(gctl_struct *gc);
57 void GCtlDelete(gctl_struct *gc);
58 
59 
60 #define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
61 #define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
62 #define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
63 #define STRDUP(s)       (((s) != NULL) ? strdup(s) : NULL)
64 
65 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
66 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
67 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
68 #define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
69 #define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : 1)
70 
71 
72 /*
73  *	Returns a pointer to a string describing the last error that
74  *	occured while calling a GCtl*() function or NULL if there was
75  *	no error.
76  */
GCtlGetError(void)77 char *GCtlGetError(void)
78 {
79 	return(last_gctl_error);
80 }
81 
82 /*
83  *	Initializes the Game Controller with the specified values.
84  */
GCtlNew(gctl_values_struct * v)85 gctl_struct *GCtlNew(gctl_values_struct *v)
86 {
87 	int i;
88 
89 	gctl_js_struct *joystick;
90 	gctl_values_js_struct *js_value;
91 	gctl_struct *gc = GCTL(calloc(1, sizeof(gctl_struct)));
92 
93 	last_gctl_error = NULL;
94 
95 	if(gc == NULL)
96 	{
97 	    last_gctl_error = "Memory allocation error";
98 	    return(NULL);
99 	}
100 
101 	/* Game Controller Values not specified? */
102 	if(v == NULL)
103 	{
104 	    free(gc);
105 	    last_gctl_error = "Game Controller Values not specified";
106 	    return(NULL);
107 	}
108 
109 	/* Set controller(s) and option(s) */
110 	gc->controllers = v->controllers;
111 	gc->options = v->options;
112 
113 	/* Initialize the joystick? */
114 	if(v->controllers & GCTL_CONTROLLER_JOYSTICK)
115 	{
116 	    const char *device;
117 	    gctl_js_axis_roles axis_role;
118 
119 	    /* Allocate Game Controller Joysticks */
120 	    gc->total_joysticks = v->total_joysticks;
121 	    gc->joystick = GCTL_JS(calloc(
122 		gc->total_joysticks, sizeof(gctl_js_struct)
123 	    ));
124 
125 	    if(gc->joystick == NULL)
126 	    {
127 		gc->total_joysticks = 0;
128 	    }
129 
130             /* Attempt to initialize the joystick subsystem. */
131             if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0)  {
132                 fprintf(stderr, "Unable to initialize SDL joysticks: %s\n", SDL_GetError());
133                 gc->sdljoystick = NULL;
134                 gc->total_joysticks = 0;
135             } else if (gc->total_joysticks > 0){
136                 /* Allocate space for SDL_Joystick structure */
137                 gc->sdljoystick = calloc(gc->total_joysticks, sizeof(SDL_Joystick*));
138             }
139 
140 
141 	    /* Iterate through each joystick */
142 	    for(i = 0; i < gc->total_joysticks; i++)
143 	    {
144 		/* Get pointer to current Game Controller Joystick and
145 		 * Joystick Values
146 		 */
147 		joystick = &gc->joystick[i];
148 		js_value = &v->joystick[i];
149 
150 
151 		device = js_value->device;
152 		axis_role = js_value->axis_role;
153 
154                 /* Enable SDL joysticks */
155                 if (SDL_NumJoysticks() > i) {
156                     fprintf(stderr, "Found SDL Joystick\n");
157                     //SDL_JoystickEventState(SDL_ENABLE);
158                     gc->sdljoystick[i] = SDL_JoystickOpen(i);
159                 }
160 
161 
162 		/* Begin setting up joystick axis mappings */
163 
164 		/* Reset all axis mappings first */
165 		joystick->axis_heading = -1;
166 		joystick->axis_bank = -1;
167 		joystick->axis_pitch = -1;
168 		joystick->axis_throttle = -1;
169 		joystick->axis_hat_x = -1;
170 		joystick->axis_hat_y = -1;
171 
172 		/* Throttle and rudder unit? */
173 		if(axis_role & GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER)
174 		{
175 		    joystick->axis_heading = 0;
176 		    joystick->axis_throttle = 1;
177 		}
178 		/* Joystick with no axises (only buttons) */
179 		else if(axis_role & GCTL_JS_AXIS_ROLE_NONE)
180 		{
181 
182 		}
183 		/* Joystick as a standard composite unit */
184 		else
185 		{
186 		    /* Get bank axis */
187 		    if(axis_role & GCTL_JS_AXIS_ROLE_BANK)
188 			joystick->axis_bank = 0;
189 		    /* Get heading axis */
190 		    if(axis_role & GCTL_JS_AXIS_ROLE_HEADING)
191 			joystick->axis_heading = 2;
192 		    /* Get pitch axis */
193 		    if(axis_role & GCTL_JS_AXIS_ROLE_PITCH)
194 			joystick->axis_pitch = 1;
195 
196 		    /* Get throttle axis */
197 		    if(axis_role & GCTL_JS_AXIS_ROLE_THROTTLE)
198 		    {
199 			/* Check if heading axis is valid, if not then
200 			 * throttle is axis 2
201 			 */
202 			if(joystick->axis_heading < 0)
203 			    joystick->axis_throttle = 2;
204 			else
205 			    joystick->axis_throttle = 3;
206 		    }
207 
208 		    /* Get hat x and y axis */
209 		    if(axis_role & GCTL_JS_AXIS_ROLE_HAT)
210 		    {
211 			/* Hat x */
212 			if(joystick->axis_heading < 0)
213 			{
214 			    if(joystick->axis_throttle < 0)
215 				joystick->axis_hat_x = 2;
216 			    else
217 				joystick->axis_hat_x = 3;
218 			}
219 			else if(joystick->axis_throttle < 0)
220 			{
221 			    joystick->axis_hat_x = 3;
222 			}
223 			else
224 			{
225 			    joystick->axis_hat_x = 4;
226 			}
227 			/* Hat y (the axis after hat x) */
228 			joystick->axis_hat_y =
229 			    joystick->axis_hat_x + 1;
230 		    }
231 		}	/* Joystick as a standard composite unit */
232 
233 
234 		/* Begin setting up joystick button mappings */
235 
236 		/* Copy joystick button mappings from js_value structure */
237 		joystick->button_rotate = js_value->button_rotate;
238 		joystick->button_air_brakes = js_value->button_air_brakes;
239 		joystick->button_wheel_brakes = js_value->button_wheel_brakes;
240 		joystick->button_zoom_in = js_value->button_zoom_in;
241 		joystick->button_zoom_out = js_value->button_zoom_out;
242 		joystick->button_hoist_up = js_value->button_hoist_up;
243 		joystick->button_hoist_down = js_value->button_hoist_down;
244 
245 
246 	    }	/* Iterate through each joystick */
247 	}	/* Initialize joystick? */
248 
249 
250 	/* Initialize keyboard? */
251 	if(v->controllers & GCTL_CONTROLLER_KEYBOARD)
252 	{
253 	    /* Begin resetting keyboard values */
254 	    /* Keyboard states */
255 	    gc->heading_kb_state = False;
256 	    gc->pitch_kb_state = False;
257 	    gc->bank_kb_state = False;
258 	    gc->throttle_kb_state = False;
259 	    gc->hat_x_kb_state = False;
260 	    gc->hat_y_kb_state = False;
261 
262 	    /* Last keypress time stamps */
263 	    gc->heading_kb_last = 0;
264 	    gc->pitch_kb_last = 0;
265 	    gc->bank_kb_last = 0;
266 	    gc->throttle_kb_last = 0;
267 	    gc->hat_x_kb_last = 0;
268 	    gc->hat_y_kb_last = 0;
269 
270 	    gc->axis_kb_state = False;
271 	    gc->button_kb_state = False;
272 	}	/* Initialize keyboard? */
273 
274 	/* Initialize pointer? */
275 	if(v->controllers & GCTL_CONTROLLER_POINTER)
276 	{
277 	    /* Begin resetting pointer values */
278 	    /* Pressed buttons mask */
279 	    gc->pointer_buttons = 0x00000000;
280 	    /* Set default pointer box size */
281 	    gc->pointer_box_x = 0;
282 	    gc->pointer_box_y = 0;
283 	    gc->pointer_box_width = 100;
284 	    gc->pointer_box_height = 70;
285 	    /* Reset pointer coordinates */
286 	    gc->pointer_x = (gc->pointer_box_width / 2);
287 	    gc->pointer_y = (gc->pointer_box_height / 2);
288 	}	/* Initialize pointer? */
289 
290 
291 	return(gc);
292 }
293 
294 /*
295  *	Updates the game controller structure with new (current)
296  *	controller values.
297  *
298  *	Keyboard handling is performed in GCtlHandleKey().
299  *
300  *	Pointer handling is performed in GCtlHandlePointer().
301  */
GCtlUpdate(gctl_struct * gc,Boolean heading_has_nz,Boolean pitch_has_nz,Boolean bank_has_nz,time_t cur_ms,time_t lapsed_ms,float time_compensation)302 void GCtlUpdate(
303 	gctl_struct *gc,
304 	Boolean heading_has_nz,	/* Include heading pitch nullzone */
305 	Boolean pitch_has_nz,	/* Include pitch nullzone */
306 	Boolean bank_has_nz,	/* Include bank nullzone */
307 	time_t cur_ms, time_t lapsed_ms,
308 	float time_compensation
309 )
310 {
311 	int i;
312 	gctl_controllers controllers;
313 	gctl_options options;
314 	time_t gc_last_updated_ms, dms;
315 	gctl_js_struct *joystick;
316 	Boolean js_def_heading = False,
317 		js_def_pitch = False,
318 		js_def_bank = False,
319 		js_def_hat_x = False,
320 		js_def_hat_y = False,
321 		js_def_zoom_in = False,
322 		js_def_zoom_out = False,
323 		js_def_air_brakes = False,
324 		js_def_wheel_brakes = False;
325 	Boolean	*btn_kb_state;
326 	float	*btn_kb_coeff;
327 	time_t	*btn_kb_last;
328 	float	btn_kb_decell_coeff;
329         SDL_Joystick *sdljoystick;
330 
331 	if(gc == NULL)
332 	    return;
333 
334 	/* Get game controllers and general options flags */
335 	controllers = gc->controllers;
336 	options = gc->options;
337 
338 	/* Get timings */
339 	gc_last_updated_ms = gc->last_updated;
340 	dms = (time_t)MAX(cur_ms - gc_last_updated_ms, 0);
341 
342 
343 	/* Check if joystick updating is needed and allowed */
344 	if((controllers & GCTL_CONTROLLER_JOYSTICK) &&
345 	   (gc->joystick != NULL)
346 	)
347 	{
348             SDL_JoystickUpdate();
349 	    /* Iterate through each joystick */
350 	    for(i = 0; i < gc->total_joysticks; i++)
351 	    {
352 		joystick = &gc->joystick[i];
353                 sdljoystick = gc->sdljoystick[i];
354 		/* Update defined joystick operations for this joystick.
355 		 * This is to tabulate a list of functions that were
356 		 * handled/controlled by any of the joystick(s) so the
357 		 * function does not get updated again by the keyboard
358 		 * check farther below
359 		 */
360 		if(joystick->axis_heading > -1)
361 		    js_def_heading = True;
362 		if(joystick->axis_pitch > -1)
363 		    js_def_pitch = True;
364 		if(joystick->axis_bank > -1)
365 		    js_def_bank = True;
366 		if(joystick->axis_hat_x > -1)
367 		    js_def_hat_x = True;
368 		if(joystick->axis_hat_y > -1)
369 		    js_def_hat_y = True;
370 		/* If ctrl state modifier is on then bank becomes heading */
371 		if((joystick->button_rotate > -1) &&
372                    gc->ctrl_state
373 		)
374 		{
375 		    if(js_def_bank)
376 		    {
377 			js_def_heading = True;
378 			js_def_bank = False;
379 		    }
380 		}
381 		if(joystick->button_zoom_in > -1)
382 		    js_def_zoom_in = True;
383 		if(joystick->button_zoom_out > -1)
384 		    js_def_zoom_out = True;
385 		if(joystick->button_air_brakes > -1)
386 		    js_def_air_brakes = True;
387 		if(joystick->button_wheel_brakes > -1)
388 		    js_def_wheel_brakes = True;
389 
390                 /* Begin handling joystick */
391 
392                 int axis_heading = joystick->axis_heading,
393                     axis_bank = joystick->axis_bank,
394                     axis_pitch = joystick->axis_pitch,
395                     axis_throttle = joystick->axis_throttle,
396                     axis_hat_x = joystick->axis_hat_x,
397                     axis_hat_y = joystick->axis_hat_y;
398 
399 
400                 /* Check bank to heading modifier */
401                 if((joystick->button_rotate > -1) &&
402                    gc->ctrl_state
403                     )
404                 {
405                     /* Bank axis becomes the heading axis */
406                     if(axis_bank > -1)
407                     {
408                         axis_heading = axis_bank;
409                         axis_bank = -1;
410                     }
411                 }
412 
413                 /* SDL joystick */
414 
415                 if (sdljoystick) {
416                     // So we've got an SDL joystick structure.
417                     // For now, we treat
418                     //  Axis 0: -ve bank left, +ve bank right
419                     //  Axis 1: -ve pitch nose down, +ve pitch nose up
420                     //  Axis 2: -ve throttle 0%, +ve throttle 100%
421 
422                     /* Heading */
423                     if((axis_heading > -1) &&
424                        !gc->axis_kb_state)
425                         gc->heading = ((float)SDL_JoystickGetAxis(sdljoystick, axis_heading) / 32768.0);
426 
427                     if((axis_bank > -1) &&
428                        !gc->axis_kb_state)
429                         gc->bank = ((float)SDL_JoystickGetAxis(sdljoystick, axis_bank) / 32768.0);
430 
431                     /* Pitch */
432                     if((axis_pitch > -1) &&
433                        !gc->axis_kb_state)
434                         gc->pitch = - ((float)SDL_JoystickGetAxis(sdljoystick, axis_pitch) / 32768.0);
435 
436                     if((axis_throttle > -1) &&
437                        !gc->axis_kb_state)
438                         gc->throttle = 1.0 - (((float)SDL_JoystickGetAxis(sdljoystick, axis_throttle) + 32768.0) / 65536.0);
439 
440                     /* Hat */
441 
442                     if ((axis_hat_x > -1) && (axis_hat_y > -1))
443                     {
444                         int pos = SDL_JoystickGetHat(sdljoystick,0);
445                         switch (pos) {
446                             case SDL_HAT_CENTERED:
447                                 gc->hat_y= 0.0f;
448                                 gc->hat_x= 0.0f;
449                                 break;
450                             case SDL_HAT_UP:
451                                 gc->hat_y= 1.0f;
452                                 gc->hat_x= 0.0f;
453                                 break;
454                             case SDL_HAT_RIGHT:
455                                 gc->hat_y= 0.0f;
456                                 gc->hat_x= 1.0f;
457                                 break;
458                             case SDL_HAT_DOWN:
459                                 gc->hat_y= -1.0f;
460                                 gc->hat_x= 0.0f;
461                                 break;
462                             case SDL_HAT_LEFT:
463                                 gc->hat_y= 0.0f;
464                                 gc->hat_x= -1.0f;
465                                 break;
466                             case SDL_HAT_RIGHTUP:
467                                 gc->hat_y= 1.0f;
468                                 gc->hat_x= 1.0f;
469                                 break;
470                             case SDL_HAT_RIGHTDOWN:
471                                 gc->hat_y= -1.0f;
472                                 gc->hat_x= 1.0f;
473                                 break;
474                             case SDL_HAT_LEFTUP:
475                                 gc->hat_y= 1.0f;
476                                 gc->hat_x= -1.0f;
477                                 break;
478                             case SDL_HAT_LEFTDOWN:
479                                 gc->hat_y= -1.0f;
480                                 gc->hat_x= -1.0f;
481                                 break;
482                             default:
483                                 gc->hat_y= 0.0f;
484                                 gc->hat_x= 0.0f;
485                                 break;
486                         }
487                     }
488 
489 
490                     /* Handle buttons */
491 
492 
493 
494                     /* Zoom */
495                     if (!gc->button_kb_state){
496                     gc->zoom_in_state = SDL_JoystickGetButton(
497                         sdljoystick,
498                         joystick->button_zoom_in) ? True : False;
499                     gc->zoom_in_coeff = (float)((gc->zoom_in_state) ? 1.0 : 0.0);
500                     }
501 
502                     if (!gc->button_kb_state){
503                         gc->zoom_out_state = SDL_JoystickGetButton(
504                             sdljoystick,
505                             joystick->button_zoom_out) ? True : False;
506                         gc->zoom_out_coeff = (float)((gc->zoom_out_state) ? 1.0 : 0.0);
507                     }
508 
509                     /*Hoist*/
510                     if (!gc->button_kb_state){
511                         gc->hoist_up_state = SDL_JoystickGetButton(
512                             sdljoystick,
513                             joystick->button_hoist_up) ? True : False;
514                         gc->hoist_up_coeff = (float)((gc->hoist_up_state) ? 1.0 : 0.0);
515                     }
516 
517                     if (!gc->button_kb_state){
518                         gc->hoist_down_state = SDL_JoystickGetButton(
519                             sdljoystick,
520                             joystick->button_hoist_down) ? True : False;
521                         gc->hoist_down_coeff = (float)((gc->hoist_down_state) ? 1.0 : 0.0);
522                     }
523                     /* Update ctrl modifier state (for switching
524                      * bank axis to act as heading axis), but update
525                      * this modifier only if the button mapped to it
526                      * has been defined
527                      */
528                     if((joystick->button_rotate > -1) &&
529                        !gc->button_kb_state)
530                         gc->ctrl_state = (SDL_JoystickGetButton(sdljoystick, joystick->button_rotate)) ? True : False;
531 
532                     /* Air brakes */
533                     if (!gc->button_kb_state){
534                         if ( SDL_JoystickGetButton(
535                                  sdljoystick,
536                                  joystick->button_air_brakes)){
537                             gc->air_brakes_state = gc->air_brakes_state ? False : True;
538                             gc->air_brakes_coeff = gc->air_brakes_state ? 1.0f : 0.0f;
539                         }
540                     }
541                     /* Wheel brakes */
542                     if (!gc->button_kb_state){
543                         gc->wheel_brakes_state = SDL_JoystickGetButton(
544                             sdljoystick,
545                             joystick->button_wheel_brakes) ? True : False;
546                         gc->wheel_brakes_coeff = gc->wheel_brakes_state ? 1.0f : 0.0f;
547 
548                         if (gc->wheel_brakes_state)
549                         {
550                             if (gc->shift_state)
551                                 gc->wheel_brakes_state = 2;
552                             else
553                                 gc->wheel_brakes_state = 1;
554                         }
555                         else
556                         {
557                             if (gc->wheel_brakes_state != 2)
558                                 gc->wheel_brakes_state = 0;
559                         }
560                     }
561                 }
562 
563 
564 
565 
566 	    }	/* Iterate through each joystick */
567 	}	/* Check if joystick updating is needed and allowed */
568 
569 
570 	/* Check if keyboard updating is needed and allowed
571 	 *
572 	 * Handle keyboard only if pointer or joystick are not present
573 	 */
574 	if(controllers & GCTL_CONTROLLER_KEYBOARD)
575 	{
576 
577 /* Reduces the btn_kb_coeff towards 0.0 if btn_kb_state is false.
578  * The bigger btn_kb_decell_coeff is, the faster btn_kb_coeff reaches
579  * 0.0.
580  */
581 #define DO_KB_BTN_UPDATE				\
582 { 							\
583  if(!(*btn_kb_state))					\
584  {							\
585   if(*btn_kb_coeff > 0.0f)				\
586    *btn_kb_coeff = (float)MAX(				\
587     (*btn_kb_coeff) -					\
588     (btn_kb_decell_coeff * time_compensation),		\
589     0.0							\
590    );							\
591   else							\
592    *btn_kb_coeff = (float)MIN(				\
593     (*btn_kb_coeff) +					\
594     (btn_kb_decell_coeff * time_compensation),		\
595     0.0							\
596    );							\
597  }							\
598 }
599 
600 	    /* Begin reducing coefficients for keyboard key states.
601 	     *
602 	     * Some key states will be skipped if their corresponding
603 	     * functions were already handled by the joystick.
604 	     */
605 	    /* Heading */
606 	    if(!js_def_heading || gc->axis_kb_state)
607 	    {
608 		btn_kb_decell_coeff = 3.0f;
609 		btn_kb_state = &gc->heading_kb_state;
610 		btn_kb_last = &gc->heading_kb_last;
611 		btn_kb_coeff = &gc->heading;
612 		DO_KB_BTN_UPDATE
613 	    }
614 	    /* Pitch */
615 	    if(!js_def_pitch || gc->axis_kb_state)
616 	    {
617 		btn_kb_decell_coeff = 3.0f;
618 		btn_kb_state = &gc->pitch_kb_state;
619 		btn_kb_last = &gc->pitch_kb_last;
620 		btn_kb_coeff = &gc->pitch;
621 		DO_KB_BTN_UPDATE
622 	    }
623 	    /* Bank */
624 	    if(!js_def_bank || gc->axis_kb_state)
625 	    {
626 		/* Bank */
627 		btn_kb_decell_coeff = 3.0f;
628 		btn_kb_state = &gc->bank_kb_state;
629 		btn_kb_last = &gc->bank_kb_last;
630 		btn_kb_coeff = &gc->bank;
631 		DO_KB_BTN_UPDATE
632 	    }
633 
634 	    /* Leave throttle alone */
635 
636 	    /* Hat X */
637 	    if(!js_def_hat_x || gc->axis_kb_state)
638 	    {
639 		btn_kb_decell_coeff = 2.0f;
640 		btn_kb_state = &gc->hat_x_kb_state;
641 		btn_kb_last = &gc->hat_x_kb_last;
642 		btn_kb_coeff = &gc->hat_x;
643 		DO_KB_BTN_UPDATE
644 	    }
645 	    /* Hat Y */
646 	    if(!js_def_hat_y || gc->axis_kb_state)
647 	    {
648 		btn_kb_decell_coeff = 2.0f;
649 		btn_kb_state = &gc->hat_y_kb_state;
650 		btn_kb_last = &gc->hat_y_kb_last;
651 		btn_kb_coeff = &gc->hat_y;
652 		DO_KB_BTN_UPDATE
653 	    }
654 
655 	    /* Wheel brakes */
656 	    if(!js_def_wheel_brakes || gc->button_kb_state)
657 	    {
658 		Boolean b = (Boolean)gc->wheel_brakes_state;
659 		btn_kb_decell_coeff = 0.5f;
660 		btn_kb_state = &b;
661 		btn_kb_last = &gc->wheel_brakes_kb_last;
662 		btn_kb_coeff = &gc->wheel_brakes_coeff;
663 		DO_KB_BTN_UPDATE
664 		gc->wheel_brakes_state = (int)*btn_kb_state;
665 	    }
666 	    /* Air brakes */
667 	    if(!js_def_air_brakes || gc->button_kb_state)
668 	    {
669 		/* Leave air brakes alone */
670 	    }
671 
672 	    /* Zoom in */
673 	    if(!js_def_zoom_in || gc->button_kb_state)
674 	    {
675 		btn_kb_decell_coeff = 1.6f;
676 		btn_kb_state = &gc->zoom_in_state;
677 		btn_kb_last = &gc->zoom_in_kb_last;
678 		btn_kb_coeff = &gc->zoom_in_coeff;
679 		DO_KB_BTN_UPDATE
680 	    }
681 	    /* Zoom out */
682 	    if(!js_def_zoom_out || gc->button_kb_state)
683 	    {
684 		btn_kb_decell_coeff = 1.6f;
685 		btn_kb_state = &gc->zoom_out_state;
686 		btn_kb_last = &gc->zoom_out_kb_last;
687 		btn_kb_coeff = &gc->zoom_out_coeff;
688 		DO_KB_BTN_UPDATE
689 	    }
690 
691 #undef DO_KB_BTN_UPDATE
692 	}	/* Check if keyboard updating is needed and allowed */
693 
694 
695 	/* Check if pointer updating is needed and allowed */
696 	if(controllers & GCTL_CONTROLLER_POINTER)
697 	{
698 
699 
700 
701 	}
702 
703 	/* Update last gc time updated in ms to the current time */
704 	gc->last_updated = cur_ms;
705 }
706 
707 /*
708  *	Handles a pointer event with respect to the given game
709  *	controller.
710  */
GCtlHandlePointer(gw_display_struct * display,gctl_struct * gc,gw_event_type type,int button,int x,int y,time_t t,time_t lapsed_ms)711 void GCtlHandlePointer(
712 	gw_display_struct *display, gctl_struct *gc,
713 	gw_event_type type,
714 	int button,		/* Button number */
715 	int x, int y,
716 	time_t t,		/* Time stamp (in ms) */
717 	time_t lapsed_ms
718 )
719 {
720 	if(gc == NULL)
721 	    return;
722 
723 	if(!(gc->controllers & GCTL_CONTROLLER_POINTER))
724 	    return;
725 
726 /* TODO */
727 
728 }
729 
730 
731 /*
732  *	Handles the key, where state indicates if it is pressed or
733  *	released.
734  */
GCtlHandleKey(gw_display_struct * display,gctl_struct * gc,int k,Boolean state,Boolean alt_state,Boolean ctrl_state,Boolean shift_state,time_t t,time_t lapsed_ms)735 void GCtlHandleKey(
736 	gw_display_struct *display, gctl_struct *gc,
737 	int k, Boolean state,	/* Key value and state */
738 	Boolean alt_state,	/* Modifier key states */
739 	Boolean ctrl_state,
740 	Boolean shift_state,
741 	time_t t,		/* Time stamp (in ms) */
742 	time_t lapsed_ms
743 )
744 {
745 	Boolean	*btn_kb_state;
746 	float	*btn_kb_coeff;
747 	time_t	*btn_kb_last;
748 	float	btn_kb_to_coeff;
749 
750 
751 	if(gc == NULL)
752 	    return;
753 
754 	if(!(gc->controllers & GCTL_CONTROLLER_KEYBOARD))
755 	    return;
756 
757 	/* Alt key state */
758 	gc->alt_state = (alt_state) ? True : False;
759 	gc->ctrl_state = (ctrl_state) ? True : False;
760 	gc->shift_state = (shift_state) ? True : False;
761 
762 
763 /* Macro to switch off keyboard repeats if the key is held down */
764 #define DO_HAS_NO_AUTOREPEAT    \
765 GWKeyboardAutoRepeat(display, (Boolean)!state);
766 
767 /* Update the keyboard key based on the value of the pointers to
768  * three variables representing the key's state, coefficient, and
769  * last event time (btn_kb_state, btn_kb_coeff, and btn_kb_last
770  * respectivly).
771  */
772 #define DO_BTN_KB_UPDATE					\
773 if(state != (*btn_kb_state))					\
774 {								\
775  time_t dt = MAX(t - (*btn_kb_last), 0);			\
776  if(state)							\
777  {								\
778   /* Pressed down */						\
779   *btn_kb_state = True;						\
780   *btn_kb_coeff = 1.0f;						\
781   *btn_kb_last = t;						\
782  }								\
783  else if(dt > lapsed_ms)					\
784  {								\
785   /* Released up */						\
786   *btn_kb_state = False;					\
787   *btn_kb_last = t;						\
788  }								\
789  else								\
790  {								\
791   /* Released up quickly from a prior press which occured	\
792    * during this cycle.						\
793    */								\
794   *btn_kb_state = False;					\
795   *btn_kb_coeff = (lapsed_ms > 0) ?				\
796    ((float)dt / (float)lapsed_ms) : 0.0f;			\
797   *btn_kb_last = t;						\
798  }								\
799 }
800 
801 /* Update the keyboard key for an axis based on the value of the
802  * pointers to three variables representing the key's state,
803  * coefficient, and last event time (btn_kb_state, btn_kb_coeff,
804  * and btn_kb_last respectivly).
805  */
806 #define DO_BTN_KB_AXIS_UPDATE					\
807 if(state != (*btn_kb_state))					\
808 {								\
809  time_t dt = MAX(t - (*btn_kb_last), 0);			\
810  if(state)							\
811  {								\
812   /* Pressed down */						\
813   *btn_kb_state = True;						\
814   *btn_kb_coeff = btn_kb_to_coeff;				\
815   *btn_kb_last = t;						\
816  }								\
817  else if(dt > lapsed_ms)					\
818  {								\
819   /* Released up */						\
820   *btn_kb_state = False;					\
821   *btn_kb_last = t;						\
822  }								\
823  else								\
824  {								\
825   /* Released up quickly from a prior press which occured	\
826    * during this cycle.						\
827    */								\
828   *btn_kb_state = False;					\
829   *btn_kb_coeff = btn_kb_to_coeff * ((lapsed_ms > 0) ?	\
830    ((float)dt / (float)lapsed_ms) : 0.0f);		\
831   *btn_kb_last = t;						\
832  }								\
833 }
834 
835 
836 	switch(k)
837 	{
838 	  case GWKeyLeft:
839 	    DO_HAS_NO_AUTOREPEAT
840 	    btn_kb_to_coeff = -1.0f;
841 	    if(gc->ctrl_state)
842 	    {
843 		btn_kb_state = &gc->heading_kb_state;
844 		btn_kb_coeff = &gc->heading;
845 		btn_kb_last = &gc->heading_kb_last;
846 	    }
847 	    else if(gc->shift_state)
848 	    {
849 		btn_kb_state = &gc->hat_x_kb_state;
850 		btn_kb_coeff = &gc->hat_x;
851 		btn_kb_last = &gc->hat_x_kb_last;
852 	    }
853 	    else
854 	    {
855 		btn_kb_state = &gc->bank_kb_state;
856 		btn_kb_coeff = &gc->bank;
857 		btn_kb_last = &gc->bank_kb_last;
858 	    }
859 	    DO_BTN_KB_AXIS_UPDATE
860 	    if(!state)
861 	    {
862 		gc->heading_kb_state = False;
863 		gc->hat_x_kb_state = False;
864 		gc->bank_kb_state = False;
865 	    }
866 	    gc->axis_kb_state = state;
867 	    break;
868 
869 	  case GWKeyRight:
870 	    DO_HAS_NO_AUTOREPEAT
871 	    btn_kb_to_coeff = 1.0f;
872 	    if(gc->ctrl_state)
873 	    {
874 		btn_kb_state = &gc->heading_kb_state;
875 		btn_kb_coeff = &gc->heading;
876 		btn_kb_last = &gc->heading_kb_last;
877 	    }
878 	    else if(gc->shift_state)
879 	    {
880 		btn_kb_state = &gc->hat_x_kb_state;
881 		btn_kb_coeff = &gc->hat_x;
882 		btn_kb_last = &gc->hat_x_kb_last;
883 	    }
884 	    else
885 	    {
886 		btn_kb_state = &gc->bank_kb_state;
887 		btn_kb_coeff = &gc->bank;
888 		btn_kb_last = &gc->bank_kb_last;
889 	    }
890 	    DO_BTN_KB_AXIS_UPDATE
891 	    if(!state)
892 	    {
893 		gc->heading_kb_state = False;
894 		gc->hat_x_kb_state = False;
895 		gc->bank_kb_state = False;
896 	    }
897 	    gc->axis_kb_state = state;
898 	    break;
899 
900 	  case GWKeyUp:
901 	    DO_HAS_NO_AUTOREPEAT
902 	    btn_kb_to_coeff = 1.0f;
903 	    if(gc->shift_state)
904 	    {
905 		btn_kb_state = &gc->hat_y_kb_state;
906 		btn_kb_coeff = &gc->hat_y;
907 		btn_kb_last = &gc->hat_y_kb_last;
908 	    }
909 	    else
910 	    {
911 		btn_kb_state = &gc->pitch_kb_state;
912 		btn_kb_coeff = &gc->pitch;
913 		btn_kb_last = &gc->pitch_kb_last;
914 	    }
915 	    DO_BTN_KB_AXIS_UPDATE
916 	    if(!state)
917 	    {
918 		gc->pitch_kb_state = False;
919 		gc->hat_y_kb_state = False;
920 	    }
921 	    gc->axis_kb_state = state;
922 	    break;
923 
924 	  case GWKeyDown:
925 	    DO_HAS_NO_AUTOREPEAT
926 	    btn_kb_to_coeff = -1.0f;
927 	    if(gc->shift_state)
928 	    {
929 		btn_kb_state = &gc->hat_y_kb_state;
930 		btn_kb_coeff = &gc->hat_y;
931 		btn_kb_last = &gc->hat_y_kb_last;
932 	    }
933 	    else
934 	    {
935 		btn_kb_state = &gc->pitch_kb_state;
936 		btn_kb_coeff = &gc->pitch;
937 		btn_kb_last = &gc->pitch_kb_last;
938 	    }
939 	    DO_BTN_KB_AXIS_UPDATE
940 	    if(!state)
941 	    {
942 		gc->pitch_kb_state = False;
943 		gc->hat_y_kb_state = False;
944 	    }
945 	    gc->axis_kb_state = state;
946 	    break;
947 
948 	  /* Throttle */
949 	  case GWKeyPageUp:
950 	    if(state)
951 	    {
952 		gc->throttle += (float)((gc->shift_state) ? 0.1 : 0.01);
953 		if(gc->throttle > 1.0)
954 		    gc->throttle = 1.0f;
955 	    }
956 	    gc->axis_kb_state = state;
957 	    break;
958 	  case GWKeyPageDown:
959 	    if(state)
960 	    {
961 		gc->throttle -= (float)((gc->shift_state) ? 0.1 : 0.01);
962 		if(gc->throttle < 0.0)
963 		    gc->throttle = 0.0f;
964 	    }
965 	    gc->axis_kb_state = state;
966 	    break;
967 
968           /* adding some more throttle short-cuts here. -- Jesse */
969           case '1': case '2': case '3':
970           case '4': case '5': case '6':
971           case '7': case '8': case '9':
972                gc->throttle = (float) ( ( k - '0') / 10.0);
973                break;
974           case '0':
975                gc->throttle = 1.0;
976                break;
977 
978 	  /* Wheel brakes */
979 	  case GWKeyDelete: case '.': case '>':
980 	    DO_HAS_NO_AUTOREPEAT
981 	    if(True)
982 	    {
983 		Boolean b = (Boolean)gc->wheel_brakes_state;
984 		btn_kb_state = &b;
985 		btn_kb_coeff = &gc->wheel_brakes_coeff;
986 		btn_kb_last = &gc->wheel_brakes_kb_last;
987 		DO_BTN_KB_UPDATE
988 		gc->wheel_brakes_state = (int)*btn_kb_state;
989 	    }
990 	    gc->button_kb_state = state;
991 	    break;
992 
993 	  /* Air brakes */
994 	  case 'b':
995 	    if(state)
996 	    {
997 		/* Air brakes are toggled on/off */
998 		if(gc->air_brakes_state)
999 		{
1000 		    gc->air_brakes_state = False;
1001 		    gc->air_brakes_coeff = 0.0f;
1002 		}
1003 		else
1004 		{
1005 		    gc->air_brakes_state = True;
1006 		    gc->air_brakes_coeff = 1.0f;
1007 		}
1008 	    }
1009 	    gc->button_kb_state = state;
1010 	    break;
1011 
1012 	  /* Zoom in */
1013 	  case '=': case '+':
1014 	    DO_HAS_NO_AUTOREPEAT
1015 	    btn_kb_state = &gc->zoom_in_state;
1016 	    btn_kb_coeff = &gc->zoom_in_coeff;
1017 	    btn_kb_last = &gc->zoom_in_kb_last;
1018 	    DO_BTN_KB_UPDATE
1019 	    gc->button_kb_state = state;
1020 	    break;
1021 
1022 	  /* Zoom out */
1023 	  case '-': case '_':
1024 	    DO_HAS_NO_AUTOREPEAT
1025 	    btn_kb_state = &gc->zoom_out_state;
1026 	    btn_kb_coeff = &gc->zoom_out_coeff;
1027 	    btn_kb_last = &gc->zoom_out_kb_last;
1028 	    DO_BTN_KB_UPDATE
1029 	    gc->button_kb_state = state;
1030 	    break;
1031 
1032 	}
1033 
1034 #undef DO_BTN_KB_UPDATE
1035 #undef DO_BTN_KB_AXIS_UPDATE
1036 #undef DO_HAS_NO_AUTOREPEAT
1037 }
1038 
1039 
1040 /*
1041  *	Resets all toggle state dependent values to defaults on the
1042  *	given game controller structure.
1043  */
GCtlResetValues(gctl_struct * gc)1044 void GCtlResetValues(gctl_struct *gc)
1045 {
1046 	if(gc == NULL)
1047 	    return;
1048 
1049 	/* Air brakes are toggled, so its value needs to be reset */
1050 	gc->air_brakes_state = False;
1051 	gc->air_brakes_kb_last = 0;
1052 	gc->air_brakes_coeff = 0.0f;
1053 
1054 
1055 }
1056 
1057 /*
1058  *	Resets all timmer values on the given game controller structure.
1059  */
GCtlResetTimmers(gctl_struct * gc)1060 void GCtlResetTimmers(gctl_struct *gc)
1061 {
1062 	if(gc == NULL)
1063 	    return;
1064 
1065 	gc->last_updated = 0;
1066 
1067 	gc->heading_kb_last = 0;
1068 	gc->pitch_kb_last = 0;
1069 	gc->bank_kb_last = 0;
1070 	gc->throttle_kb_last = 0;
1071 	gc->hat_x_kb_last = 0;
1072 	gc->hat_y_kb_last = 0;
1073 
1074 	gc->zoom_in_kb_last = 0;
1075 	gc->zoom_out_kb_last = 0;
1076 
1077 	gc->hoist_up_kb_last = 0;
1078 	gc->hoist_down_kb_last = 0;
1079 
1080 	gc->air_brakes_kb_last = 0;
1081 	gc->wheel_brakes_kb_last = 0;
1082 }
1083 
1084 /*
1085  *	Shuts down the Game Controller.
1086  */
GCtlDelete(gctl_struct * gc)1087 void GCtlDelete(gctl_struct *gc)
1088 {
1089 	int i;
1090 	gctl_js_struct *joystick;
1091 
1092 	last_gctl_error = NULL;
1093 
1094 	if(gc == NULL)
1095 	    return;
1096 
1097 	/* Joystick(s) initialized? */
1098 	if(gc->joystick != NULL)
1099 	{
1100 	    /* Iterate through each joystick */
1101 	    for(i = 0; i < gc->total_joysticks; i++)
1102 	    {
1103 		joystick = &gc->joystick[i];
1104 
1105 		/* Begin shutting down this joystick */
1106 
1107 	    }
1108 
1109 	    /* Delete joysticks */
1110 	    free(gc->joystick);
1111 	    gc->joystick = NULL;
1112 	    gc->total_joysticks = 0;
1113 	}
1114 
1115 	free(gc);
1116 }
1117