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

Last change on this file since 4369 was 4369, checked in by Sam Hocevar, 12 years ago

Add the copyright unit test and update copyright information everywhere.

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