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

Last change on this file since 692 was 681, checked in by Sam Hocevar, 14 years ago
  • Massive rework of the event handling code, as per the TODO list.
  • Property svn:keywords set to Id
File size: 7.1 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 *
[268]6 *  This library is free software; you can redistribute it and/or
[522]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.
[35]10 */
[17]11
[345]12/** \file event.c
[268]13 *  \version \$Id: event.c 681 2006-03-23 18:36:59Z sam $
14 *  \author Sam Hocevar <sam@zoy.org>
[298]15 *  \brief Event handling
[205]16 *
[268]17 *  This file contains event handling functions for keyboard and mouse input.
[205]18 */
19
[63]20#include "config.h"
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
[681]31static int _get_next_event(caca_t *, struct caca_event *);
32static int _lowlevel_event(caca_t *, struct caca_event *);
[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 */
37#define AUTOREPEAT_THRESHOLD 200000
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 *
[316]46 *  This function polls the event queue for mouse or keyboard events matching
47 *  the event mask and returns the first matching event. Non-matching events
[332]48 *  are discarded. \c event_mask must have a non-zero value. This function is
49 *  non-blocking and returns zero if no more events are pending in the queue.
50 *  See also caca_wait_event() for a blocking version of this function.
[268]51 *
[316]52 * \param event_mask Bitmask of requested events.
53 * \return The next matching event in the queue, or 0 if no event is pending.
[257]54 */
[681]55int caca_get_event(caca_t *kk, unsigned int event_mask, struct caca_event *ev)
[79]56{
[332]57    if(!event_mask)
[681]58        return 0;
[332]59
[316]60    for( ; ; )
61    {
[681]62        int ret = _get_next_event(kk, ev);
[316]63
[681]64        if(!ret || ev->type & event_mask)
65            return ret;
[316]66    }
67}
68
69/** \brief Wait for the next mouse or keyboard input event.
70 *
71 *  This function returns the first mouse or keyboard event in the queue
72 *  that matches the event mask. If no event is pending, it blocks until a
[332]73 *  matching event is received. \c event_mask must have a non-zero value.
74 *  See also caca_get_event() for a non-blocking version of this function.
[316]75 *
76 *  \param event_mask Bitmask of requested events.
77 *  \return The next event in the queue.
78 */
[681]79int caca_wait_event(caca_t *kk, unsigned int event_mask, struct caca_event *ev)
[316]80{
[332]81    if(!event_mask)
[681]82        return 0;
[332]83
[316]84    for( ; ; )
85    {
[681]86        int ret = _get_next_event(kk, ev);
[316]87
[681]88        if(ret && (ev->type & event_mask))
89            return ret;
[316]90
[335]91        _caca_sleep(10000);
[316]92    }
93}
94
[347]95/** \brief Return the X mouse coordinate.
96 *
97 *  This function returns the X coordinate of the mouse position last time
98 *  it was detected. This function is not reliable if the ncurses or S-Lang
99 *  drivers are being used, because mouse position is only detected when
100 *  the mouse is clicked. Other drivers such as X11 work well.
101 *
102 *  \return The X mouse coordinate.
103 */
[524]104unsigned int caca_get_mouse_x(caca_t *kk)
[347]105{
[551]106    if(kk->mouse.x >= kk->qq->width)
107        kk->mouse.x = kk->qq->width - 1;
[351]108
[551]109    return kk->mouse.x;
[347]110}
111
112/** \brief Return the Y mouse coordinate.
113 *
114 *  This function returns the Y coordinate of the mouse position last time
115 *  it was detected. This function is not reliable if the ncurses or S-Lang
116 *  drivers are being used, because mouse position is only detected when
117 *  the mouse is clicked. Other drivers such as X11 work well.
118 *
119 *  \return The Y mouse coordinate.
120 */
[524]121unsigned int caca_get_mouse_y(caca_t *kk)
[347]122{
[551]123    if(kk->mouse.y >= kk->qq->height)
124        kk->mouse.y = kk->qq->height - 1;
[351]125
[551]126    return kk->mouse.y;
[347]127}
128
[316]129/*
130 * XXX: The following functions are local.
131 */
132
[681]133static int _get_next_event(caca_t *kk, struct caca_event *ev)
[316]134{
[331]135#if defined(USE_SLANG) || defined(USE_NCURSES)
136    unsigned int ticks;
[498]137#endif
[681]138    int ret;
[487]139
[553]140    /* If we are about to return a resize event, acknowledge it */
141    if(kk->resize.resized)
142    {
143        kk->resize.resized = 0;
144        _caca_handle_resize(kk);
[681]145        ev->type = CACA_EVENT_RESIZE;
146        ev->data.resize.w = kk->qq->width;
147        ev->data.resize.h = kk->qq->height;
148        return 1;
[553]149    }
150
[681]151    ret = _lowlevel_event(kk, ev);
[331]152
153#if defined(USE_SLANG)
[550]154    if(kk->drv.driver != CACA_DRIVER_SLANG)
[331]155#endif
156#if defined(USE_NCURSES)
[550]157    if(kk->drv.driver != CACA_DRIVER_NCURSES)
[331]158#endif
[681]159    return ret;
[331]160
161#if defined(USE_SLANG) || defined(USE_NCURSES)
162    /* Simulate long keypresses using autorepeat features */
[527]163    ticks = _caca_getticks(&kk->events.key_timer);
164    kk->events.last_key_ticks += ticks;
165    kk->events.autorepeat_ticks += ticks;
[331]166
167    /* Handle autorepeat */
[681]168    if(kk->events.last_key_event.type
[527]169           && kk->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
170           && kk->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
171           && kk->events.autorepeat_ticks > AUTOREPEAT_RATE)
[331]172    {
[681]173        _push_event(kk, ev);
[527]174        kk->events.autorepeat_ticks -= AUTOREPEAT_RATE;
[681]175        *ev = kk->events.last_key_event;
176        return 1;
[331]177    }
178
179    /* We are in autorepeat mode and the same key was just pressed, ignore
180     * this event and return the next one by calling ourselves. */
[681]181    if(ev->type == CACA_EVENT_KEY_PRESS
182        && kk->events.last_key_event.type
183        && ev->data.key.c == kk->events.last_key_event.data.key.c
184        && ev->data.key.ucs4 == kk->events.last_key_event.data.key.ucs4)
[331]185    {
[527]186        kk->events.last_key_ticks = 0;
[681]187        return _get_next_event(kk, ev);
[331]188    }
189
190    /* We are in autorepeat mode, but key has expired or a new key was
191     * pressed - store our event and return a key release event first */
[681]192    if(kk->events.last_key_event.type
[527]193          && (kk->events.last_key_ticks > AUTOREPEAT_THRESHOLD
[681]194               || (ev->type & CACA_EVENT_KEY_PRESS)))
[331]195    {
[681]196        _push_event(kk, ev);
197        *ev = kk->events.last_key_event;
198        ev->type = CACA_EVENT_KEY_RELEASE;
199        kk->events.last_key_event.type = CACA_EVENT_NONE;
200        return 1;
[331]201    }
202
203    /* A new key was pressed, enter autorepeat mode */
[681]204    if(ev->type & CACA_EVENT_KEY_PRESS)
[331]205    {
[527]206        kk->events.last_key_ticks = 0;
207        kk->events.autorepeat_ticks = 0;
[681]208        kk->events.last_key_event = *ev;
[331]209    }
210
[681]211    return ev->type ? 1 : 0;
[331]212#endif
213}
214
[681]215static int _lowlevel_event(caca_t *kk, struct caca_event *ev)
[331]216{
[336]217#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
[681]218    int ret = _pop_event(kk, ev);
[336]219
[681]220    if(ret)
221        return ret;
[336]222#endif
[329]223
[681]224    return kk->drv.get_event(kk, ev);
[198]225}
226
[681]227#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
228void _push_event(caca_t *kk, struct caca_event *ev)
[199]229{
[681]230    if(!ev->type || kk->events.queue == EVENTBUF_LEN)
[213]231        return;
[681]232    kk->events.buf[kk->events.queue] = *ev;
[541]233    kk->events.queue++;
[199]234}
235
[681]236int _pop_event(caca_t *kk, struct caca_event *ev)
[199]237{
[213]238    int i;
239
[541]240    if(kk->events.queue == 0)
[681]241        return 0;
[199]242
[681]243    *ev = kk->events.buf[0];
[541]244    for(i = 1; i < kk->events.queue; i++)
245        kk->events.buf[i - 1] = kk->events.buf[i];
246    kk->events.queue--;
[251]247
[681]248    return 1;
[199]249}
[336]250#endif
[199]251
Note: See TracBrowser for help on using the repository browser.