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

Last change on this file since 769 was 769, checked in by Sam Hocevar, 14 years ago
  • Removed \file directives from all files except caca.h and cucul.h, to remove redundencies in the Doxygen documentation.
  • Property svn:keywords set to Id
File size: 7.2 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 769 2006-04-14 07:30:53Z sam $
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14/*
15 *  This file contains event handling functions for keyboard and mouse input.
16 */
17
18#include "config.h"
19
20#if !defined(__KERNEL__)
21#   include <stdio.h>
22#endif
23
24#include "cucul.h"
25#include "cucul_internals.h"
26#include "caca.h"
27#include "caca_internals.h"
28
29static int _get_next_event(caca_t *, struct caca_event *);
30static int _lowlevel_event(caca_t *, struct caca_event *);
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 200000
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 *  This function polls the event queue for mouse or keyboard events matching
45 *  the event mask and returns the first matching event. Non-matching events
46 *  are discarded. \c event_mask must have a non-zero value.
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 * \param event_mask Bitmask of requested events.
54 * \param timeout A timeout value in microseconds
55 * \return The next matching event in the queue, or 0 if no event is pending.
56 */
57int caca_get_event(caca_t *kk, unsigned int event_mask,
58                   struct caca_event *ev, int timeout)
59{
60    struct caca_timer timer;
61    int usec = 0;
62
63    if(!event_mask)
64        return 0;
65
66    if(timeout > 0)
67        _caca_getticks(&timer);
68
69    for( ; ; )
70    {
71        int ret = _get_next_event(kk, ev);
72
73        /* If we got the event we wanted, return */
74        if(ev->type & event_mask)
75            return ret;
76
77        /* If there is no timeout, sleep and try again. */
78        if(timeout < 0)
79        {
80            _caca_sleep(10000);
81            continue;
82        }
83
84        /* If we timeouted, return an empty event */
85        if(usec >= timeout)
86        {
87            ev->type = CACA_EVENT_NONE;
88            return 0;
89        }
90
91        /* Otherwise sleep a bit. Our granularity is far too high for values
92         * below 10000 microseconds so we cheat a bit. */
93        if(usec > 10000)
94            _caca_sleep(10000);
95        else
96            _caca_sleep(1000);
97
98        usec += _caca_getticks(&timer);
99    }
100}
101
102/** \brief Return the X mouse coordinate.
103 *
104 *  This function returns the X coordinate of the mouse position last time
105 *  it was detected. This function is not reliable if the ncurses or S-Lang
106 *  drivers are being used, because mouse position is only detected when
107 *  the mouse is clicked. Other drivers such as X11 work well.
108 *
109 *  \return The X mouse coordinate.
110 */
111unsigned int caca_get_mouse_x(caca_t *kk)
112{
113    if(kk->mouse.x >= kk->qq->width)
114        kk->mouse.x = kk->qq->width - 1;
115
116    return kk->mouse.x;
117}
118
119/** \brief Return the Y mouse coordinate.
120 *
121 *  This function returns the Y coordinate of the mouse position last time
122 *  it was detected. This function is not reliable if the ncurses or S-Lang
123 *  drivers are being used, because mouse position is only detected when
124 *  the mouse is clicked. Other drivers such as X11 work well.
125 *
126 *  \return The Y mouse coordinate.
127 */
128unsigned int caca_get_mouse_y(caca_t *kk)
129{
130    if(kk->mouse.y >= kk->qq->height)
131        kk->mouse.y = kk->qq->height - 1;
132
133    return kk->mouse.y;
134}
135
136/*
137 * XXX: The following functions are local.
138 */
139
140static int _get_next_event(caca_t *kk, struct caca_event *ev)
141{
142#if defined(USE_SLANG) || defined(USE_NCURSES)
143    unsigned int ticks;
144#endif
145    int ret;
146
147    /* If we are about to return a resize event, acknowledge it */
148    if(kk->resize.resized)
149    {
150        kk->resize.resized = 0;
151        _caca_handle_resize(kk);
152        ev->type = CACA_EVENT_RESIZE;
153        ev->data.resize.w = kk->qq->width;
154        ev->data.resize.h = kk->qq->height;
155        return 1;
156    }
157
158    ret = _lowlevel_event(kk, ev);
159
160#if defined(USE_SLANG)
161    if(kk->drv.driver != CACA_DRIVER_SLANG)
162#endif
163#if defined(USE_NCURSES)
164    if(kk->drv.driver != CACA_DRIVER_NCURSES)
165#endif
166    return ret;
167
168#if defined(USE_SLANG) || defined(USE_NCURSES)
169    /* Simulate long keypresses using autorepeat features */
170    ticks = _caca_getticks(&kk->events.key_timer);
171    kk->events.last_key_ticks += ticks;
172    kk->events.autorepeat_ticks += ticks;
173
174    /* Handle autorepeat */
175    if(kk->events.last_key_event.type
176           && kk->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
177           && kk->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
178           && kk->events.autorepeat_ticks > AUTOREPEAT_RATE)
179    {
180        _push_event(kk, ev);
181        kk->events.autorepeat_ticks -= AUTOREPEAT_RATE;
182        *ev = kk->events.last_key_event;
183        return 1;
184    }
185
186    /* We are in autorepeat mode and the same key was just pressed, ignore
187     * this event and return the next one by calling ourselves. */
188    if(ev->type == CACA_EVENT_KEY_PRESS
189        && kk->events.last_key_event.type
190        && ev->data.key.c == kk->events.last_key_event.data.key.c
191        && ev->data.key.ucs4 == kk->events.last_key_event.data.key.ucs4)
192    {
193        kk->events.last_key_ticks = 0;
194        return _get_next_event(kk, ev);
195    }
196
197    /* We are in autorepeat mode, but key has expired or a new key was
198     * pressed - store our event and return a key release event first */
199    if(kk->events.last_key_event.type
200          && (kk->events.last_key_ticks > AUTOREPEAT_THRESHOLD
201               || (ev->type & CACA_EVENT_KEY_PRESS)))
202    {
203        _push_event(kk, ev);
204        *ev = kk->events.last_key_event;
205        ev->type = CACA_EVENT_KEY_RELEASE;
206        kk->events.last_key_event.type = CACA_EVENT_NONE;
207        return 1;
208    }
209
210    /* A new key was pressed, enter autorepeat mode */
211    if(ev->type & CACA_EVENT_KEY_PRESS)
212    {
213        kk->events.last_key_ticks = 0;
214        kk->events.autorepeat_ticks = 0;
215        kk->events.last_key_event = *ev;
216    }
217
218    return ev->type ? 1 : 0;
219#endif
220}
221
222static int _lowlevel_event(caca_t *kk, struct caca_event *ev)
223{
224#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
225    int ret = _pop_event(kk, ev);
226
227    if(ret)
228        return ret;
229#endif
230
231    return kk->drv.get_event(kk, ev);
232}
233
234#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
235void _push_event(caca_t *kk, struct caca_event *ev)
236{
237    if(!ev->type || kk->events.queue == EVENTBUF_LEN)
238        return;
239    kk->events.buf[kk->events.queue] = *ev;
240    kk->events.queue++;
241}
242
243int _pop_event(caca_t *kk, struct caca_event *ev)
244{
245    int i;
246
247    if(kk->events.queue == 0)
248        return 0;
249
250    *ev = kk->events.buf[0];
251    for(i = 1; i < kk->events.queue; i++)
252        kk->events.buf[i - 1] = kk->events.buf[i];
253    kk->events.queue--;
254
255    return 1;
256}
257#endif
258
Note: See TracBrowser for help on using the repository browser.