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

Last change on this file since 2043 was 2043, checked in by Sam Hocevar, 13 years ago
  • Added as many "const" qualifiers as possible to the public API.
  • Property svn:keywords set to Id
File size: 7.9 KB
RevLine 
[35]1/*
[672]2 *  libcaca       Colour ASCII-Art library
[527]3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
[268]4 *                All Rights Reserved
[35]5 *
[769]6 *  $Id: event.c 2043 2007-11-24 11:08:21Z sam $
7 *
[1462]8 *  This library is free software. It comes without any warranty, to
[1452]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
[522]12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
[35]13 */
[17]14
[769]15/*
[268]16 *  This file contains event handling functions for keyboard and mouse input.
[205]17 */
18
[63]19#include "config.h"
[859]20#include "common.h"
[63]21
[681]22#if !defined(__KERNEL__)
23#   include <stdio.h>
24#endif
25
[524]26#include "cucul.h"
27#include "cucul_internals.h"
[185]28#include "caca.h"
29#include "caca_internals.h"
[17]30
[811]31static int _get_next_event(caca_display_t *, caca_event_t *);
32static int _lowlevel_event(caca_display_t *, caca_event_t *);
[199]33
[322]34#if !defined(_DOXYGEN_SKIP_ME)
[331]35/* If no new key was pressed after AUTOREPEAT_THRESHOLD usec, assume the
36 * key was released */
[1556]37#define AUTOREPEAT_THRESHOLD 100000
[331]38/* Start repeating key after AUTOREPEAT_TRIGGER usec and send keypress
39 * events every AUTOREPEAT_RATE usec. */
40#define AUTOREPEAT_TRIGGER 300000
41#define AUTOREPEAT_RATE 100000
42#endif
43
[268]44/** \brief Get the next mouse or keyboard input event.
[257]45 *
[1231]46 *  Poll the event queue for mouse or keyboard events matching the event
47 *  mask and return the first matching event. Non-matching events are
48 *  discarded. If \c event_mask is zero, the function returns immediately.
[268]49 *
[710]50 *  The timeout value tells how long this function needs to wait for an
51 *  event. A value of zero returns immediately and the function returns zero
52 *  if no more events are pending in the queue. A negative value causes the
53 *  function to wait indefinitely until a matching event is received.
54 *
[849]55 *  If not null, \c ev will be filled with information about the event
56 *  received. If null, the function will return but no information about
57 *  the event will be sent.
58 *
[1006]59 *  This function never fails.
60 *
[811]61 *  \param dp The libcaca graphical context.
[773]62 *  \param event_mask Bitmask of requested events.
[923]63 *  \param timeout A timeout value in microseconds, -1 for blocking behaviour
[849]64 *  \param ev A pointer to a caca_event structure, or NULL.
65 *  \return 1 if a matching event was received, or 0 if the wait timeouted.
[257]66 */
[811]67int caca_get_event(caca_display_t *dp, unsigned int event_mask,
[777]68                   caca_event_t *ev, int timeout)
[79]69{
[849]70    caca_event_t dummy_event;
[777]71    caca_timer_t timer;
[710]72    int usec = 0;
73
[332]74    if(!event_mask)
[681]75        return 0;
[332]76
[710]77    if(timeout > 0)
78        _caca_getticks(&timer);
79
[849]80    if(ev == NULL)
81        ev = &dummy_event;
82
[316]83    for( ; ; )
84    {
[811]85        int ret = _get_next_event(dp, ev);
[316]86
[710]87        /* If we got the event we wanted, return */
88        if(ev->type & event_mask)
[681]89            return ret;
[316]90
[710]91        /* If there is no timeout, sleep and try again. */
92        if(timeout < 0)
93        {
94            _caca_sleep(10000);
95            continue;
96        }
[332]97
[710]98        /* If we timeouted, return an empty event */
99        if(usec >= timeout)
100        {
101            ev->type = CACA_EVENT_NONE;
102            return 0;
103        }
[316]104
[710]105        /* Otherwise sleep a bit. Our granularity is far too high for values
106         * below 10000 microseconds so we cheat a bit. */
107        if(usec > 10000)
108            _caca_sleep(10000);
109        else
110            _caca_sleep(1000);
[316]111
[710]112        usec += _caca_getticks(&timer);
[316]113    }
114}
115
[347]116/** \brief Return the X mouse coordinate.
117 *
[1231]118 *  Return the X coordinate of the mouse position last time
[347]119 *  it was detected. This function is not reliable if the ncurses or S-Lang
120 *  drivers are being used, because mouse position is only detected when
121 *  the mouse is clicked. Other drivers such as X11 work well.
122 *
[1006]123 *  This function never fails.
124 *
[811]125 *  \param dp The libcaca graphical context.
[347]126 *  \return The X mouse coordinate.
127 */
[2043]128unsigned int caca_get_mouse_x(caca_display_t const *dp)
[347]129{
[811]130    if(dp->mouse.x >= dp->cv->width)
[2043]131        return dp->cv->width - 1;
[351]132
[811]133    return dp->mouse.x;
[347]134}
135
136/** \brief Return the Y mouse coordinate.
137 *
[1231]138 *  Return the Y coordinate of the mouse position last time
[347]139 *  it was detected. This function is not reliable if the ncurses or S-Lang
140 *  drivers are being used, because mouse position is only detected when
141 *  the mouse is clicked. Other drivers such as X11 work well.
142 *
[1006]143 *  This function never fails.
144 *
[811]145 *  \param dp The libcaca graphical context.
[347]146 *  \return The Y mouse coordinate.
147 */
[2043]148unsigned int caca_get_mouse_y(caca_display_t const *dp)
[347]149{
[811]150    if(dp->mouse.y >= dp->cv->height)
[2043]151        return dp->cv->height - 1;
[351]152
[811]153    return dp->mouse.y;
[347]154}
155
[316]156/*
157 * XXX: The following functions are local.
158 */
159
[811]160static int _get_next_event(caca_display_t *dp, caca_event_t *ev)
[316]161{
[331]162#if defined(USE_SLANG) || defined(USE_NCURSES)
163    unsigned int ticks;
[498]164#endif
[681]165    int ret;
[487]166
[553]167    /* If we are about to return a resize event, acknowledge it */
[811]168    if(dp->resize.resized)
[553]169    {
[811]170        dp->resize.resized = 0;
171        _caca_handle_resize(dp);
[681]172        ev->type = CACA_EVENT_RESIZE;
[811]173        ev->data.resize.w = dp->cv->width;
174        ev->data.resize.h = dp->cv->height;
[681]175        return 1;
[553]176    }
177
[811]178    ret = _lowlevel_event(dp, ev);
[331]179
180#if defined(USE_SLANG)
[811]181    if(dp->drv.driver != CACA_DRIVER_SLANG)
[331]182#endif
183#if defined(USE_NCURSES)
[811]184    if(dp->drv.driver != CACA_DRIVER_NCURSES)
[331]185#endif
[681]186    return ret;
[331]187
188#if defined(USE_SLANG) || defined(USE_NCURSES)
189    /* Simulate long keypresses using autorepeat features */
[811]190    ticks = _caca_getticks(&dp->events.key_timer);
191    dp->events.last_key_ticks += ticks;
192    dp->events.autorepeat_ticks += ticks;
[331]193
194    /* Handle autorepeat */
[811]195    if(dp->events.last_key_event.type
196           && dp->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
197           && dp->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
198           && dp->events.autorepeat_ticks > AUTOREPEAT_RATE)
[331]199    {
[811]200        _push_event(dp, ev);
201        dp->events.autorepeat_ticks -= AUTOREPEAT_RATE;
202        *ev = dp->events.last_key_event;
[681]203        return 1;
[331]204    }
205
206    /* We are in autorepeat mode and the same key was just pressed, ignore
207     * this event and return the next one by calling ourselves. */
[681]208    if(ev->type == CACA_EVENT_KEY_PRESS
[811]209        && dp->events.last_key_event.type
210        && ev->data.key.ch == dp->events.last_key_event.data.key.ch
[969]211        && ev->data.key.utf32 == dp->events.last_key_event.data.key.utf32)
[331]212    {
[811]213        dp->events.last_key_ticks = 0;
214        return _get_next_event(dp, ev);
[331]215    }
216
217    /* We are in autorepeat mode, but key has expired or a new key was
218     * pressed - store our event and return a key release event first */
[811]219    if(dp->events.last_key_event.type
220          && (dp->events.last_key_ticks > AUTOREPEAT_THRESHOLD
[681]221               || (ev->type & CACA_EVENT_KEY_PRESS)))
[331]222    {
[811]223        _push_event(dp, ev);
224        *ev = dp->events.last_key_event;
[681]225        ev->type = CACA_EVENT_KEY_RELEASE;
[811]226        dp->events.last_key_event.type = CACA_EVENT_NONE;
[681]227        return 1;
[331]228    }
229
230    /* A new key was pressed, enter autorepeat mode */
[681]231    if(ev->type & CACA_EVENT_KEY_PRESS)
[331]232    {
[811]233        dp->events.last_key_ticks = 0;
234        dp->events.autorepeat_ticks = 0;
235        dp->events.last_key_event = *ev;
[331]236    }
237
[681]238    return ev->type ? 1 : 0;
[331]239#endif
240}
241
[811]242static int _lowlevel_event(caca_display_t *dp, caca_event_t *ev)
[331]243{
[336]244#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
[811]245    int ret = _pop_event(dp, ev);
[336]246
[681]247    if(ret)
248        return ret;
[336]249#endif
[329]250
[811]251    return dp->drv.get_event(dp, ev);
[198]252}
253
[681]254#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
[811]255void _push_event(caca_display_t *dp, caca_event_t *ev)
[199]256{
[811]257    if(!ev->type || dp->events.queue == EVENTBUF_LEN)
[213]258        return;
[811]259    dp->events.buf[dp->events.queue] = *ev;
260    dp->events.queue++;
[199]261}
262
[811]263int _pop_event(caca_display_t *dp, caca_event_t *ev)
[199]264{
[213]265    int i;
266
[811]267    if(dp->events.queue == 0)
[681]268        return 0;
[199]269
[811]270    *ev = dp->events.buf[0];
271    for(i = 1; i < dp->events.queue; i++)
272        dp->events.buf[i - 1] = dp->events.buf[i];
273    dp->events.queue--;
[251]274
[681]275    return 1;
[199]276}
[336]277#endif
[199]278
Note: See TracBrowser for help on using the repository browser.