Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

245 řádky
6.8 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. /* If we are about to return a resize event, acknowledge it */
  122. if(kk->resize.resized)
  123. {
  124. kk->resize.resized = 0;
  125. _caca_handle_resize(kk);
  126. return CACA_EVENT_RESIZE;
  127. }
  128. event = _lowlevel_event(kk);
  129. #if defined(USE_SLANG)
  130. if(kk->drv.driver != CACA_DRIVER_SLANG)
  131. #endif
  132. #if defined(USE_NCURSES)
  133. if(kk->drv.driver != CACA_DRIVER_NCURSES)
  134. #endif
  135. return event;
  136. #if defined(USE_SLANG) || defined(USE_NCURSES)
  137. /* Simulate long keypresses using autorepeat features */
  138. ticks = _caca_getticks(&kk->events.key_timer);
  139. kk->events.last_key_ticks += ticks;
  140. kk->events.autorepeat_ticks += ticks;
  141. /* Handle autorepeat */
  142. if(kk->events.last_key
  143. && kk->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
  144. && kk->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
  145. && kk->events.autorepeat_ticks > AUTOREPEAT_RATE)
  146. {
  147. _push_event(kk, event);
  148. kk->events.autorepeat_ticks -= AUTOREPEAT_RATE;
  149. return CACA_EVENT_KEY_PRESS | kk->events.last_key;
  150. }
  151. /* We are in autorepeat mode and the same key was just pressed, ignore
  152. * this event and return the next one by calling ourselves. */
  153. if(event == (CACA_EVENT_KEY_PRESS | kk->events.last_key))
  154. {
  155. kk->events.last_key_ticks = 0;
  156. return _get_next_event(kk);
  157. }
  158. /* We are in autorepeat mode, but key has expired or a new key was
  159. * pressed - store our event and return a key release event first */
  160. if(kk->events.last_key
  161. && (kk->events.last_key_ticks > AUTOREPEAT_THRESHOLD
  162. || (event & CACA_EVENT_KEY_PRESS)))
  163. {
  164. _push_event(kk, event);
  165. event = CACA_EVENT_KEY_RELEASE | kk->events.last_key;
  166. kk->events.last_key = 0;
  167. return event;
  168. }
  169. /* A new key was pressed, enter autorepeat mode */
  170. if(event & CACA_EVENT_KEY_PRESS)
  171. {
  172. kk->events.last_key_ticks = 0;
  173. kk->events.autorepeat_ticks = 0;
  174. kk->events.last_key = event & 0x00ffffff;
  175. }
  176. return event;
  177. #endif
  178. }
  179. static unsigned int _lowlevel_event(caca_t *kk)
  180. {
  181. #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
  182. unsigned int event = _pop_event(kk);
  183. if(event)
  184. return event;
  185. #endif
  186. return kk->drv.get_event(kk);
  187. }
  188. #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
  189. void _push_event(caca_t *kk, unsigned int event)
  190. {
  191. if(!event || kk->events.queue == EVENTBUF_LEN)
  192. return;
  193. kk->events.buf[kk->events.queue] = event;
  194. kk->events.queue++;
  195. }
  196. unsigned int _pop_event(caca_t *kk)
  197. {
  198. int i;
  199. unsigned int event;
  200. if(kk->events.queue == 0)
  201. return CACA_EVENT_NONE;
  202. event = kk->events.buf[0];
  203. for(i = 1; i < kk->events.queue; i++)
  204. kk->events.buf[i - 1] = kk->events.buf[i];
  205. kk->events.queue--;
  206. return event;
  207. }
  208. #endif