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

Last change on this file since 3486 was 3486, checked in by Sam Hocevar, 11 years ago

Increased the autorepeat delay in the ncurses and SLang drivers. Now that
we have dirty rectangles, fast autorepeat becomes perfectly usable.

  • Property svn:keywords set to Id
File size: 13.7 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: event.c 3486 2009-05-19 21:41:44Z sam $
7 *
8 *  This library is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  This file contains event handling functions for keyboard and mouse input.
17 */
18
19#include "config.h"
20
21#if !defined(__KERNEL__)
22#   include <stdio.h>
23#   include <string.h>
24#endif
25
26#include "caca.h"
27#include "caca_internals.h"
28
29static int _get_next_event(caca_display_t *, caca_privevent_t *);
30static int _lowlevel_event(caca_display_t *, caca_privevent_t *);
31
32#if !defined(_DOXYGEN_SKIP_ME)
33/* If no new key was pressed after AUTOREPEAT_THRESHOLD usec, assume the
34 * key was released */
35#define AUTOREPEAT_THRESHOLD 100000
36/* Start repeating key after AUTOREPEAT_TRIGGER usec and send keypress
37 * events every AUTOREPEAT_RATE usec. */
38#define AUTOREPEAT_TRIGGER 300000
39#define AUTOREPEAT_RATE 20000
40#endif
41
42/** \brief Get the next mouse or keyboard input event.
43 *
44 *  Poll the event queue for mouse or keyboard events matching the event
45 *  mask and return the first matching event. Non-matching events are
46 *  discarded. If \c event_mask is zero, the function returns immediately.
47 *
48 *  The timeout value tells how long this function needs to wait for an
49 *  event. A value of zero returns immediately and the function returns zero
50 *  if no more events are pending in the queue. A negative value causes the
51 *  function to wait indefinitely until a matching event is received.
52 *
53 *  If not null, \c ev will be filled with information about the event
54 *  received. If null, the function will return but no information about
55 *  the event will be sent.
56 *
57 *  This function never fails.
58 *
59 *  \param dp The libcaca graphical context.
60 *  \param event_mask Bitmask of requested events.
61 *  \param timeout A timeout value in microseconds, -1 for blocking behaviour
62 *  \param ev A pointer to a caca_event structure, or NULL.
63 *  \return 1 if a matching event was received, or 0 if the wait timeouted.
64 */
65int caca_get_event(caca_display_t *dp, int event_mask,
66                   caca_event_t *ev, int timeout)
67{
68    caca_privevent_t privevent;
69    caca_timer_t timer = {0, 0};
70    int usec = 0;
71
72    if(!event_mask)
73        return 0;
74
75    if(timeout > 0)
76        _caca_getticks(&timer);
77
78    for( ; ; )
79    {
80        int ret = _get_next_event(dp, &privevent);
81
82        /* If we got the event we wanted, return */
83        if(privevent.type & event_mask)
84        {
85            if(ev)
86                memcpy(ev, &privevent, sizeof(privevent));
87            return ret;
88        }
89
90        /* If there is no timeout, sleep and try again. */
91        if(timeout < 0)
92        {
93            _caca_sleep(1000);
94            continue;
95        }
96
97        /* If we timeouted, return an empty event */
98        if(usec >= timeout)
99        {
100            privevent.type = CACA_EVENT_NONE;
101            if(ev)
102                memcpy(ev, &privevent, sizeof(privevent));
103            return 0;
104        }
105
106        /* Otherwise sleep a bit. Our granularity is far too high for values
107         * below 10000 microseconds so we cheat a bit. */
108        if(usec > 10000)
109            _caca_sleep(10000);
110        else
111            _caca_sleep(1000);
112
113        usec += _caca_getticks(&timer);
114    }
115}
116
117/** \brief Return the X mouse coordinate.
118 *
119 *  Return the X coordinate of the mouse position last time
120 *  it was detected. This function is not reliable if the ncurses or S-Lang
121 *  drivers are being used, because mouse position is only detected when
122 *  the mouse is clicked. Other drivers such as X11 work well.
123 *
124 *  This function never fails.
125 *
126 *  \param dp The libcaca graphical context.
127 *  \return The X mouse coordinate.
128 */
129int caca_get_mouse_x(caca_display_t const *dp)
130{
131    int width = caca_get_canvas_width(dp->cv);
132
133    if(dp->mouse.x >= width)
134        return width - 1;
135
136    return dp->mouse.x;
137}
138
139/** \brief Return the Y mouse coordinate.
140 *
141 *  Return the Y coordinate of the mouse position last time
142 *  it was detected. This function is not reliable if the ncurses or S-Lang
143 *  drivers are being used, because mouse position is only detected when
144 *  the mouse is clicked. Other drivers such as X11 work well.
145 *
146 *  This function never fails.
147 *
148 *  \param dp The libcaca graphical context.
149 *  \return The Y mouse coordinate.
150 */
151int caca_get_mouse_y(caca_display_t const *dp)
152{
153    int height = caca_get_canvas_height(dp->cv);
154
155    if(dp->mouse.y >= height)
156        return height - 1;
157
158    return dp->mouse.y;
159}
160
161/** \brief Return an event's type.
162 *
163 *  Return the type of an event. This function may always be called on an
164 *  event after caca_get_event() was called, and its return value indicates
165 *  which other functions may be called:
166 *  - \c CACA_EVENT_NONE: no other function may be called.
167 *  - \c CACA_EVENT_KEY_PRESS, \c CACA_EVENT_KEY_RELEASE:
168 *  caca_get_event_key_ch(), caca_get_event_key_utf32() and
169 *  caca_get_event_key_utf8() may be called.
170 *  - \c CACA_EVENT_MOUSE_PRESS, \c CACA_EVENT_MOUSE_RELEASE:
171 *  caca_get_event_mouse_button() may be called.
172 *  - \c CACA_EVENT_MOUSE_MOTION: caca_get_event_mouse_x() and
173 *  caca_get_event_mouse_y() may be called.
174 *  - \c CACA_EVENT_RESIZE: caca_get_event_resize_width() and
175 *  caca_get_event_resize_height() may be called.
176 *  - \c CACA_EVENT_QUIT: no other function may be called.
177 *
178 *  This function never fails.
179 *
180 *  \param ev The libcaca event.
181 *  \return The event's type.
182 */
183enum caca_event_type caca_get_event_type(caca_event_t const *ev)
184{
185    return ((caca_privevent_t const *)ev)->type;
186}
187
188/** \brief Return a key press or key release event's value
189 *
190 *  Return either the ASCII value for an event's key, or if the key is not
191 *  an ASCII character, an appropriate \e enum \e caca_key value.
192 *
193 *  This function never fails, but must only be called with a valid event of
194 *  type \c CACA_EVENT_KEY_PRESS or \c CACA_EVENT_KEY_RELEASE, or the results
195 *  will be undefined. See caca_get_event_type() for more information.
196 *
197 *  \param ev The libcaca event.
198 *  \return The key value.
199 */
200int caca_get_event_key_ch(caca_event_t const *ev)
201{
202    return ((caca_privevent_t const *)ev)->data.key.ch;
203}
204
205/** \brief Return a key press or key release event's Unicode value
206 *
207 *  Return the UTF-32/UCS-4 value for an event's key if it resolves to a
208 *  printable character.
209 *
210 *  This function never fails, but must only be called with a valid event of
211 *  type \c CACA_EVENT_KEY_PRESS or \c CACA_EVENT_KEY_RELEASE, or the results
212 *  will be undefined. See caca_get_event_type() for more information.
213 *
214 *  \param ev The libcaca event.
215 *  \return The key's Unicode value.
216 */
217uint32_t caca_get_event_key_utf32(caca_event_t const *ev)
218{
219    return ((caca_privevent_t const *)ev)->data.key.utf32;
220}
221
222/** \brief Return a key press or key release event's UTF-8 value
223 *
224 *  Write the UTF-8 value for an event's key if it resolves to a printable
225 *  character. Up to 6 UTF-8 bytes and a null termination are written.
226 *
227 *  This function never fails, but must only be called with a valid event of
228 *  type \c CACA_EVENT_KEY_PRESS or \c CACA_EVENT_KEY_RELEASE, or the results
229 *  will be undefined. See caca_get_event_type() for more information.
230 *
231 *  \param ev The libcaca event.
232 *  \param utf8 A string buffer with enough bytes to hold the pressed
233 *              key value in UTF-8. Though fewer bytes may be written to
234 *              it, 7 bytes is the minimum safe size.
235 *  \return This function always returns 0.
236 */
237int caca_get_event_key_utf8(caca_event_t const *ev, char *utf8)
238{
239    memcpy(utf8, ((caca_privevent_t const *)ev)->data.key.utf8, 8);
240    return 0;
241}
242
243/** \brief Return a mouse press or mouse release event's button
244 *
245 *  Return the mouse button index for an event.
246 *
247 *  This function never fails, but must only be called with a valid event of
248 *  type \c CACA_EVENT_MOUSE_PRESS or \c CACA_EVENT_MOUSE_RELEASE, or the
249 *  results will be undefined. See caca_get_event_type() for more information.
250 *
251 *  \param ev The libcaca event.
252 *  \return The event's mouse button.
253 */
254int caca_get_event_mouse_button(caca_event_t const *ev)
255{
256    return ((caca_privevent_t const *)ev)->data.mouse.button;
257}
258
259/** \brief Return a mouse motion event's X coordinate.
260 *
261 *  Return the X coordinate for a mouse motion event.
262 *
263 *  This function never fails, but must only be called with a valid event of
264 *  type \c CACA_EVENT_MOUSE_MOTION, or the results will be undefined. See
265 *  caca_get_event_type() for more information.
266 *
267 *  \param ev The libcaca event.
268 *  \return The event's X mouse coordinate.
269 */
270int caca_get_event_mouse_x(caca_event_t const *ev)
271{
272    return ((caca_privevent_t const *)ev)->data.mouse.x;
273}
274
275/** \brief Return a mouse motion event's Y coordinate.
276 *
277 *  Return the Y coordinate for a mouse motion event.
278 *
279 *  This function never fails, but must only be called with a valid event of
280 *  type \c CACA_EVENT_MOUSE_MOTION, or the results will be undefined. See
281 *  caca_get_event_type() for more information.
282 *
283 *  \param ev The libcaca event.
284 *  \return The event's Y mouse coordinate.
285 */
286int caca_get_event_mouse_y(caca_event_t const *ev)
287{
288    return ((caca_privevent_t const *)ev)->data.mouse.y;
289}
290
291/** \brief Return a resize event's display width value.
292 *
293 *  Return the width value for a display resize event.
294 *
295 *  This function never fails, but must only be called with a valid event of
296 *  type \c CACA_EVENT_RESIZE, or the results will be undefined. See
297 *  caca_get_event_type() for more information.
298 *
299 *  \param ev The libcaca event.
300 *  \return The event's new display width value.
301 */
302int caca_get_event_resize_width(caca_event_t const *ev)
303{
304    return ((caca_privevent_t const *)ev)->data.resize.w;
305}
306
307/** \brief Return a resize event's display height value.
308 *
309 *  Return the height value for a display resize event.
310 *
311 *  This function never fails, but must only be called with a valid event of
312 *  type \c CACA_EVENT_RESIZE, or the results will be undefined. See
313 *  caca_get_event_type() for more information.
314 *
315 *  \param ev The libcaca event.
316 *  \return The event's new display height value.
317 */
318int caca_get_event_resize_height(caca_event_t const *ev)
319{
320    return ((caca_privevent_t const *)ev)->data.resize.h;
321}
322
323/*
324 * XXX: The following functions are local.
325 */
326
327static int _get_next_event(caca_display_t *dp, caca_privevent_t *ev)
328{
329#if defined(USE_SLANG) || defined(USE_NCURSES)
330    int ticks;
331#endif
332    int ret;
333
334    /* If we are about to return a resize event, acknowledge it */
335    if(dp->resize.resized)
336    {
337        dp->resize.resized = 0;
338        _caca_handle_resize(dp);
339        ev->type = CACA_EVENT_RESIZE;
340        ev->data.resize.w = caca_get_canvas_width(dp->cv);
341        ev->data.resize.h = caca_get_canvas_height(dp->cv);
342        return 1;
343    }
344
345    ret = _lowlevel_event(dp, ev);
346
347#if defined(USE_SLANG)
348    if(dp->drv.id != CACA_DRIVER_SLANG)
349#endif
350#if defined(USE_NCURSES)
351    if(dp->drv.id != CACA_DRIVER_NCURSES)
352#endif
353    return ret;
354
355#if defined(USE_SLANG) || defined(USE_NCURSES)
356    /* Simulate long keypresses using autorepeat features */
357    ticks = _caca_getticks(&dp->events.key_timer);
358    dp->events.last_key_ticks += ticks;
359    dp->events.autorepeat_ticks += ticks;
360
361    /* Handle autorepeat */
362    if(dp->events.last_key_event.type
363           && dp->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
364           && dp->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
365           && dp->events.autorepeat_ticks > AUTOREPEAT_RATE)
366    {
367        _push_event(dp, ev);
368        dp->events.autorepeat_ticks -= AUTOREPEAT_RATE;
369        *ev = dp->events.last_key_event;
370        return 1;
371    }
372
373    /* We are in autorepeat mode and the same key was just pressed, ignore
374     * this event and return the next one by calling ourselves. */
375    if(ev->type == CACA_EVENT_KEY_PRESS
376        && dp->events.last_key_event.type
377        && ev->data.key.ch == dp->events.last_key_event.data.key.ch
378        && ev->data.key.utf32 == dp->events.last_key_event.data.key.utf32)
379    {
380        dp->events.last_key_ticks = 0;
381        return _get_next_event(dp, ev);
382    }
383
384    /* We are in autorepeat mode, but key has expired or a new key was
385     * pressed - store our event and return a key release event first */
386    if(dp->events.last_key_event.type
387          && (dp->events.last_key_ticks > AUTOREPEAT_THRESHOLD
388               || (ev->type & CACA_EVENT_KEY_PRESS)))
389    {
390        _push_event(dp, ev);
391        *ev = dp->events.last_key_event;
392        ev->type = CACA_EVENT_KEY_RELEASE;
393        dp->events.last_key_event.type = CACA_EVENT_NONE;
394        return 1;
395    }
396
397    /* A new key was pressed, enter autorepeat mode */
398    if(ev->type & CACA_EVENT_KEY_PRESS)
399    {
400        dp->events.last_key_ticks = 0;
401        dp->events.autorepeat_ticks = 0;
402        dp->events.last_key_event = *ev;
403    }
404
405    return ev->type ? 1 : 0;
406#endif
407}
408
409static int _lowlevel_event(caca_display_t *dp, caca_privevent_t *ev)
410{
411#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
412    int ret = _pop_event(dp, ev);
413
414    if(ret)
415        return ret;
416#endif
417
418    return dp->drv.get_event(dp, ev);
419}
420
421#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
422void _push_event(caca_display_t *dp, caca_privevent_t *ev)
423{
424    if(!ev->type || dp->events.queue == EVENTBUF_LEN)
425        return;
426    dp->events.buf[dp->events.queue] = *ev;
427    dp->events.queue++;
428}
429
430int _pop_event(caca_display_t *dp, caca_privevent_t *ev)
431{
432    int i;
433
434    if(dp->events.queue == 0)
435        return 0;
436
437    *ev = dp->events.buf[0];
438    for(i = 1; i < dp->events.queue; i++)
439        dp->events.buf[i - 1] = dp->events.buf[i];
440    dp->events.queue--;
441
442    return 1;
443}
444#endif
445
Note: See TracBrowser for help on using the repository browser.