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

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

Better caca_get_event_mouse_button() documentation.

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