OSDN Git Service

a90548b35da37369af77070992901ccf0aae9871
[nazghul-jp/nazghul-jp.git] / src / event.c
1 //
2 // nazghul - an old-school RPG engine
3 // Copyright (C) 2002, 2003 Gordon McNutt
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 2 of the License, or (at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 // more details.
14 //
15 // You should have received a copy of the GNU General Public License along with
16 // this program; if not, write to the Free Foundation, Inc., 59 Temple Place,
17 // Suite 330, Boston, MA 02111-1307 USA
18 //
19 // Gordon McNutt
20 // gmcnutt@users.sourceforge.net
21 //
22 #include "event.h"
23 #include "cfg.h"
24
25 #include <SDL.h>
26 #include <ctype.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <common.h>
33
34 #ifndef DEBUG_KEYS
35 # define DEBUG_KEYS 0
36 #endif
37
38 #define EVENT_NONBLOCK   (1 << 0)
39 #define EVENT_NOPLAYBACK (1 << 1)
40
41 #define getHandler(stack,type) \
42   (list_empty((stack)) ? NULL : (type*)(stack)->next)
43 #define pushHandler(stack,handler) (list_add((stack), &(handler)->list))
44
45 typedef struct {
46         struct list list;
47         SDL_Event event;
48 } sdl_event_list_t;
49
50 static struct list KeyHandlers;
51 static struct list TickHandlers;
52 static struct list QuitHandlers;
53 static struct list MouseButtonHandlers;
54 static struct list MouseMotionHandlers;
55 static struct list backlog;
56
57 static bool record_events;
58 static int record_fd;
59 static bool playback_events;
60 static int playback_fd;
61 static int event_playback_speed = 0;
62
63 static void (*eventHook) (void);
64 static int (*wait_event) (SDL_Event * event, int flags);
65 static int qcount = 0;
66
67 static struct list *popHandler(struct list *stack) 
68 {
69         if (list_empty(stack)) {
70                 return NULL;
71         }
72
73         struct list *lptr = stack->next;
74         list_remove(lptr);
75         return lptr;
76 }
77
78 static void backlog_enqueue(SDL_Event *event)
79 {
80         sdl_event_list_t *elem = (sdl_event_list_t*)malloc(sizeof(*elem));
81         elem->event = *event;
82         list_add(&backlog, &elem->list);
83         qcount++;
84 }
85
86 static int backlog_dequeue(SDL_Event *event)
87 {
88         sdl_event_list_t *elem;
89         struct list *ptr;
90         if (list_empty(&backlog))
91                 return -1;
92         ptr = backlog.next;
93         elem = outcast(ptr, sdl_event_list_t, list);
94         list_remove(&elem->list);
95         *event = elem->event;
96         free(elem);
97         qcount--;
98         return 0;
99 }
100
101 static int mapKey(SDL_keysym * keysym)
102 {
103         int key = keysym->sym;
104         
105         if (DEBUG_KEYS) {
106                 printf("sym='%c'[%d] mod=%02x unicode=%04x\n", 
107                        keysym->sym,  
108                        keysym->sym,
109                        keysym->mod,
110                        keysym->unicode);
111         }
112
113         /* If the key has a UNICODE representation and its from the default
114          * Basic Latin code page then return it as an ASCII character. */
115         /* fixme: unicode is messing up ctrl+key sequences */
116         if (keysym->unicode) {
117
118                 /* Map CR to LF (legacy code expects this) */
119                 if (keysym->unicode == 0x000d)
120                         return '\n';
121
122                 /* Map all other Basic Latin codes to ASCII */
123                 if (keysym->unicode < 0x7f)
124                         return keysym->unicode & 0x7f;
125
126                 /* Code page not supported... fall through */
127         }
128
129         /* Map arrow keys to equivalent numberpad entries */
130         if (key >= SDLK_UP && key <= SDLK_LEFT) {
131                 static int map[] = { KEY_NORTH, KEY_SOUTH, KEY_EAST, 
132                                      KEY_WEST };
133                 key = map[key - SDLK_UP];
134         }
135
136         /* Set the "shift" bit */
137         if (keysym->mod & KMOD_SHIFT) {
138                 key |= KEY_SHIFT;
139         }
140
141         /* Unsupported? fallback to the SDL sym */
142         return key;
143 }
144
145 static int event_get_next_event(SDL_Event *event, int flags)
146 {
147         /* if a key handler exists */
148         if (getHandler(&KeyHandlers, struct KeyHandler)) {
149
150                 /* if the backlog queue is not empty */
151                 if (! backlog_dequeue(event)) {
152
153                         /* get the event from the backlog queue */
154                         return 1;
155                 }
156         }
157
158         if (flags & EVENT_NONBLOCK)
159                 return SDL_PollEvent(event);
160         else
161                 return SDL_WaitEvent(event);
162 }
163
164 static int playback_event(SDL_Event * event, int flags)
165 {
166         // For now use the expedient but non-portable technique of reading the
167         // binary data straight to the file.
168         int n;
169         int len = sizeof(SDL_Event);
170         char *ptr = (char *) event;
171
172         if (flags & EVENT_NOPLAYBACK)
173                 return 0;
174
175
176         while (len) {
177                 n = read(playback_fd, ptr, len);
178                 if (n == -1) {
179                         perror("read");
180                         return -1;
181                 }
182                 ptr += n;
183                 len -= n;
184         }
185
186         SDL_Delay(event_playback_speed);
187
188         return 1;
189 }
190
191 static void record_event(SDL_Event * event)
192 {
193         // For now use the expedient but non-portable technique of writing the
194         // binary data straight to the file.
195         int n;
196         int len = sizeof(SDL_Event);
197         char *ptr = (char *) event;
198         while (len) {
199                 n = write(record_fd, ptr, len);
200                 if (n == -1) {
201                         perror("write");
202                         return;
203                 }
204                 ptr += n;
205                 len -= n;
206         }
207 }
208
209 static void event_handle_aux(int flags)
210 {
211         bool done = false;
212         bool use_hook = false;
213
214         while (!done) {
215
216                 SDL_Event event;
217                 if (!wait_event(&event, flags)) {
218                         return;
219                 }
220                 if (record_events)
221                         record_event(&event);
222
223                 switch (event.type) {
224
225                 case SDL_USEREVENT:
226                         {
227                                 struct TickHandler *tickh;
228                                 tickh = getHandler(&TickHandlers,
229                                                    struct TickHandler);
230                                 if (tickh) {
231                                         use_hook = true;
232                                         if (tickh->fx(tickh)) {
233                                                 done = true;
234                                         }
235                                 }
236                                 
237                         }
238                         break;
239
240                 case SDL_KEYDOWN:
241                         {
242                                 struct KeyHandler *keyh;
243                                 keyh = getHandler(&KeyHandlers, 
244                                                   struct KeyHandler);
245                                 if (keyh) {
246                                         int mapped_key = 
247                                                 mapKey(&event.key.keysym);
248                                         use_hook = true;
249                                         if (keyh->fx(keyh, mapped_key, 
250                                                      event.key.keysym.mod)) {
251                                                 done = true;
252                                         }
253                                 } else {
254                                         /* enqueue this event */
255                                         backlog_enqueue(&event);
256                                 }
257                         }
258                         break;
259
260                 case SDL_QUIT:
261                         {
262                                 struct QuitHandler *quith;
263                                 quith =
264                                     getHandler(&QuitHandlers,
265                                                struct QuitHandler);
266                                 if (quith && quith->fx(quith))
267                                         done = true;
268                         }
269                         break;
270
271                 case SDL_MOUSEBUTTONDOWN:
272                         {
273                                 struct MouseButtonHandler *mouseh;
274                                 mouseh = getHandler(&MouseButtonHandlers,
275                                                     struct MouseButtonHandler);
276                                 if (mouseh &&
277                                     mouseh->fx(mouseh, &event.button)) {
278                                         done = true;
279                                 }
280                         }
281                         break;
282
283                 case SDL_MOUSEMOTION:
284                         {
285                                 struct MouseMotionHandler *mouseh;
286                                 mouseh = getHandler(&MouseMotionHandlers,
287                                                     struct MouseMotionHandler);
288                                 if (mouseh &&
289                                     mouseh->fx(mouseh, &event.motion)) {
290                                         done = true;
291                                 }
292                         }
293                         break;
294
295                 default:
296                         break;
297                 }
298
299                 if (use_hook && eventHook)
300                         eventHook();
301
302         }
303
304 }
305
306 int eventInit(void)
307 {
308         char *record_fname = cfg_get("record-filename");
309         char *playback_fname = cfg_get("playback-filename");
310
311         list_init(&KeyHandlers);
312         list_init(&TickHandlers);
313         list_init(&QuitHandlers);
314         list_init(&MouseButtonHandlers);
315         list_init(&MouseMotionHandlers);
316         list_init(&backlog);
317         eventHook = NULL;
318         wait_event = event_get_next_event;
319         qcount=0;
320
321         if (record_fname != NULL) {
322                 record_events = true;
323                 record_fd = open(record_fname, O_WRONLY | O_CREAT, 00666);
324                 if (record_fd == -1) {
325                         perror(record_fname);
326                         return -1;
327                 }
328         }
329
330         if (playback_fname != NULL) {
331                 char *playback_spd_str = cfg_get("playback-speed");
332                 playback_events = true;
333                 playback_fd = open(playback_fname, O_RDONLY, 00666);
334                 if (playback_fd == -1) {
335                         perror(playback_fname);
336                         return -1;
337                 }
338                 // Override the normal wait_event routine
339                 wait_event = playback_event;
340
341                 /* Set the play back speed. */
342                 if (playback_spd_str) {
343                         event_playback_speed = atoi(playback_spd_str);
344                 }
345         }
346
347         SDL_EnableUNICODE(1);
348
349         return 0;
350 }
351
352 void eventExit(void)
353 {
354         /* cleanup the backlog queue */
355         SDL_Event event;
356         while (! backlog_dequeue(&event))
357                 ;
358 }
359
360 void eventHandle(void)
361 {
362         event_handle_aux(0);
363 }
364
365 void eventHandlePending(void)
366 {
367         event_handle_aux(EVENT_NONBLOCK|EVENT_NOPLAYBACK);
368 }
369
370 void eventPushKeyHandler(struct KeyHandler *keyh)
371 {
372         pushHandler(&KeyHandlers, keyh);
373 }
374
375 struct KeyHandler * eventPopKeyHandler(void)
376 {
377         return (struct KeyHandler*)popHandler(&KeyHandlers);
378 }
379
380 void eventPushTickHandler(struct TickHandler *keyh)
381 {
382         pushHandler(&TickHandlers, keyh);
383 }
384
385 void eventPopTickHandler(void)
386 {
387         popHandler(&TickHandlers);
388 }
389
390 void eventPushQuitHandler(struct QuitHandler *keyh)
391 {
392         pushHandler(&QuitHandlers, keyh);
393 }
394
395 void eventPopQuitHandler(void)
396 {
397         popHandler(&QuitHandlers);
398 }
399
400 void eventPushMouseButtonHandler(struct MouseButtonHandler *keyh)
401 {
402         pushHandler(&MouseButtonHandlers, keyh);
403 }
404
405 void eventPopMouseButtonHandler(void)
406 {
407         popHandler(&MouseButtonHandlers);
408 }
409
410 void eventPushMouseMotionHandler(struct MouseMotionHandler *keyh)
411 {
412         pushHandler(&MouseMotionHandlers, keyh);
413 }
414
415 void eventPopMouseMotionHandler(void)
416 {
417         popHandler(&MouseMotionHandlers);
418 }
419
420 void eventAddHook(void (*fx) (void))
421 {
422         eventHook = fx;
423 }
424
425 void eventRunKeyHandler(key_handler_fx_t fx, void *data)
426 {
427         struct KeyHandler kh;
428         kh.fx = fx;
429         kh.data = data;
430         eventPushKeyHandler(&kh);
431         eventHandle();
432         eventPopKeyHandler();
433 }