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

Last change on this file since 824 was 811, checked in by Sam Hocevar, 15 years ago
  • Renamed caca_t into caca_display_t.
  • Renamed canvas handle variables from "c" to "cv". Eh ouais mon gros.
  • Property svn:keywords set to Id
File size: 7.4 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 811 2006-04-18 15:11:25Z 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_display_t *, caca_event_t *);
30static int _lowlevel_event(caca_display_t *, caca_event_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 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 dp The libcaca graphical context.
54 *  \param event_mask Bitmask of requested events.
55 *  \param timeout A timeout value in microseconds
56 *  \param ev A pointer to a caca_event structure.
57 *  \return The next matching event in the queue, or 0 if no event is pending.
58 */
59int caca_get_event(caca_display_t *dp, unsigned int event_mask,
60                   caca_event_t *ev, int timeout)
61{
62    caca_timer_t timer;
63    int usec = 0;
64
65    if(!event_mask)
66        return 0;
67
68    if(timeout > 0)
69        _caca_getticks(&timer);
70
71    for( ; ; )
72    {
73        int ret = _get_next_event(dp, ev);
74
75        /* If we got the event we wanted, return */
76        if(ev->type & event_mask)
77            return ret;
78
79        /* If there is no timeout, sleep and try again. */
80        if(timeout < 0)
81        {
82            _caca_sleep(10000);
83            continue;
84        }
85
86        /* If we timeouted, return an empty event */
87        if(usec >= timeout)
88        {
89            ev->type = CACA_EVENT_NONE;
90            return 0;
91        }
92
93        /* Otherwise sleep a bit. Our granularity is far too high for values
94         * below 10000 microseconds so we cheat a bit. */
95        if(usec > 10000)
96            _caca_sleep(10000);
97        else
98            _caca_sleep(1000);
99
100        usec += _caca_getticks(&timer);
101    }
102}
103
104/** \brief Return the X mouse coordinate.
105 *
106 *  This function returns the X coordinate of the mouse position last time
107 *  it was detected. This function is not reliable if the ncurses or S-Lang
108 *  drivers are being used, because mouse position is only detected when
109 *  the mouse is clicked. Other drivers such as X11 work well.
110 *
111 *  \param dp The libcaca graphical context.
112 *  \return The X mouse coordinate.
113 */
114unsigned int caca_get_mouse_x(caca_display_t *dp)
115{
116    if(dp->mouse.x >= dp->cv->width)
117        dp->mouse.x = dp->cv->width - 1;
118
119    return dp->mouse.x;
120}
121
122/** \brief Return the Y mouse coordinate.
123 *
124 *  This function returns the Y coordinate of the mouse position last time
125 *  it was detected. This function is not reliable if the ncurses or S-Lang
126 *  drivers are being used, because mouse position is only detected when
127 *  the mouse is clicked. Other drivers such as X11 work well.
128 *
129 *  \param dp The libcaca graphical context.
130 *  \return The Y mouse coordinate.
131 */
132unsigned int caca_get_mouse_y(caca_display_t *dp)
133{
134    if(dp->mouse.y >= dp->cv->height)
135        dp->mouse.y = dp->cv->height - 1;
136
137    return dp->mouse.y;
138}
139
140/*
141 * XXX: The following functions are local.
142 */
143
144static int _get_next_event(caca_display_t *dp, caca_event_t *ev)
145{
146#if defined(USE_SLANG) || defined(USE_NCURSES)
147    unsigned int ticks;
148#endif
149    int ret;
150
151    /* If we are about to return a resize event, acknowledge it */
152    if(dp->resize.resized)
153    {
154        dp->resize.resized = 0;
155        _caca_handle_resize(dp);
156        ev->type = CACA_EVENT_RESIZE;
157        ev->data.resize.w = dp->cv->width;
158        ev->data.resize.h = dp->cv->height;
159        return 1;
160    }
161
162    ret = _lowlevel_event(dp, ev);
163
164#if defined(USE_SLANG)
165    if(dp->drv.driver != CACA_DRIVER_SLANG)
166#endif
167#if defined(USE_NCURSES)
168    if(dp->drv.driver != CACA_DRIVER_NCURSES)
169#endif
170    return ret;
171
172#if defined(USE_SLANG) || defined(USE_NCURSES)
173    /* Simulate long keypresses using autorepeat features */
174    ticks = _caca_getticks(&dp->events.key_timer);
175    dp->events.last_key_ticks += ticks;
176    dp->events.autorepeat_ticks += ticks;
177
178    /* Handle autorepeat */
179    if(dp->events.last_key_event.type
180           && dp->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
181           && dp->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
182           && dp->events.autorepeat_ticks > AUTOREPEAT_RATE)
183    {
184        _push_event(dp, ev);
185        dp->events.autorepeat_ticks -= AUTOREPEAT_RATE;
186        *ev = dp->events.last_key_event;
187        return 1;
188    }
189
190    /* We are in autorepeat mode and the same key was just pressed, ignore
191     * this event and return the next one by calling ourselves. */
192    if(ev->type == CACA_EVENT_KEY_PRESS
193        && dp->events.last_key_event.type
194        && ev->data.key.ch == dp->events.last_key_event.data.key.ch
195        && ev->data.key.ucs4 == dp->events.last_key_event.data.key.ucs4)
196    {
197        dp->events.last_key_ticks = 0;
198        return _get_next_event(dp, ev);
199    }
200
201    /* We are in autorepeat mode, but key has expired or a new key was
202     * pressed - store our event and return a key release event first */
203    if(dp->events.last_key_event.type
204          && (dp->events.last_key_ticks > AUTOREPEAT_THRESHOLD
205               || (ev->type & CACA_EVENT_KEY_PRESS)))
206    {
207        _push_event(dp, ev);
208        *ev = dp->events.last_key_event;
209        ev->type = CACA_EVENT_KEY_RELEASE;
210        dp->events.last_key_event.type = CACA_EVENT_NONE;
211        return 1;
212    }
213
214    /* A new key was pressed, enter autorepeat mode */
215    if(ev->type & CACA_EVENT_KEY_PRESS)
216    {
217        dp->events.last_key_ticks = 0;
218        dp->events.autorepeat_ticks = 0;
219        dp->events.last_key_event = *ev;
220    }
221
222    return ev->type ? 1 : 0;
223#endif
224}
225
226static int _lowlevel_event(caca_display_t *dp, caca_event_t *ev)
227{
228#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
229    int ret = _pop_event(dp, ev);
230
231    if(ret)
232        return ret;
233#endif
234
235    return dp->drv.get_event(dp, ev);
236}
237
238#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
239void _push_event(caca_display_t *dp, caca_event_t *ev)
240{
241    if(!ev->type || dp->events.queue == EVENTBUF_LEN)
242        return;
243    dp->events.buf[dp->events.queue] = *ev;
244    dp->events.queue++;
245}
246
247int _pop_event(caca_display_t *dp, caca_event_t *ev)
248{
249    int i;
250
251    if(dp->events.queue == 0)
252        return 0;
253
254    *ev = dp->events.buf[0];
255    for(i = 1; i < dp->events.queue; i++)
256        dp->events.buf[i - 1] = dp->events.buf[i];
257    dp->events.queue--;
258
259    return 1;
260}
261#endif
262
Note: See TracBrowser for help on using the repository browser.