[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] | 31 | static int _get_next_event(caca_t *, struct caca_event *); |
---|
| 32 | static 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] | 55 | int 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] | 79 | int 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] | 104 | unsigned 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] | 121 | unsigned 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] | 133 | static 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] | 215 | static 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) |
---|
| 228 | void _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] | 236 | int _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 | |
---|