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