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

Last change on this file since 645 was 645, checked in by Sam Hocevar, 14 years ago
  • Cosmetic fixes.
  • Property svn:keywords set to Id
File size: 6.7 KB
Line 
1/*
2 *  libcaca       ASCII-Art library
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the Do What The Fuck You Want To
8 *  Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12/** \file event.c
13 *  \version \$Id: event.c 645 2006-03-18 00:12:25Z sam $
14 *  \author Sam Hocevar <sam@zoy.org>
15 *  \brief Event handling
16 *
17 *  This file contains event handling functions for keyboard and mouse input.
18 */
19
20#include "config.h"
21
22#include "cucul.h"
23#include "cucul_internals.h"
24#include "caca.h"
25#include "caca_internals.h"
26
27static unsigned int _get_next_event(caca_t *);
28static unsigned int _lowlevel_event(caca_t *);
29
30#if !defined(_DOXYGEN_SKIP_ME)
31/* If no new key was pressed after AUTOREPEAT_THRESHOLD usec, assume the
32 * key was released */
33#define AUTOREPEAT_THRESHOLD 200000
34/* Start repeating key after AUTOREPEAT_TRIGGER usec and send keypress
35 * events every AUTOREPEAT_RATE usec. */
36#define AUTOREPEAT_TRIGGER 300000
37#define AUTOREPEAT_RATE 100000
38#endif
39
40/** \brief Get the next mouse or keyboard input event.
41 *
42 *  This function polls the event queue for mouse or keyboard events matching
43 *  the event mask and returns the first matching event. Non-matching events
44 *  are discarded. \c event_mask must have a non-zero value. This function is
45 *  non-blocking and returns zero if no more events are pending in the queue.
46 *  See also caca_wait_event() for a blocking version of this function.
47 *
48 * \param event_mask Bitmask of requested events.
49 * \return The next matching event in the queue, or 0 if no event is pending.
50 */
51unsigned int caca_get_event(caca_t *kk, unsigned int event_mask)
52{
53    if(!event_mask)
54        return CACA_EVENT_NONE;
55
56    for( ; ; )
57    {
58        unsigned int event = _get_next_event(kk);
59
60        if(!event || event & event_mask)
61            return event;
62    }
63}
64
65/** \brief Wait for the next mouse or keyboard input event.
66 *
67 *  This function returns the first mouse or keyboard event in the queue
68 *  that matches the event mask. If no event is pending, it blocks until a
69 *  matching event is received. \c event_mask must have a non-zero value.
70 *  See also caca_get_event() for a non-blocking version of this function.
71 *
72 *  \param event_mask Bitmask of requested events.
73 *  \return The next event in the queue.
74 */
75unsigned int caca_wait_event(caca_t *kk, unsigned int event_mask)
76{
77    if(!event_mask)
78        return CACA_EVENT_NONE;
79
80    for( ; ; )
81    {
82        unsigned int event = _get_next_event(kk);
83
84        if(event & event_mask)
85            return event;
86
87        _caca_sleep(10000);
88    }
89}
90
91/** \brief Return the X mouse coordinate.
92 *
93 *  This function returns the X coordinate of the mouse position last time
94 *  it was detected. This function is not reliable if the ncurses or S-Lang
95 *  drivers are being used, because mouse position is only detected when
96 *  the mouse is clicked. Other drivers such as X11 work well.
97 *
98 *  \return The X mouse coordinate.
99 */
100unsigned int caca_get_mouse_x(caca_t *kk)
101{
102    if(kk->mouse.x >= kk->qq->width)
103        kk->mouse.x = kk->qq->width - 1;
104
105    return kk->mouse.x;
106}
107
108/** \brief Return the Y mouse coordinate.
109 *
110 *  This function returns the Y coordinate of the mouse position last time
111 *  it was detected. This function is not reliable if the ncurses or S-Lang
112 *  drivers are being used, because mouse position is only detected when
113 *  the mouse is clicked. Other drivers such as X11 work well.
114 *
115 *  \return The Y mouse coordinate.
116 */
117unsigned int caca_get_mouse_y(caca_t *kk)
118{
119    if(kk->mouse.y >= kk->qq->height)
120        kk->mouse.y = kk->qq->height - 1;
121
122    return kk->mouse.y;
123}
124
125/*
126 * XXX: The following functions are local.
127 */
128
129static unsigned int _get_next_event(caca_t *kk)
130{
131#if defined(USE_SLANG) || defined(USE_NCURSES)
132    unsigned int ticks;
133#endif
134    unsigned int event;
135
136    /* If we are about to return a resize event, acknowledge it */
137    if(kk->resize.resized)
138    {
139        kk->resize.resized = 0;
140        _caca_handle_resize(kk);
141        return CACA_EVENT_RESIZE;
142    }
143
144    event = _lowlevel_event(kk);
145
146#if defined(USE_SLANG)
147    if(kk->drv.driver != CACA_DRIVER_SLANG)
148#endif
149#if defined(USE_NCURSES)
150    if(kk->drv.driver != CACA_DRIVER_NCURSES)
151#endif
152    return event;
153
154#if defined(USE_SLANG) || defined(USE_NCURSES)
155    /* Simulate long keypresses using autorepeat features */
156    ticks = _caca_getticks(&kk->events.key_timer);
157    kk->events.last_key_ticks += ticks;
158    kk->events.autorepeat_ticks += ticks;
159
160    /* Handle autorepeat */
161    if(kk->events.last_key
162           && kk->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
163           && kk->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
164           && kk->events.autorepeat_ticks > AUTOREPEAT_RATE)
165    {
166        _push_event(kk, event);
167        kk->events.autorepeat_ticks -= AUTOREPEAT_RATE;
168        return CACA_EVENT_KEY_PRESS | kk->events.last_key;
169    }
170
171    /* We are in autorepeat mode and the same key was just pressed, ignore
172     * this event and return the next one by calling ourselves. */
173    if(event == (CACA_EVENT_KEY_PRESS | kk->events.last_key))
174    {
175        kk->events.last_key_ticks = 0;
176        return _get_next_event(kk);
177    }
178
179    /* We are in autorepeat mode, but key has expired or a new key was
180     * pressed - store our event and return a key release event first */
181    if(kk->events.last_key
182          && (kk->events.last_key_ticks > AUTOREPEAT_THRESHOLD
183               || (event & CACA_EVENT_KEY_PRESS)))
184    {
185        _push_event(kk, event);
186        event = CACA_EVENT_KEY_RELEASE | kk->events.last_key;
187        kk->events.last_key = 0;
188        return event;
189    }
190
191    /* A new key was pressed, enter autorepeat mode */
192    if(event & CACA_EVENT_KEY_PRESS)
193    {
194        kk->events.last_key_ticks = 0;
195        kk->events.autorepeat_ticks = 0;
196        kk->events.last_key = event & 0x00ffffff;
197    }
198
199    return event;
200#endif
201}
202
203static unsigned int _lowlevel_event(caca_t *kk)
204{
205#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
206    unsigned int event = _pop_event(kk);
207
208    if(event)
209        return event;
210#endif
211
212    return kk->drv.get_event(kk);
213}
214
215#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
216void _push_event(caca_t *kk, unsigned int event)
217{
218    if(!event || kk->events.queue == EVENTBUF_LEN)
219        return;
220    kk->events.buf[kk->events.queue] = event;
221    kk->events.queue++;
222}
223
224unsigned int _pop_event(caca_t *kk)
225{
226    int i;
227    unsigned int event;
228
229    if(kk->events.queue == 0)
230        return CACA_EVENT_NONE;
231
232    event = kk->events.buf[0];
233    for(i = 1; i < kk->events.queue; i++)
234        kk->events.buf[i - 1] = kk->events.buf[i];
235    kk->events.queue--;
236
237    return event;
238}
239#endif
240
Note: See TracBrowser for help on using the repository browser.