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

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

Starting refactoring to get rid of libcucul. The initial reason for the
split is rendered moot by the plugin system: when enabled, binaries do
not link directly with libX11 or libGL. I hope this is a step towards
more consisteny and clarity.

  • Property svn:keywords set to Id
File size: 13.5 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 2821 2008-09-27 13:12:46Z 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 100000
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(10000);
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 *  \return This function always returns 0.
233 */
234int caca_get_event_key_utf8(caca_event_t const *ev, char *utf8)
235{
236    memcpy(utf8, ((caca_privevent_t const *)ev)->data.key.utf8, 8);
237    return 0;
238}
239
240/** \brief Return a mouse press or mouse release event's button
241 *
242 *  Return the mouse button index for an event.
243 *
244 *  This function never fails, but must only be called with a valid event of
245 *  type \c CACA_EVENT_MOUSE_PRESS or \c CACA_EVENT_MOUSE_RELEASE, or the
246 *  results will be undefined. See caca_get_event_type() for more information.
247 *
248 *  \param ev The libcaca event.
249 *  \return The event's mouse button.
250 */
251int caca_get_event_mouse_button(caca_event_t const *ev)
252{
253    return ((caca_privevent_t const *)ev)->data.mouse.button;
254}
255
256/** \brief Return a mouse motion event's X coordinate.
257 *
258 *  Return the X coordinate for a mouse motion event.
259 *
260 *  This function never fails, but must only be called with a valid event of
261 *  type \c CACA_EVENT_MOUSE_MOTION, or the results will be undefined. See
262 *  caca_get_event_type() for more information.
263 *
264 *  \param ev The libcaca event.
265 *  \return The event's X mouse coordinate.
266 */
267int caca_get_event_mouse_x(caca_event_t const *ev)
268{
269    return ((caca_privevent_t const *)ev)->data.mouse.x;
270}
271
272/** \brief Return a mouse motion event's Y coordinate.
273 *
274 *  Return the Y coordinate for a mouse motion event.
275 *
276 *  This function never fails, but must only be called with a valid event of
277 *  type \c CACA_EVENT_MOUSE_MOTION, or the results will be undefined. See
278 *  caca_get_event_type() for more information.
279 *
280 *  \param ev The libcaca event.
281 *  \return The event's Y mouse coordinate.
282 */
283int caca_get_event_mouse_y(caca_event_t const *ev)
284{
285    return ((caca_privevent_t const *)ev)->data.mouse.y;
286}
287
288/** \brief Return a resize event's display width value.
289 *
290 *  Return the width value for a display resize event.
291 *
292 *  This function never fails, but must only be called with a valid event of
293 *  type \c CACA_EVENT_RESIZE, or the results will be undefined. See
294 *  caca_get_event_type() for more information.
295 *
296 *  \param ev The libcaca event.
297 *  \return The event's new display width value.
298 */
299int caca_get_event_resize_width(caca_event_t const *ev)
300{
301    return ((caca_privevent_t const *)ev)->data.resize.w;
302}
303
304/** \brief Return a resize event's display height value.
305 *
306 *  Return the height value for a display resize event.
307 *
308 *  This function never fails, but must only be called with a valid event of
309 *  type \c CACA_EVENT_RESIZE, or the results will be undefined. See
310 *  caca_get_event_type() for more information.
311 *
312 *  \param ev The libcaca event.
313 *  \return The event's new display height value.
314 */
315int caca_get_event_resize_height(caca_event_t const *ev)
316{
317    return ((caca_privevent_t const *)ev)->data.resize.h;
318}
319
320/*
321 * XXX: The following functions are local.
322 */
323
324static int _get_next_event(caca_display_t *dp, caca_privevent_t *ev)
325{
326#if defined(USE_SLANG) || defined(USE_NCURSES)
327    int ticks;
328#endif
329    int ret;
330
331    /* If we are about to return a resize event, acknowledge it */
332    if(dp->resize.resized)
333    {
334        dp->resize.resized = 0;
335        _caca_handle_resize(dp);
336        ev->type = CACA_EVENT_RESIZE;
337        ev->data.resize.w = caca_get_canvas_width(dp->cv);
338        ev->data.resize.h = caca_get_canvas_height(dp->cv);
339        return 1;
340    }
341
342    ret = _lowlevel_event(dp, ev);
343
344#if defined(USE_SLANG)
345    if(dp->drv.id != CACA_DRIVER_SLANG)
346#endif
347#if defined(USE_NCURSES)
348    if(dp->drv.id != CACA_DRIVER_NCURSES)
349#endif
350    return ret;
351
352#if defined(USE_SLANG) || defined(USE_NCURSES)
353    /* Simulate long keypresses using autorepeat features */
354    ticks = _caca_getticks(&dp->events.key_timer);
355    dp->events.last_key_ticks += ticks;
356    dp->events.autorepeat_ticks += ticks;
357
358    /* Handle autorepeat */
359    if(dp->events.last_key_event.type
360           && dp->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
361           && dp->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
362           && dp->events.autorepeat_ticks > AUTOREPEAT_RATE)
363    {
364        _push_event(dp, ev);
365        dp->events.autorepeat_ticks -= AUTOREPEAT_RATE;
366        *ev = dp->events.last_key_event;
367        return 1;
368    }
369
370    /* We are in autorepeat mode and the same key was just pressed, ignore
371     * this event and return the next one by calling ourselves. */
372    if(ev->type == CACA_EVENT_KEY_PRESS
373        && dp->events.last_key_event.type
374        && ev->data.key.ch == dp->events.last_key_event.data.key.ch
375        && ev->data.key.utf32 == dp->events.last_key_event.data.key.utf32)
376    {
377        dp->events.last_key_ticks = 0;
378        return _get_next_event(dp, ev);
379    }
380
381    /* We are in autorepeat mode, but key has expired or a new key was
382     * pressed - store our event and return a key release event first */
383    if(dp->events.last_key_event.type
384          && (dp->events.last_key_ticks > AUTOREPEAT_THRESHOLD
385               || (ev->type & CACA_EVENT_KEY_PRESS)))
386    {
387        _push_event(dp, ev);
388        *ev = dp->events.last_key_event;
389        ev->type = CACA_EVENT_KEY_RELEASE;
390        dp->events.last_key_event.type = CACA_EVENT_NONE;
391        return 1;
392    }
393
394    /* A new key was pressed, enter autorepeat mode */
395    if(ev->type & CACA_EVENT_KEY_PRESS)
396    {
397        dp->events.last_key_ticks = 0;
398        dp->events.autorepeat_ticks = 0;
399        dp->events.last_key_event = *ev;
400    }
401
402    return ev->type ? 1 : 0;
403#endif
404}
405
406static int _lowlevel_event(caca_display_t *dp, caca_privevent_t *ev)
407{
408#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
409    int ret = _pop_event(dp, ev);
410
411    if(ret)
412        return ret;
413#endif
414
415    return dp->drv.get_event(dp, ev);
416}
417
418#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
419void _push_event(caca_display_t *dp, caca_privevent_t *ev)
420{
421    if(!ev->type || dp->events.queue == EVENTBUF_LEN)
422        return;
423    dp->events.buf[dp->events.queue] = *ev;
424    dp->events.queue++;
425}
426
427int _pop_event(caca_display_t *dp, caca_privevent_t *ev)
428{
429    int i;
430
431    if(dp->events.queue == 0)
432        return 0;
433
434    *ev = dp->events.buf[0];
435    for(i = 1; i < dp->events.queue; i++)
436        dp->events.buf[i - 1] = dp->events.buf[i];
437    dp->events.queue--;
438
439    return 1;
440}
441#endif
442
Note: See TracBrowser for help on using the repository browser.