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

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