source: libcaca/trunk/src/io.c @ 329

Last change on this file since 329 was 329, checked in by Sam Hocevar, 17 years ago
  • src/io.c: + Use SLkp_getkey instead of SLang_getkey so that escape sequences are

directly interpreted.

+ Major rehandling of the event code. All output drivers are now

correctly separated.

  • src/graphics.c: + Fixed a compilation warning.
  • test/event.c: + More human-readable event printing.
  • Property svn:keywords set to Id
File size: 15.4 KB
Line 
1/*
2 *  libcaca       ASCII-Art library
3 *  Copyright (c) 2002, 2003 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the GNU Lesser General Public
8 *  License as published by the Free Software Foundation; either
9 *  version 2 of the License, or (at your option) any later version.
10 *
11 *  This library is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *  Lesser General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Lesser General Public
17 *  License along with this library; if not, write to the Free Software
18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 *  02111-1307  USA
20 */
21
22/** \file io.c
23 *  \version \$Id: io.c 329 2004-01-08 10:22:14Z sam $
24 *  \author Sam Hocevar <sam@zoy.org>
25 *  \brief Event handling
26 *
27 *  This file contains event handling functions for keyboard and mouse input.
28 */
29
30#include "config.h"
31
32#if defined(USE_SLANG)
33#   if defined(HAVE_SLANG_SLANG_H)
34#       include <slang/slang.h>
35#   else
36#       include <slang.h>
37#   endif
38#endif
39#if defined(USE_NCURSES)
40#   include <curses.h>
41#endif
42#if defined(USE_CONIO)
43#   include <conio.h>
44#endif
45#if defined(USE_X11)
46#   include <X11/Xlib.h>
47#   include <X11/Xutil.h>
48#   include <X11/keysym.h>
49#endif
50
51#include <unistd.h>
52
53#include "caca.h"
54#include "caca_internals.h"
55
56static unsigned int _get_next_event(void);
57static void _push_event(unsigned int);
58static unsigned int _pop_event(void);
59
60#if !defined(_DOXYGEN_SKIP_ME)
61#define EVENTBUF_LEN 10
62#endif
63static unsigned int eventbuf[EVENTBUF_LEN];
64static int events = 0;
65
66/** \brief Get the next mouse or keyboard input event.
67 *
68 *  This function polls the event queue for mouse or keyboard events matching
69 *  the event mask and returns the first matching event. Non-matching events
70 *  are discarded. It is non-blocking and returns zero if no more events are
71 *  pending in the queue. See also caca_wait_event() for a blocking version
72 *  of this function.
73 *
74 * \param event_mask Bitmask of requested events.
75 * \return The next matching event in the queue, or 0 if no event is pending.
76 */
77unsigned int caca_get_event(unsigned int event_mask)
78{
79    for( ; ; )
80    {
81        unsigned int event = _get_next_event();
82
83        if(!event || event & event_mask)
84            return event;
85    }
86}
87
88/** \brief Wait for the next mouse or keyboard input event.
89 *
90 *  This function returns the first mouse or keyboard event in the queue
91 *  that matches the event mask. If no event is pending, it blocks until a
92 *  matching event is received. See also caca_get_event() for a non-blocking
93 *  version of this function.
94 *
95 *  \param event_mask Bitmask of requested events.
96 *  \return The next event in the queue.
97 */
98unsigned int caca_wait_event(unsigned int event_mask)
99{
100    for( ; ; )
101    {
102        unsigned int event = _get_next_event();
103
104        if(event & event_mask)
105            return event;
106
107        usleep(1000);
108    }
109}
110
111/*
112 * XXX: The following functions are local.
113 */
114
115static unsigned int _get_next_event(void)
116{
117    unsigned int event = _pop_event();
118
119    if(event)
120        return event;
121
122#if defined(USE_X11)
123    /* The X11 event check routine */
124    if(_caca_driver == CACA_DRIVER_X11)
125    {
126        XEvent xevent;
127        static unsigned int x11_x = 0, x11_y = 0;
128        long int xevent_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask
129                                | ButtonReleaseMask | PointerMotionMask;
130        char key;
131
132        while(XCheckWindowEvent(x11_dpy, x11_window, xevent_mask, &xevent)
133               == True)
134        {
135            KeySym keysym;
136
137            /* Check for mouse motion events */
138            if(xevent.type == MotionNotify)
139            {
140                unsigned int newx = xevent.xmotion.x / x11_font_width;
141                unsigned int newy = xevent.xmotion.y / x11_font_height;
142
143                if(newx >= _caca_width)
144                    newx = _caca_width - 1;
145                if(newy >= _caca_height)
146                    newy = _caca_height - 1;
147
148                if(x11_x == newx && x11_y == newy)
149                    continue;
150
151                x11_x = newx & 0xfff;
152                x11_y = newy & 0xfff;
153
154                return CACA_EVENT_MOUSE_MOTION | (newx << 12) | (newy << 0);
155            }
156
157            /* Check for mouse press and release events */
158            if(xevent.type == ButtonPress)
159                return CACA_EVENT_MOUSE_PRESS
160                        | ((XButtonEvent *)&xevent)->button;
161
162            if(xevent.type == ButtonRelease)
163                return CACA_EVENT_MOUSE_RELEASE
164                        | ((XButtonEvent *)&xevent)->button;
165
166            /* Check for key press and release events */
167            if(xevent.type == KeyPress)
168                event |= CACA_EVENT_KEY_PRESS;
169            else if(xevent.type == KeyRelease)
170                event |= CACA_EVENT_KEY_RELEASE;
171            else
172                continue;
173
174            if(XLookupString(&xevent.xkey, &key, 1, NULL, NULL))
175                return event | key;
176
177            keysym = XKeycodeToKeysym(x11_dpy, xevent.xkey.keycode, 0);
178            switch(keysym)
179            {
180            case XK_F1:    return event | CACA_KEY_F1;
181            case XK_F2:    return event | CACA_KEY_F2;
182            case XK_F3:    return event | CACA_KEY_F3;
183            case XK_F4:    return event | CACA_KEY_F4;
184            case XK_F5:    return event | CACA_KEY_F5;
185            case XK_F6:    return event | CACA_KEY_F6;
186            case XK_F7:    return event | CACA_KEY_F7;
187            case XK_F8:    return event | CACA_KEY_F8;
188            case XK_F9:    return event | CACA_KEY_F9;
189            case XK_F10:   return event | CACA_KEY_F10;
190            case XK_F11:   return event | CACA_KEY_F11;
191            case XK_F12:   return event | CACA_KEY_F12;
192            case XK_F13:   return event | CACA_KEY_F13;
193            case XK_F14:   return event | CACA_KEY_F14;
194            case XK_F15:   return event | CACA_KEY_F15;
195            case XK_Left:  return event | CACA_KEY_LEFT;
196            case XK_Right: return event | CACA_KEY_RIGHT;
197            case XK_Up:    return event | CACA_KEY_UP;
198            case XK_Down:  return event | CACA_KEY_DOWN;
199            default:       return 0;
200            }
201        }
202
203        return 0;
204    }
205    else
206#endif
207#if defined(USE_NCURSES)
208    if(_caca_driver == CACA_DRIVER_NCURSES)
209    {
210        int intkey = getch();
211        if(intkey == ERR)
212            return 0;
213
214        if(intkey < 0x100)
215        {
216            _push_event(CACA_EVENT_KEY_RELEASE | intkey);
217            return CACA_EVENT_KEY_PRESS | intkey;
218        }
219
220        if(intkey == KEY_MOUSE)
221        {
222            MEVENT mevent;
223            getmouse(&mevent);
224
225            switch(mevent.bstate)
226            {
227                case BUTTON1_PRESSED:
228                    _push_event(CACA_EVENT_MOUSE_PRESS | 1);
229                    break;
230                case BUTTON1_RELEASED:
231                    _push_event(CACA_EVENT_MOUSE_RELEASE | 1);
232                    break;
233                case BUTTON1_CLICKED:
234                    _push_event(CACA_EVENT_MOUSE_PRESS | 1);
235                    _push_event(CACA_EVENT_MOUSE_RELEASE | 1);
236                    break;
237                case BUTTON1_DOUBLE_CLICKED:
238                    _push_event(CACA_EVENT_MOUSE_PRESS | 1);
239                    _push_event(CACA_EVENT_MOUSE_RELEASE | 1);
240                    _push_event(CACA_EVENT_MOUSE_PRESS | 1);
241                    _push_event(CACA_EVENT_MOUSE_RELEASE | 1);
242                    break;
243                case BUTTON1_TRIPLE_CLICKED:
244                    _push_event(CACA_EVENT_MOUSE_PRESS | 1);
245                    _push_event(CACA_EVENT_MOUSE_RELEASE | 1);
246                    _push_event(CACA_EVENT_MOUSE_PRESS | 1);
247                    _push_event(CACA_EVENT_MOUSE_RELEASE | 1);
248                    _push_event(CACA_EVENT_MOUSE_PRESS | 1);
249                    _push_event(CACA_EVENT_MOUSE_RELEASE | 1);
250                    break;
251                case BUTTON1_RESERVED_EVENT:
252                    break;
253
254                case BUTTON2_PRESSED:
255                    _push_event(CACA_EVENT_MOUSE_PRESS | 2);
256                    break;
257                case BUTTON2_RELEASED:
258                    _push_event(CACA_EVENT_MOUSE_RELEASE | 2);
259                    break;
260                case BUTTON2_CLICKED:
261                    _push_event(CACA_EVENT_MOUSE_PRESS | 2);
262                    _push_event(CACA_EVENT_MOUSE_RELEASE | 2);
263                    break;
264                case BUTTON2_DOUBLE_CLICKED:
265                    _push_event(CACA_EVENT_MOUSE_PRESS | 2);
266                    _push_event(CACA_EVENT_MOUSE_RELEASE | 2);
267                    _push_event(CACA_EVENT_MOUSE_PRESS | 2);
268                    _push_event(CACA_EVENT_MOUSE_RELEASE | 2);
269                    break;
270                case BUTTON2_TRIPLE_CLICKED:
271                    _push_event(CACA_EVENT_MOUSE_PRESS | 2);
272                    _push_event(CACA_EVENT_MOUSE_RELEASE | 2);
273                    _push_event(CACA_EVENT_MOUSE_PRESS | 2);
274                    _push_event(CACA_EVENT_MOUSE_RELEASE | 2);
275                    _push_event(CACA_EVENT_MOUSE_PRESS | 2);
276                    _push_event(CACA_EVENT_MOUSE_RELEASE | 2);
277                    break;
278                case BUTTON2_RESERVED_EVENT:
279                    break;
280
281                case BUTTON3_PRESSED:
282                    _push_event(CACA_EVENT_MOUSE_PRESS | 3);
283                    break;
284                case BUTTON3_RELEASED:
285                    _push_event(CACA_EVENT_MOUSE_RELEASE | 3);
286                    break;
287                case BUTTON3_CLICKED:
288                    _push_event(CACA_EVENT_MOUSE_PRESS | 3);
289                    _push_event(CACA_EVENT_MOUSE_RELEASE | 3);
290                    break;
291                case BUTTON3_DOUBLE_CLICKED:
292                    _push_event(CACA_EVENT_MOUSE_PRESS | 3);
293                    _push_event(CACA_EVENT_MOUSE_RELEASE | 3);
294                    _push_event(CACA_EVENT_MOUSE_PRESS | 3);
295                    _push_event(CACA_EVENT_MOUSE_RELEASE | 3);
296                    break;
297                case BUTTON3_TRIPLE_CLICKED:
298                    _push_event(CACA_EVENT_MOUSE_PRESS | 3);
299                    _push_event(CACA_EVENT_MOUSE_RELEASE | 3);
300                    _push_event(CACA_EVENT_MOUSE_PRESS | 3);
301                    _push_event(CACA_EVENT_MOUSE_RELEASE | 3);
302                    _push_event(CACA_EVENT_MOUSE_PRESS | 3);
303                    _push_event(CACA_EVENT_MOUSE_RELEASE | 3);
304                    break;
305                case BUTTON3_RESERVED_EVENT:
306                    break;
307
308                case BUTTON4_PRESSED:
309                    _push_event(CACA_EVENT_MOUSE_PRESS | 4);
310                    break;
311                case BUTTON4_RELEASED:
312                    _push_event(CACA_EVENT_MOUSE_RELEASE | 4);
313                    break;
314                case BUTTON4_CLICKED:
315                    _push_event(CACA_EVENT_MOUSE_PRESS | 4);
316                    _push_event(CACA_EVENT_MOUSE_RELEASE | 4);
317                    break;
318                case BUTTON4_DOUBLE_CLICKED:
319                    _push_event(CACA_EVENT_MOUSE_PRESS | 4);
320                    _push_event(CACA_EVENT_MOUSE_RELEASE | 4);
321                    _push_event(CACA_EVENT_MOUSE_PRESS | 4);
322                    _push_event(CACA_EVENT_MOUSE_RELEASE | 4);
323                    break;
324                case BUTTON4_TRIPLE_CLICKED:
325                    _push_event(CACA_EVENT_MOUSE_PRESS | 4);
326                    _push_event(CACA_EVENT_MOUSE_RELEASE | 4);
327                    _push_event(CACA_EVENT_MOUSE_PRESS | 4);
328                    _push_event(CACA_EVENT_MOUSE_RELEASE | 4);
329                    _push_event(CACA_EVENT_MOUSE_PRESS | 4);
330                    _push_event(CACA_EVENT_MOUSE_RELEASE | 4);
331                    break;
332                case BUTTON4_RESERVED_EVENT:
333                    break;
334
335                default:
336                    break;
337            }
338
339            return CACA_EVENT_MOUSE_MOTION | (mevent.x << 12) | mevent.y;
340        }
341
342        switch(intkey)
343        {
344            case KEY_UP: event = CACA_KEY_UP; break;
345            case KEY_DOWN: event = CACA_KEY_DOWN; break;
346            case KEY_LEFT: event = CACA_KEY_LEFT; break;
347            case KEY_RIGHT: event = CACA_KEY_RIGHT; break;
348
349            case KEY_F(1): event = CACA_KEY_F1; break;
350            case KEY_F(2): event = CACA_KEY_F2; break;
351            case KEY_F(3): event = CACA_KEY_F3; break;
352            case KEY_F(4): event = CACA_KEY_F4; break;
353            case KEY_F(5): event = CACA_KEY_F5; break;
354            case KEY_F(6): event = CACA_KEY_F6; break;
355            case KEY_F(7): event = CACA_KEY_F7; break;
356            case KEY_F(8): event = CACA_KEY_F8; break;
357            case KEY_F(9): event = CACA_KEY_F9; break;
358            case KEY_F(10): event = CACA_KEY_F10; break;
359            case KEY_F(11): event = CACA_KEY_F11; break;
360            case KEY_F(12): event = CACA_KEY_F12; break;
361        }
362
363        _push_event(CACA_EVENT_KEY_RELEASE | event);
364        return CACA_EVENT_KEY_PRESS | event;
365    }
366    else
367#endif
368#if defined(USE_SLANG)
369    if(_caca_driver == CACA_DRIVER_SLANG)
370    {
371        int intkey;
372
373        if(!SLang_input_pending(0))
374            return 0;
375
376        intkey = SLkp_getkey();
377
378        if(intkey < 0x100)
379        {
380            _push_event(CACA_EVENT_KEY_RELEASE | intkey);
381            return CACA_EVENT_KEY_PRESS | intkey;
382        }
383
384        if(intkey == 0x3e9)
385        {
386            int button = (SLang_getkey() - ' ' + 1) & 0xf;
387            int x = SLang_getkey() - '!';
388            int y = SLang_getkey() - '!';
389            _push_event(CACA_EVENT_MOUSE_PRESS | button);
390            _push_event(CACA_EVENT_MOUSE_RELEASE | button);
391            return CACA_EVENT_MOUSE_MOTION | (x << 12) | (y << 0);
392        }
393
394        switch(intkey)
395        {
396            case SL_KEY_UP: event = CACA_KEY_UP; break;
397            case SL_KEY_DOWN: event = CACA_KEY_DOWN; break;
398            case SL_KEY_LEFT: event = CACA_KEY_LEFT; break;
399            case SL_KEY_RIGHT: event = CACA_KEY_RIGHT; break;
400
401            case SL_KEY_F(1): event = CACA_KEY_F1; break;
402            case SL_KEY_F(2): event = CACA_KEY_F2; break;
403            case SL_KEY_F(3): event = CACA_KEY_F3; break;
404            case SL_KEY_F(4): event = CACA_KEY_F4; break;
405            case SL_KEY_F(5): event = CACA_KEY_F5; break;
406            case SL_KEY_F(6): event = CACA_KEY_F6; break;
407            case SL_KEY_F(7): event = CACA_KEY_F7; break;
408            case SL_KEY_F(8): event = CACA_KEY_F8; break;
409            case SL_KEY_F(9): event = CACA_KEY_F9; break;
410            case SL_KEY_F(10): event = CACA_KEY_F10; break;
411            case SL_KEY_F(11): event = CACA_KEY_F11; break;
412            case SL_KEY_F(12): event = CACA_KEY_F12; break;
413        }
414
415        _push_event(CACA_EVENT_KEY_RELEASE | event);
416        return CACA_EVENT_KEY_PRESS | event;
417    }
418    else
419#endif
420#if defined(USE_CONIO)
421    if(_caca_driver == CACA_DRIVER_CONIO)
422    {
423        if(!_conio_kbhit())
424            return 0;
425
426        event = getch();
427        _push_event(CACA_EVENT_KEY_RELEASE | event);
428        return CACA_EVENT_KEY_PRESS | event;
429    }
430    else
431#endif
432    {
433        /* Dummy */
434    }
435
436    return 0;
437}
438
439static void _push_event(unsigned int event)
440{
441    if(events == EVENTBUF_LEN)
442        return;
443    eventbuf[events] = event;
444    events++;
445}
446
447static unsigned int _pop_event(void)
448{
449    int i;
450    unsigned int event;
451
452    if(events == 0)
453        return 0;
454
455    event = eventbuf[0];
456    for(i = 1; i < events; i++)
457        eventbuf[i - 1] = eventbuf[i];
458    events--;
459
460    return event;
461}
462
Note: See TracBrowser for help on using the repository browser.