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.
 
 
 
 
 
 

237 lines
6.6 KiB

  1. /*
  2. * libcaca ASCII-Art library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  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.
  10. */
  11. /** \file event.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Event handling
  15. *
  16. * This file contains event handling functions for keyboard and mouse input.
  17. */
  18. #include "config.h"
  19. #include "cucul.h"
  20. #include "cucul_internals.h"
  21. #include "caca.h"
  22. #include "caca_internals.h"
  23. static unsigned int _get_next_event(caca_t *);
  24. static unsigned int _lowlevel_event(caca_t *);
  25. #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
  26. void _push_event(caca_t *, unsigned int);
  27. unsigned int _pop_event(caca_t *);
  28. #endif
  29. #if !defined(_DOXYGEN_SKIP_ME)
  30. /* If no new key was pressed after AUTOREPEAT_THRESHOLD usec, assume the
  31. * key was released */
  32. #define AUTOREPEAT_THRESHOLD 200000
  33. /* Start repeating key after AUTOREPEAT_TRIGGER usec and send keypress
  34. * events every AUTOREPEAT_RATE usec. */
  35. #define AUTOREPEAT_TRIGGER 300000
  36. #define AUTOREPEAT_RATE 100000
  37. #endif
  38. /** \brief Get the next mouse or keyboard input event.
  39. *
  40. * This function polls the event queue for mouse or keyboard events matching
  41. * the event mask and returns the first matching event. Non-matching events
  42. * are discarded. \c event_mask must have a non-zero value. This function is
  43. * non-blocking and returns zero if no more events are pending in the queue.
  44. * See also caca_wait_event() for a blocking version of this function.
  45. *
  46. * \param event_mask Bitmask of requested events.
  47. * \return The next matching event in the queue, or 0 if no event is pending.
  48. */
  49. unsigned int caca_get_event(caca_t *kk, unsigned int event_mask)
  50. {
  51. if(!event_mask)
  52. return CACA_EVENT_NONE;
  53. for( ; ; )
  54. {
  55. unsigned int event = _get_next_event(kk);
  56. if(!event || event & event_mask)
  57. return event;
  58. }
  59. }
  60. /** \brief Wait for the next mouse or keyboard input event.
  61. *
  62. * This function returns the first mouse or keyboard event in the queue
  63. * that matches the event mask. If no event is pending, it blocks until a
  64. * matching event is received. \c event_mask must have a non-zero value.
  65. * See also caca_get_event() for a non-blocking version of this function.
  66. *
  67. * \param event_mask Bitmask of requested events.
  68. * \return The next event in the queue.
  69. */
  70. unsigned int caca_wait_event(caca_t *kk, unsigned int event_mask)
  71. {
  72. if(!event_mask)
  73. return CACA_EVENT_NONE;
  74. for( ; ; )
  75. {
  76. unsigned int event = _get_next_event(kk);
  77. if(event & event_mask)
  78. return event;
  79. _caca_sleep(10000);
  80. }
  81. }
  82. /** \brief Return the X mouse coordinate.
  83. *
  84. * This function returns the X coordinate of the mouse position last time
  85. * it was detected. This function is not reliable if the ncurses or S-Lang
  86. * drivers are being used, because mouse position is only detected when
  87. * the mouse is clicked. Other drivers such as X11 work well.
  88. *
  89. * \return The X mouse coordinate.
  90. */
  91. unsigned int caca_get_mouse_x(caca_t *kk)
  92. {
  93. if(kk->mouse_x >= kk->qq->width)
  94. kk->mouse_x = kk->qq->width - 1;
  95. return kk->mouse_x;
  96. }
  97. /** \brief Return the Y mouse coordinate.
  98. *
  99. * This function returns the Y coordinate of the mouse position last time
  100. * it was detected. This function is not reliable if the ncurses or S-Lang
  101. * drivers are being used, because mouse position is only detected when
  102. * the mouse is clicked. Other drivers such as X11 work well.
  103. *
  104. * \return The Y mouse coordinate.
  105. */
  106. unsigned int caca_get_mouse_y(caca_t *kk)
  107. {
  108. if(kk->mouse_y >= kk->qq->height)
  109. kk->mouse_y = kk->qq->height - 1;
  110. return kk->mouse_y;
  111. }
  112. /*
  113. * XXX: The following functions are local.
  114. */
  115. static unsigned int _get_next_event(caca_t *kk)
  116. {
  117. #if defined(USE_SLANG) || defined(USE_NCURSES)
  118. unsigned int ticks;
  119. #endif
  120. unsigned int event;
  121. event = _lowlevel_event(kk);
  122. #if defined(USE_SLANG)
  123. if(kk->drv.driver != CACA_DRIVER_SLANG)
  124. #endif
  125. #if defined(USE_NCURSES)
  126. if(kk->drv.driver != CACA_DRIVER_NCURSES)
  127. #endif
  128. return event;
  129. #if defined(USE_SLANG) || defined(USE_NCURSES)
  130. /* Simulate long keypresses using autorepeat features */
  131. ticks = _caca_getticks(&kk->events.key_timer);
  132. kk->events.last_key_ticks += ticks;
  133. kk->events.autorepeat_ticks += ticks;
  134. /* Handle autorepeat */
  135. if(kk->events.last_key
  136. && kk->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
  137. && kk->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
  138. && kk->events.autorepeat_ticks > AUTOREPEAT_RATE)
  139. {
  140. _push_event(kk, event);
  141. kk->events.autorepeat_ticks -= AUTOREPEAT_RATE;
  142. return CACA_EVENT_KEY_PRESS | kk->events.last_key;
  143. }
  144. /* We are in autorepeat mode and the same key was just pressed, ignore
  145. * this event and return the next one by calling ourselves. */
  146. if(event == (CACA_EVENT_KEY_PRESS | kk->events.last_key))
  147. {
  148. kk->events.last_key_ticks = 0;
  149. return _get_next_event(kk);
  150. }
  151. /* We are in autorepeat mode, but key has expired or a new key was
  152. * pressed - store our event and return a key release event first */
  153. if(kk->events.last_key
  154. && (kk->events.last_key_ticks > AUTOREPEAT_THRESHOLD
  155. || (event & CACA_EVENT_KEY_PRESS)))
  156. {
  157. _push_event(kk, event);
  158. event = CACA_EVENT_KEY_RELEASE | kk->events.last_key;
  159. kk->events.last_key = 0;
  160. return event;
  161. }
  162. /* A new key was pressed, enter autorepeat mode */
  163. if(event & CACA_EVENT_KEY_PRESS)
  164. {
  165. kk->events.last_key_ticks = 0;
  166. kk->events.autorepeat_ticks = 0;
  167. kk->events.last_key = event & 0x00ffffff;
  168. }
  169. return event;
  170. #endif
  171. }
  172. static unsigned int _lowlevel_event(caca_t *kk)
  173. {
  174. #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
  175. unsigned int event = _pop_event(kk);
  176. if(event)
  177. return event;
  178. #endif
  179. return kk->drv.get_event(kk);
  180. }
  181. #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
  182. void _push_event(caca_t *kk, unsigned int event)
  183. {
  184. if(!event || kk->events.queue == EVENTBUF_LEN)
  185. return;
  186. kk->events.buf[kk->events.queue] = event;
  187. kk->events.queue++;
  188. }
  189. unsigned int _pop_event(caca_t *kk)
  190. {
  191. int i;
  192. unsigned int event;
  193. if(kk->events.queue == 0)
  194. return CACA_EVENT_NONE;
  195. event = kk->events.buf[0];
  196. for(i = 1; i < kk->events.queue; i++)
  197. kk->events.buf[i - 1] = kk->events.buf[i];
  198. kk->events.queue--;
  199. return event;
  200. }
  201. #endif