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