1 /* $Id: tenm_input.c,v 1.91 2004/02/15 14:43:09 oohara Exp $ */
2 
3 #include <stdio.h>
4 /* atexit, malloc */
5 #include <stdlib.h>
6 /* for tenm_polygon_new */
7 #include <stdarg.h>
8 /* errno */
9 #include <errno.h>
10 /* strerror */
11 #include <string.h>
12 
13 #include <SDL.h>
14 
15 /* tenm_redraw_window() */
16 #include "tenm_graphic.h"
17 /* tenm_pow2() */
18 #include "tenm_math.h"
19 #include "tenm_sdl_init.h"
20 
21 #include "tenm_input.h"
22 
23 static int number_key_mask = 0;
24 static tenm_key *key_mask = NULL;
25 
26 static void (*focus_handler)(int) = NULL;
27 
28 static SDL_Joystick *js = NULL;
29 static int *joystick_axis_set = NULL;
30 static tenm_key *joystick_axis_mask = NULL;
31 static int *joystick_button_set = NULL;
32 static tenm_key *joystick_button_mask = NULL;
33 static int neutral_range = 8192;
34 
35 static int key_status;
36 
37 static int tenm_add_key_status(tenm_key key, int delta);
38 static void tenm_key_quit(void);
39 static void tenm_joystick_quit(void);
40 
41 /* there is no init() for keyboard because it is initialized
42  * along with video and there is tenm_graphic_init()
43  */
44 
45 /* ... is 0 -- TENM_NUMBER_KEY_MAX (16) of (tenm_key key)
46  * return 0 on success, 1 on error
47  */
48 int
tenm_set_key(int number_key,...)49 tenm_set_key(int number_key, ...)
50 {
51   int i;
52   va_list ap;
53   tenm_key *temp_key_mask = NULL;
54 
55   /* sanity check */
56   if (number_key <= -1)
57   {
58     fprintf(stderr, "tenm_set_key: number_key is negative\n");
59     return 1;
60   }
61 
62   if (number_key > TENM_NUMBER_KEY_MAX)
63   {
64     fprintf(stderr, "tenm_set_key: warning: registering only the first "
65             "%d keys and ignoring the rest\n", TENM_NUMBER_KEY_MAX);
66     number_key = TENM_NUMBER_KEY_MAX;
67   }
68 
69   /* initialize SDL if necessary */
70   if (tenm_sdl_init(SDL_INIT_VIDEO) != 0)
71   {
72     fprintf(stderr, "tenm_set_key: cannot initialize SDL video \n");
73     return 1;
74   }
75 
76   errno = 0;
77   if (atexit(tenm_key_quit) != 0)
78   {
79     fprintf(stderr, "tenm_set_key: cannot register tenm_key_quit "
80             "to exit");
81     if (errno != 0)
82       fprintf(stderr, " (%s)", strerror(errno));
83     fprintf(stderr, "\n");
84     tenm_key_quit();
85     return 1;
86   }
87 
88   /* don't substitute key_mask directly, or you will be in a trouble
89    * if realloc fails  */
90   if (key_mask == NULL)
91     temp_key_mask = (tenm_key *) malloc(sizeof(tenm_key) * number_key);
92   else
93     temp_key_mask = (tenm_key *) realloc(key_mask,
94                                          sizeof(tenm_key) * number_key);
95   if (temp_key_mask == NULL)
96   {
97     fprintf(stderr, "tenm_event_init: memory allocation to key_mask failed\n");
98     tenm_key_quit();
99     return 1;
100   }
101 
102   key_mask = temp_key_mask;
103   number_key_mask = number_key;
104   va_start(ap, number_key);
105   for (i = 0; i < number_key; i++)
106     key_mask[i] = va_arg(ap, tenm_key);
107   va_end(ap);
108 
109   return 0;
110 }
111 
112 void
tenm_set_focus_handler(void (* handler)(int))113 tenm_set_focus_handler(void (*handler)(int))
114 {
115   focus_handler = (void (*)(int)) handler;
116 }
117 
118 /* range is the maximum of the absolute value of event.jaxis.axis
119  * that is considered to be neutral
120  * return TENM_JOYSTICK_INIT_SUCCESS, TENM_JOYSTICK_INIT_NO_JOYSTICK
121  * or TENM_JOYSTICK_INIT_ERROR
122  */
123 int
tenm_joystick_init(int range)124 tenm_joystick_init(int range)
125 {
126   int i;
127 
128   /* sanity check */
129   if (range <= 0)
130   {
131     fprintf(stderr, "tenm_joystick_init: strange range (%d)\n", range);
132     return TENM_JOYSTICK_INIT_ERROR;
133   }
134 
135   if (SDL_WasInit(SDL_INIT_JOYSTICK) != 0)
136   {
137     fprintf(stderr, "tenm_joystick_init: warning: joystick is already "
138             "initialized\n");
139     return TENM_JOYSTICK_INIT_SUCCESS;
140   }
141 
142   if (tenm_sdl_init(SDL_INIT_JOYSTICK) != 0)
143   {
144     fprintf(stderr, "tenm_joystick_init: cannot initialize SDL joystick "
145             "(%s)\n", SDL_GetError());
146     return TENM_JOYSTICK_INIT_ERROR;
147   }
148 
149   errno = 0;
150   if (atexit(tenm_joystick_quit) != 0)
151   {
152     fprintf(stderr, "tenm_joystick_init: cannot register tenm_joystick_quit "
153             "to exit");
154     if (errno != 0)
155       fprintf(stderr, " (%s)", strerror(errno));
156     fprintf(stderr, "\n");
157     tenm_joystick_quit();
158     return TENM_JOYSTICK_INIT_ERROR;
159   }
160 
161   if (SDL_NumJoysticks() <= 0)
162   {
163     fprintf(stderr, "tenm_joystick_init: no joystick found\n");
164     /* this is not a fatal error --- you should fall back to a keyboard */
165     return TENM_JOYSTICK_INIT_NO_JOYSTICK;
166   }
167 
168   if (js != NULL)
169   {
170     fprintf(stderr, "tenm_joystick_init: js is already set\n");
171     /* this is a fatal error --- if we are here, joystick is not
172      * initialized before tenm_joystick_init() is called, so
173      * the situation is weird enough
174      */
175     tenm_joystick_quit();
176     return TENM_JOYSTICK_INIT_ERROR;
177   }
178   js = SDL_JoystickOpen(0);
179   if (js == NULL)
180   {
181     fprintf(stderr, "tenm_joystick_init: cannot open joystick 1 (%s)\n",
182             SDL_GetError());
183     tenm_joystick_quit();
184     return TENM_JOYSTICK_INIT_ERROR;
185   }
186 
187   if (SDL_JoystickEventState(SDL_ENABLE) != SDL_ENABLE)
188   {
189     fprintf(stderr, "tenm_set_key: cannot enable SDL joystick event "
190             "processing (%s)\n", SDL_GetError());
191     tenm_joystick_quit();
192     return TENM_JOYSTICK_INIT_ERROR;
193   }
194 
195   if (joystick_axis_set != NULL)
196   {
197     fprintf(stderr, "tenm_joystick_init: warning: joystick_axis_set is "
198             "not NULL, freeing\n");
199     free(joystick_axis_set);
200     joystick_axis_set = NULL;
201   }
202   joystick_axis_set = (int *) malloc(sizeof(int) * 4);
203   if (joystick_axis_set == NULL)
204   {
205     fprintf(stderr, "tenm_joystick_init: malloc(joystick_axis_set) failed\n");
206     tenm_joystick_quit();
207     return TENM_JOYSTICK_INIT_ERROR;
208   }
209   for (i = 0; i < 4; i++)
210     joystick_axis_set[i] = 0;
211 
212   if (joystick_axis_mask != NULL)
213   {
214     fprintf(stderr, "tenm_joystick_init: warning: joystick_axis_mask is "
215             "not NULL, freeing\n");
216     free(joystick_axis_mask);
217     joystick_axis_mask = NULL;
218   }
219   joystick_axis_mask = (tenm_key *) malloc(sizeof(tenm_key) * 4);
220   if (joystick_axis_mask == NULL)
221   {
222     fprintf(stderr, "tenm_joystick_init: malloc(joystick_axis_mask) failed\n");
223     tenm_joystick_quit();
224     return TENM_JOYSTICK_INIT_ERROR;
225   }
226 
227   if (joystick_button_set != NULL)
228   {
229     fprintf(stderr, "tenm_joystick_init: warning: joystick_button_set is "
230             "not NULL, freeing\n");
231     free(joystick_button_set);
232     joystick_button_set = NULL;
233   }
234   joystick_button_set = (int *) malloc(sizeof(int) * (TENM_NUMBER_KEY_MAX -4));
235   if (joystick_button_set == NULL)
236   {
237     fprintf(stderr, "tenm_joystick_init: malloc(joystick_button_set) "
238             "failed\n");
239     tenm_joystick_quit();
240     return TENM_JOYSTICK_INIT_ERROR;
241   }
242   for (i = 0; i < TENM_NUMBER_KEY_MAX - 4; i++)
243     joystick_button_set[i] = 0;
244 
245   if (joystick_button_mask != NULL)
246   {
247     fprintf(stderr, "tenm_joystick_init: warning: joystick_button_mask is "
248             "not NULL, freeing\n");
249     free(joystick_button_mask);
250     joystick_button_mask = NULL;
251   }
252   joystick_button_mask = (tenm_key *) malloc(sizeof(tenm_key)
253                                              * (TENM_NUMBER_KEY_MAX - 4));
254   if (joystick_button_mask == NULL)
255   {
256     fprintf(stderr, "tenm_joystick_init: malloc(joystick_button_mask) "
257             "failed\n");
258     tenm_joystick_quit();
259     return TENM_JOYSTICK_INIT_ERROR;
260   }
261 
262   neutral_range = range;
263 
264   return TENM_JOYSTICK_INIT_SUCCESS;
265 }
266 
267 /* translate a direction of a joystick axis into a key
268  * return 0 on success, 1 on error
269  */
270 int
tenm_joystick_map_axis(int direction,tenm_key key)271 tenm_joystick_map_axis(int direction, tenm_key key)
272 {
273   /* sanity check */
274   if ((direction < 0) || (direction >= 4))
275   {
276     fprintf(stderr, "tenm_joystick_map_axis: strange direction (%d)\n",
277             direction);
278     return 1;
279   }
280 
281   if ((joystick_axis_set == NULL) || (joystick_axis_mask == NULL))
282   {
283     fprintf(stderr, "tenm_joystick_map_axis: joystick is not initialized\n");
284     return 1;
285   }
286 
287   joystick_axis_set[direction] = 1;
288   joystick_axis_mask[direction] = key;
289 
290   return 0;
291 }
292 
293 /* translate a button of a joystick axis into a key
294  * return 0 on success, 1 on error
295  */
296 int
tenm_joystick_map_button(int button_index,tenm_key key)297 tenm_joystick_map_button(int button_index, tenm_key key)
298 {
299   /* sanity check */
300   if ((button_index < 0) || (button_index >= 12))
301   {
302     fprintf(stderr, "tenm_joystick_map_button: strange button_index (%d)\n",
303             button_index);
304     return 1;
305   }
306 
307   if ((joystick_button_set == NULL) || (joystick_button_mask == NULL))
308   {
309     fprintf(stderr, "tenm_joystick_map_button: joystick is not initialized\n");
310     return 1;
311   }
312 
313   joystick_button_set[button_index] = 1;
314   joystick_button_mask[button_index] = key;
315 
316   return 0;
317 }
318 
319 int
tenm_get_key_status(void)320 tenm_get_key_status(void)
321 {
322   return key_status;
323 }
324 
325 /* return 1 if the program should quit, 0 if not */
326 int
tenm_event_handle(void)327 tenm_event_handle(void)
328 {
329   SDL_Event event;
330 
331   while (SDL_PollEvent(&event) > 0)
332   {
333     if (event.type == SDL_QUIT)
334       return 1;
335 
336     if (event.type == SDL_VIDEOEXPOSE)
337     {
338       tenm_redraw_window();
339     }
340     else if (event.type == SDL_ACTIVEEVENT)
341     {
342       if (event.active.gain == 1)
343       {
344         /* the mouse cursor entered the window */
345         if (focus_handler != NULL)
346           (*focus_handler)(1);
347       }
348       else
349       {
350         /* the mouse cursor left the window */
351         if (focus_handler != NULL)
352           (*focus_handler)(0);
353       }
354     }
355     else if (event.type == SDL_KEYDOWN)
356     {
357       tenm_add_key_status(event.key.keysym.sym, 1);
358     }
359     else if (event.type == SDL_KEYUP)
360     {
361       tenm_add_key_status(event.key.keysym.sym, -1);
362     }
363     else if (event.type == SDL_JOYAXISMOTION)
364     {
365       if ((joystick_axis_set == NULL)
366           || (joystick_axis_mask == NULL))
367       {
368         fprintf(stderr, "tenm_event_handle: SDL_JOYAXISMOTION event happened "
369                 "while joystick is not initialized, ignoring\n");
370         continue;
371       }
372 
373       if (event.jaxis.axis == 0)
374       {
375         /* left/right (mutually exclusive) */
376         if (joystick_axis_set[TENM_JOYSTICK_LEFT])
377         {
378           if (event.jaxis.value < -neutral_range)
379             tenm_add_key_status(joystick_axis_mask[TENM_JOYSTICK_LEFT], 1);
380           else
381             tenm_add_key_status(joystick_axis_mask[TENM_JOYSTICK_LEFT], -1);
382         }
383         if (joystick_axis_set[TENM_JOYSTICK_RIGHT])
384         {
385           if (event.jaxis.value > neutral_range)
386             tenm_add_key_status(joystick_axis_mask[TENM_JOYSTICK_RIGHT], 1);
387           else
388             tenm_add_key_status(joystick_axis_mask[TENM_JOYSTICK_RIGHT], -1);
389         }
390       }
391       else if (event.jaxis.axis == 1)
392       {
393         /* up/down (mutually exclusive) */
394         if (joystick_axis_set[TENM_JOYSTICK_UP])
395         {
396           if (event.jaxis.value < -neutral_range)
397             tenm_add_key_status(joystick_axis_mask[TENM_JOYSTICK_UP], 1);
398           else
399             tenm_add_key_status(joystick_axis_mask[TENM_JOYSTICK_UP], -1);
400         }
401         if (joystick_axis_set[TENM_JOYSTICK_DOWN])
402         {
403           if (event.jaxis.value > neutral_range)
404             tenm_add_key_status(joystick_axis_mask[TENM_JOYSTICK_DOWN], 1);
405           else
406             tenm_add_key_status(joystick_axis_mask[TENM_JOYSTICK_DOWN], -1);
407         }
408       }
409     }
410     else if (event.type == SDL_JOYBUTTONDOWN)
411     {
412       if ((joystick_button_set == NULL)
413           || (joystick_button_mask == NULL))
414       {
415         fprintf(stderr, "tenm_event_handle: SDL_JOYBUTTONDOWN event happened "
416                 "while joystick is not initialized, ignoring\n");
417         continue;
418       }
419 
420       /* event.jbutton.button is always nonnegative because it is unsigned */
421       if ((event.jbutton.button < TENM_NUMBER_KEY_MAX - 4)
422           && (joystick_button_set[event.jbutton.button]))
423         tenm_add_key_status(joystick_button_mask[event.jbutton.button], 1);
424     }
425     else if (event.type == SDL_JOYBUTTONUP)
426     {
427       if ((joystick_button_set == NULL)
428           || (joystick_button_mask == NULL))
429       {
430         fprintf(stderr, "tenm_event_handle: SDL_JOYBUTTONUP event happened "
431                 "while joystick is not initialized, ignoring\n");
432         continue;
433       }
434 
435       /* event.jbutton.button is always nonnegative because it is unsigned */
436       if ((event.jbutton.button < TENM_NUMBER_KEY_MAX - 4)
437           && (joystick_button_set[event.jbutton.button]))
438         tenm_add_key_status(joystick_button_mask[event.jbutton.button], -1);
439     }
440   }
441   return 0;
442 }
443 
444 /* positive delta means the key is pressed
445  * negative delta means the key is released
446  */
447 static int
tenm_add_key_status(tenm_key key,int delta)448 tenm_add_key_status(tenm_key key, int delta)
449 {
450   int i;
451   int value = 0;
452 
453   for (i = 0; i < number_key_mask; i++)
454     if (key == key_mask[i])
455       value = tenm_pow2(i);
456 
457   if (value == 0)
458   {
459     /* unknown key */
460     return 0;
461   }
462 
463   if (delta > 0)
464     key_status |= value;
465   else if (delta < 0)
466     key_status &= ~value;
467   else
468     return 1;
469   return 0;
470 }
471 
472 static void
tenm_key_quit(void)473 tenm_key_quit(void)
474 {
475   number_key_mask = 0;
476   if (key_mask != NULL)
477   {
478     free(key_mask);
479     key_mask = NULL;
480   }
481 }
482 
483 static void
tenm_joystick_quit(void)484 tenm_joystick_quit(void)
485 {
486   if (js != NULL)
487   {
488     SDL_JoystickClose(js);
489     js = NULL;
490   }
491   if (joystick_axis_set != NULL)
492   {
493     free(joystick_axis_set);
494     joystick_axis_set = NULL;
495   }
496   if (joystick_axis_mask != NULL)
497   {
498     free(joystick_axis_mask);
499     joystick_axis_mask = NULL;
500   }
501   if (joystick_button_set != NULL)
502   {
503     free(joystick_button_set);
504     joystick_button_set = NULL;
505   }
506   if (joystick_button_mask != NULL)
507   {
508     free(joystick_button_mask);
509     joystick_button_mask = NULL;
510   }
511   neutral_range = 8192;
512 
513   if (SDL_WasInit(SDL_INIT_JOYSTICK) != 0)
514     SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
515 }
516