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

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