You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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