[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 777 2006-04-16 18:28:47Z 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" |
---|
| 19 | |
---|
[681] | 20 | #if !defined(__KERNEL__) |
---|
| 21 | # include <stdio.h> |
---|
| 22 | #endif |
---|
| 23 | |
---|
[524] | 24 | #include "cucul.h" |
---|
| 25 | #include "cucul_internals.h" |
---|
[185] | 26 | #include "caca.h" |
---|
| 27 | #include "caca_internals.h" |
---|
[17] | 28 | |
---|
[777] | 29 | static int _get_next_event(caca_t *, caca_event_t *); |
---|
| 30 | static int _lowlevel_event(caca_t *, caca_event_t *); |
---|
[199] | 31 | |
---|
[322] | 32 | #if !defined(_DOXYGEN_SKIP_ME) |
---|
[331] | 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 | |
---|
[268] | 42 | /** \brief Get the next mouse or keyboard input event. |
---|
[257] | 43 | * |
---|
[316] | 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 |
---|
[710] | 46 | * are discarded. \c event_mask must have a non-zero value. |
---|
[268] | 47 | * |
---|
[710] | 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 | * |
---|
[773] | 53 | * \param kk 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. |
---|
[257] | 58 | */ |
---|
[710] | 59 | int caca_get_event(caca_t *kk, unsigned int event_mask, |
---|
[777] | 60 | caca_event_t *ev, int timeout) |
---|
[79] | 61 | { |
---|
[777] | 62 | caca_timer_t timer; |
---|
[710] | 63 | int usec = 0; |
---|
| 64 | |
---|
[332] | 65 | if(!event_mask) |
---|
[681] | 66 | return 0; |
---|
[332] | 67 | |
---|
[710] | 68 | if(timeout > 0) |
---|
| 69 | _caca_getticks(&timer); |
---|
| 70 | |
---|
[316] | 71 | for( ; ; ) |
---|
| 72 | { |
---|
[681] | 73 | int ret = _get_next_event(kk, ev); |
---|
[316] | 74 | |
---|
[710] | 75 | /* If we got the event we wanted, return */ |
---|
| 76 | if(ev->type & event_mask) |
---|
[681] | 77 | return ret; |
---|
[316] | 78 | |
---|
[710] | 79 | /* If there is no timeout, sleep and try again. */ |
---|
| 80 | if(timeout < 0) |
---|
| 81 | { |
---|
| 82 | _caca_sleep(10000); |
---|
| 83 | continue; |
---|
| 84 | } |
---|
[332] | 85 | |
---|
[710] | 86 | /* If we timeouted, return an empty event */ |
---|
| 87 | if(usec >= timeout) |
---|
| 88 | { |
---|
| 89 | ev->type = CACA_EVENT_NONE; |
---|
| 90 | return 0; |
---|
| 91 | } |
---|
[316] | 92 | |
---|
[710] | 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); |
---|
[316] | 99 | |
---|
[710] | 100 | usec += _caca_getticks(&timer); |
---|
[316] | 101 | } |
---|
| 102 | } |
---|
| 103 | |
---|
[347] | 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 | * |
---|
[773] | 111 | * \param kk The libcaca graphical context. |
---|
[347] | 112 | * \return The X mouse coordinate. |
---|
| 113 | */ |
---|
[524] | 114 | unsigned int caca_get_mouse_x(caca_t *kk) |
---|
[347] | 115 | { |
---|
[551] | 116 | if(kk->mouse.x >= kk->qq->width) |
---|
| 117 | kk->mouse.x = kk->qq->width - 1; |
---|
[351] | 118 | |
---|
[551] | 119 | return kk->mouse.x; |
---|
[347] | 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 | * |
---|
[773] | 129 | * \param kk The libcaca graphical context. |
---|
[347] | 130 | * \return The Y mouse coordinate. |
---|
| 131 | */ |
---|
[524] | 132 | unsigned int caca_get_mouse_y(caca_t *kk) |
---|
[347] | 133 | { |
---|
[551] | 134 | if(kk->mouse.y >= kk->qq->height) |
---|
| 135 | kk->mouse.y = kk->qq->height - 1; |
---|
[351] | 136 | |
---|
[551] | 137 | return kk->mouse.y; |
---|
[347] | 138 | } |
---|
| 139 | |
---|
[316] | 140 | /* |
---|
| 141 | * XXX: The following functions are local. |
---|
| 142 | */ |
---|
| 143 | |
---|
[777] | 144 | static int _get_next_event(caca_t *kk, caca_event_t *ev) |
---|
[316] | 145 | { |
---|
[331] | 146 | #if defined(USE_SLANG) || defined(USE_NCURSES) |
---|
| 147 | unsigned int ticks; |
---|
[498] | 148 | #endif |
---|
[681] | 149 | int ret; |
---|
[487] | 150 | |
---|
[553] | 151 | /* If we are about to return a resize event, acknowledge it */ |
---|
| 152 | if(kk->resize.resized) |
---|
| 153 | { |
---|
| 154 | kk->resize.resized = 0; |
---|
| 155 | _caca_handle_resize(kk); |
---|
[681] | 156 | ev->type = CACA_EVENT_RESIZE; |
---|
| 157 | ev->data.resize.w = kk->qq->width; |
---|
| 158 | ev->data.resize.h = kk->qq->height; |
---|
| 159 | return 1; |
---|
[553] | 160 | } |
---|
| 161 | |
---|
[681] | 162 | ret = _lowlevel_event(kk, ev); |
---|
[331] | 163 | |
---|
| 164 | #if defined(USE_SLANG) |
---|
[550] | 165 | if(kk->drv.driver != CACA_DRIVER_SLANG) |
---|
[331] | 166 | #endif |
---|
| 167 | #if defined(USE_NCURSES) |
---|
[550] | 168 | if(kk->drv.driver != CACA_DRIVER_NCURSES) |
---|
[331] | 169 | #endif |
---|
[681] | 170 | return ret; |
---|
[331] | 171 | |
---|
| 172 | #if defined(USE_SLANG) || defined(USE_NCURSES) |
---|
| 173 | /* Simulate long keypresses using autorepeat features */ |
---|
[527] | 174 | ticks = _caca_getticks(&kk->events.key_timer); |
---|
| 175 | kk->events.last_key_ticks += ticks; |
---|
| 176 | kk->events.autorepeat_ticks += ticks; |
---|
[331] | 177 | |
---|
| 178 | /* Handle autorepeat */ |
---|
[681] | 179 | if(kk->events.last_key_event.type |
---|
[527] | 180 | && kk->events.autorepeat_ticks > AUTOREPEAT_TRIGGER |
---|
| 181 | && kk->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD |
---|
| 182 | && kk->events.autorepeat_ticks > AUTOREPEAT_RATE) |
---|
[331] | 183 | { |
---|
[681] | 184 | _push_event(kk, ev); |
---|
[527] | 185 | kk->events.autorepeat_ticks -= AUTOREPEAT_RATE; |
---|
[681] | 186 | *ev = kk->events.last_key_event; |
---|
| 187 | return 1; |
---|
[331] | 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. */ |
---|
[681] | 192 | if(ev->type == CACA_EVENT_KEY_PRESS |
---|
| 193 | && kk->events.last_key_event.type |
---|
| 194 | && ev->data.key.c == kk->events.last_key_event.data.key.c |
---|
| 195 | && ev->data.key.ucs4 == kk->events.last_key_event.data.key.ucs4) |
---|
[331] | 196 | { |
---|
[527] | 197 | kk->events.last_key_ticks = 0; |
---|
[681] | 198 | return _get_next_event(kk, ev); |
---|
[331] | 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 */ |
---|
[681] | 203 | if(kk->events.last_key_event.type |
---|
[527] | 204 | && (kk->events.last_key_ticks > AUTOREPEAT_THRESHOLD |
---|
[681] | 205 | || (ev->type & CACA_EVENT_KEY_PRESS))) |
---|
[331] | 206 | { |
---|
[681] | 207 | _push_event(kk, ev); |
---|
| 208 | *ev = kk->events.last_key_event; |
---|
| 209 | ev->type = CACA_EVENT_KEY_RELEASE; |
---|
| 210 | kk->events.last_key_event.type = CACA_EVENT_NONE; |
---|
| 211 | return 1; |
---|
[331] | 212 | } |
---|
| 213 | |
---|
| 214 | /* A new key was pressed, enter autorepeat mode */ |
---|
[681] | 215 | if(ev->type & CACA_EVENT_KEY_PRESS) |
---|
[331] | 216 | { |
---|
[527] | 217 | kk->events.last_key_ticks = 0; |
---|
| 218 | kk->events.autorepeat_ticks = 0; |
---|
[681] | 219 | kk->events.last_key_event = *ev; |
---|
[331] | 220 | } |
---|
| 221 | |
---|
[681] | 222 | return ev->type ? 1 : 0; |
---|
[331] | 223 | #endif |
---|
| 224 | } |
---|
| 225 | |
---|
[777] | 226 | static int _lowlevel_event(caca_t *kk, caca_event_t *ev) |
---|
[331] | 227 | { |
---|
[336] | 228 | #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) |
---|
[681] | 229 | int ret = _pop_event(kk, ev); |
---|
[336] | 230 | |
---|
[681] | 231 | if(ret) |
---|
| 232 | return ret; |
---|
[336] | 233 | #endif |
---|
[329] | 234 | |
---|
[681] | 235 | return kk->drv.get_event(kk, ev); |
---|
[198] | 236 | } |
---|
| 237 | |
---|
[681] | 238 | #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL) |
---|
[777] | 239 | void _push_event(caca_t *kk, caca_event_t *ev) |
---|
[199] | 240 | { |
---|
[681] | 241 | if(!ev->type || kk->events.queue == EVENTBUF_LEN) |
---|
[213] | 242 | return; |
---|
[681] | 243 | kk->events.buf[kk->events.queue] = *ev; |
---|
[541] | 244 | kk->events.queue++; |
---|
[199] | 245 | } |
---|
| 246 | |
---|
[777] | 247 | int _pop_event(caca_t *kk, caca_event_t *ev) |
---|
[199] | 248 | { |
---|
[213] | 249 | int i; |
---|
| 250 | |
---|
[541] | 251 | if(kk->events.queue == 0) |
---|
[681] | 252 | return 0; |
---|
[199] | 253 | |
---|
[681] | 254 | *ev = kk->events.buf[0]; |
---|
[541] | 255 | for(i = 1; i < kk->events.queue; i++) |
---|
| 256 | kk->events.buf[i - 1] = kk->events.buf[i]; |
---|
| 257 | kk->events.queue--; |
---|
[251] | 258 | |
---|
[681] | 259 | return 1; |
---|
[199] | 260 | } |
---|
[336] | 261 | #endif |
---|
[199] | 262 | |
---|