source: libcaca/trunk/caca/event.c @ 596

Last change on this file since 596 was 553, checked in by Sam Hocevar, 15 years ago
  • Fixed async issues between the driver and libcaca when resizing windows, and simplified the handle_resize() API. Still can be polished.
  • Property svn:keywords set to Id
File size: 6.8 KB
Line 
1/*
2 *  libcaca       ASCII-Art library
3 *  Copyright (c) 2002-2006 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 Do What The Fuck You Want To
8 *  Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12/** \file event.c
13 *  \version \$Id: event.c 553 2006-03-08 19:41:53Z sam $
14 *  \author Sam Hocevar <sam@zoy.org>
15 *  \brief Event handling
16 *
17 *  This file contains event handling functions for keyboard and mouse input.
18 */
19
20#include "config.h"
21
22#include "cucul.h"
23#include "cucul_internals.h"
24#include "caca.h"
25#include "caca_internals.h"
26
27static unsigned int _get_next_event(caca_t *);
28static unsigned int _lowlevel_event(caca_t *);
29#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
30void _push_event(caca_t *, unsigned int);
31unsigned int _pop_event(caca_t *);
32#endif
33
34#if !defined(_DOXYGEN_SKIP_ME)
35/* If no new key was pressed after AUTOREPEAT_THRESHOLD usec, assume the
36 * key was released */
37#define AUTOREPEAT_THRESHOLD 200000
38/* Start repeating key after AUTOREPEAT_TRIGGER usec and send keypress
39 * events every AUTOREPEAT_RATE usec. */
40#define AUTOREPEAT_TRIGGER 300000
41#define AUTOREPEAT_RATE 100000
42#endif
43
44/** \brief Get the next mouse or keyboard input event.
45 *
46 *  This function polls the event queue for mouse or keyboard events matching
47 *  the event mask and returns the first matching event. Non-matching events
48 *  are discarded. \c event_mask must have a non-zero value. This function is
49 *  non-blocking and returns zero if no more events are pending in the queue.
50 *  See also caca_wait_event() for a blocking version of this function.
51 *
52 * \param event_mask Bitmask of requested events.
53 * \return The next matching event in the queue, or 0 if no event is pending.
54 */
55unsigned int caca_get_event(caca_t *kk, unsigned int event_mask)
56{
57    if(!event_mask)
58        return CACA_EVENT_NONE;
59
60    for( ; ; )
61    {
62        unsigned int event = _get_next_event(kk);
63
64        if(!event || event & event_mask)
65            return event;
66    }
67}
68
69/** \brief Wait for the next mouse or keyboard input event.
70 *
71 *  This function returns the first mouse or keyboard event in the queue
72 *  that matches the event mask. If no event is pending, it blocks until a
73 *  matching event is received. \c event_mask must have a non-zero value.
74 *  See also caca_get_event() for a non-blocking version of this function.
75 *
76 *  \param event_mask Bitmask of requested events.
77 *  \return The next event in the queue.
78 */
79unsigned int caca_wait_event(caca_t *kk, unsigned int event_mask)
80{
81    if(!event_mask)
82        return CACA_EVENT_NONE;
83
84    for( ; ; )
85    {
86        unsigned int event = _get_next_event(kk);
87
88        if(event & event_mask)
89            return event;
90
91        _caca_sleep(10000);
92    }
93}
94
95/** \brief Return the X mouse coordinate.
96 *
97 *  This function returns the X coordinate of the mouse position last time
98 *  it was detected. This function is not reliable if the ncurses or S-Lang
99 *  drivers are being used, because mouse position is only detected when
100 *  the mouse is clicked. Other drivers such as X11 work well.
101 *
102 *  \return The X mouse coordinate.
103 */
104unsigned int caca_get_mouse_x(caca_t *kk)
105{
106    if(kk->mouse.x >= kk->qq->width)
107        kk->mouse.x = kk->qq->width - 1;
108
109    return kk->mouse.x;
110}
111
112/** \brief Return the Y mouse coordinate.
113 *
114 *  This function returns the Y coordinate of the mouse position last time
115 *  it was detected. This function is not reliable if the ncurses or S-Lang
116 *  drivers are being used, because mouse position is only detected when
117 *  the mouse is clicked. Other drivers such as X11 work well.
118 *
119 *  \return The Y mouse coordinate.
120 */
121unsigned int caca_get_mouse_y(caca_t *kk)
122{
123    if(kk->mouse.y >= kk->qq->height)
124        kk->mouse.y = kk->qq->height - 1;
125
126    return kk->mouse.y;
127}
128
129/*
130 * XXX: The following functions are local.
131 */
132
133static unsigned int _get_next_event(caca_t *kk)
134{
135#if defined(USE_SLANG) || defined(USE_NCURSES)
136    unsigned int ticks;
137#endif
138    unsigned int event;
139
140    /* If we are about to return a resize event, acknowledge it */
141    if(kk->resize.resized)
142    {
143        kk->resize.resized = 0;
144        _caca_handle_resize(kk);
145        return CACA_EVENT_RESIZE;
146    }
147
148    event = _lowlevel_event(kk);
149
150#if defined(USE_SLANG)
151    if(kk->drv.driver != CACA_DRIVER_SLANG)
152#endif
153#if defined(USE_NCURSES)
154    if(kk->drv.driver != CACA_DRIVER_NCURSES)
155#endif
156    return event;
157
158#if defined(USE_SLANG) || defined(USE_NCURSES)
159    /* Simulate long keypresses using autorepeat features */
160    ticks = _caca_getticks(&kk->events.key_timer);
161    kk->events.last_key_ticks += ticks;
162    kk->events.autorepeat_ticks += ticks;
163
164    /* Handle autorepeat */
165    if(kk->events.last_key
166           && kk->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
167           && kk->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
168           && kk->events.autorepeat_ticks > AUTOREPEAT_RATE)
169    {
170        _push_event(kk, event);
171        kk->events.autorepeat_ticks -= AUTOREPEAT_RATE;
172        return CACA_EVENT_KEY_PRESS | kk->events.last_key;
173    }
174
175    /* We are in autorepeat mode and the same key was just pressed, ignore
176     * this event and return the next one by calling ourselves. */
177    if(event == (CACA_EVENT_KEY_PRESS | kk->events.last_key))
178    {
179        kk->events.last_key_ticks = 0;
180        return _get_next_event(kk);
181    }
182
183    /* We are in autorepeat mode, but key has expired or a new key was
184     * pressed - store our event and return a key release event first */
185    if(kk->events.last_key
186          && (kk->events.last_key_ticks > AUTOREPEAT_THRESHOLD
187               || (event & CACA_EVENT_KEY_PRESS)))
188    {
189        _push_event(kk, event);
190        event = CACA_EVENT_KEY_RELEASE | kk->events.last_key;
191        kk->events.last_key = 0;
192        return event;
193    }
194
195    /* A new key was pressed, enter autorepeat mode */
196    if(event & CACA_EVENT_KEY_PRESS)
197    {
198        kk->events.last_key_ticks = 0;
199        kk->events.autorepeat_ticks = 0;
200        kk->events.last_key = event & 0x00ffffff;
201    }
202
203    return event;
204#endif
205}
206
207static unsigned int _lowlevel_event(caca_t *kk)
208{
209#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
210    unsigned int event = _pop_event(kk);
211
212    if(event)
213        return event;
214#endif
215
216    return kk->drv.get_event(kk);
217}
218
219#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
220void _push_event(caca_t *kk, unsigned int event)
221{
222    if(!event || kk->events.queue == EVENTBUF_LEN)
223        return;
224    kk->events.buf[kk->events.queue] = event;
225    kk->events.queue++;
226}
227
228unsigned int _pop_event(caca_t *kk)
229{
230    int i;
231    unsigned int event;
232
233    if(kk->events.queue == 0)
234        return CACA_EVENT_NONE;
235
236    event = kk->events.buf[0];
237    for(i = 1; i < kk->events.queue; i++)
238        kk->events.buf[i - 1] = kk->events.buf[i];
239    kk->events.queue--;
240
241    return event;
242}
243#endif
244
Note: See TracBrowser for help on using the repository browser.