Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

279 linhas
7.9 KiB

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