Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

261 rader
7.3 KiB

  1. /*
  2. * libcaca Colour 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. #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_t *, struct caca_event *);
  27. static int _lowlevel_event(caca_t *, struct caca_event *);
  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 200000
  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. * This function polls the event queue for mouse or keyboard events matching
  40. * the event mask and returns the first matching event. Non-matching events
  41. * are discarded. \c event_mask must have a non-zero value.
  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. * \param event_mask Bitmask of requested events.
  49. * \param timeout A timeout value in microseconds
  50. * \return The next matching event in the queue, or 0 if no event is pending.
  51. */
  52. int caca_get_event(caca_t *kk, unsigned int event_mask,
  53. struct caca_event *ev, int timeout)
  54. {
  55. struct caca_timer timer;
  56. int usec = 0;
  57. if(!event_mask)
  58. return 0;
  59. if(timeout > 0)
  60. _caca_getticks(&timer);
  61. for( ; ; )
  62. {
  63. int ret = _get_next_event(kk, ev);
  64. /* If we got the event we wanted, return */
  65. if(ev->type & event_mask)
  66. return ret;
  67. /* If there is no timeout, sleep and try again. */
  68. if(timeout < 0)
  69. {
  70. _caca_sleep(10000);
  71. continue;
  72. }
  73. /* If we timeouted, return an empty event */
  74. if(usec >= timeout)
  75. {
  76. ev->type = CACA_EVENT_NONE;
  77. return 0;
  78. }
  79. /* Otherwise sleep a bit. Our granularity is far too high for values
  80. * below 10000 microseconds so we cheat a bit. */
  81. if(usec > 10000)
  82. _caca_sleep(10000);
  83. else
  84. _caca_sleep(1000);
  85. usec += _caca_getticks(&timer);
  86. }
  87. }
  88. /** \brief Return the X mouse coordinate.
  89. *
  90. * This function returns the X coordinate of the mouse position last time
  91. * it was detected. This function is not reliable if the ncurses or S-Lang
  92. * drivers are being used, because mouse position is only detected when
  93. * the mouse is clicked. Other drivers such as X11 work well.
  94. *
  95. * \return The X mouse coordinate.
  96. */
  97. unsigned int caca_get_mouse_x(caca_t *kk)
  98. {
  99. if(kk->mouse.x >= kk->qq->width)
  100. kk->mouse.x = kk->qq->width - 1;
  101. return kk->mouse.x;
  102. }
  103. /** \brief Return the Y mouse coordinate.
  104. *
  105. * This function returns the Y coordinate of the mouse position last time
  106. * it was detected. This function is not reliable if the ncurses or S-Lang
  107. * drivers are being used, because mouse position is only detected when
  108. * the mouse is clicked. Other drivers such as X11 work well.
  109. *
  110. * \return The Y mouse coordinate.
  111. */
  112. unsigned int caca_get_mouse_y(caca_t *kk)
  113. {
  114. if(kk->mouse.y >= kk->qq->height)
  115. kk->mouse.y = kk->qq->height - 1;
  116. return kk->mouse.y;
  117. }
  118. /*
  119. * XXX: The following functions are local.
  120. */
  121. static int _get_next_event(caca_t *kk, struct caca_event *ev)
  122. {
  123. #if defined(USE_SLANG) || defined(USE_NCURSES)
  124. unsigned int ticks;
  125. #endif
  126. int ret;
  127. /* If we are about to return a resize event, acknowledge it */
  128. if(kk->resize.resized)
  129. {
  130. kk->resize.resized = 0;
  131. _caca_handle_resize(kk);
  132. ev->type = CACA_EVENT_RESIZE;
  133. ev->data.resize.w = kk->qq->width;
  134. ev->data.resize.h = kk->qq->height;
  135. return 1;
  136. }
  137. ret = _lowlevel_event(kk, ev);
  138. #if defined(USE_SLANG)
  139. if(kk->drv.driver != CACA_DRIVER_SLANG)
  140. #endif
  141. #if defined(USE_NCURSES)
  142. if(kk->drv.driver != CACA_DRIVER_NCURSES)
  143. #endif
  144. return ret;
  145. #if defined(USE_SLANG) || defined(USE_NCURSES)
  146. /* Simulate long keypresses using autorepeat features */
  147. ticks = _caca_getticks(&kk->events.key_timer);
  148. kk->events.last_key_ticks += ticks;
  149. kk->events.autorepeat_ticks += ticks;
  150. /* Handle autorepeat */
  151. if(kk->events.last_key_event.type
  152. && kk->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
  153. && kk->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
  154. && kk->events.autorepeat_ticks > AUTOREPEAT_RATE)
  155. {
  156. _push_event(kk, ev);
  157. kk->events.autorepeat_ticks -= AUTOREPEAT_RATE;
  158. *ev = kk->events.last_key_event;
  159. return 1;
  160. }
  161. /* We are in autorepeat mode and the same key was just pressed, ignore
  162. * this event and return the next one by calling ourselves. */
  163. if(ev->type == CACA_EVENT_KEY_PRESS
  164. && kk->events.last_key_event.type
  165. && ev->data.key.c == kk->events.last_key_event.data.key.c
  166. && ev->data.key.ucs4 == kk->events.last_key_event.data.key.ucs4)
  167. {
  168. kk->events.last_key_ticks = 0;
  169. return _get_next_event(kk, ev);
  170. }
  171. /* We are in autorepeat mode, but key has expired or a new key was
  172. * pressed - store our event and return a key release event first */
  173. if(kk->events.last_key_event.type
  174. && (kk->events.last_key_ticks > AUTOREPEAT_THRESHOLD
  175. || (ev->type & CACA_EVENT_KEY_PRESS)))
  176. {
  177. _push_event(kk, ev);
  178. *ev = kk->events.last_key_event;
  179. ev->type = CACA_EVENT_KEY_RELEASE;
  180. kk->events.last_key_event.type = CACA_EVENT_NONE;
  181. return 1;
  182. }
  183. /* A new key was pressed, enter autorepeat mode */
  184. if(ev->type & CACA_EVENT_KEY_PRESS)
  185. {
  186. kk->events.last_key_ticks = 0;
  187. kk->events.autorepeat_ticks = 0;
  188. kk->events.last_key_event = *ev;
  189. }
  190. return ev->type ? 1 : 0;
  191. #endif
  192. }
  193. static int _lowlevel_event(caca_t *kk, struct caca_event *ev)
  194. {
  195. #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
  196. int ret = _pop_event(kk, ev);
  197. if(ret)
  198. return ret;
  199. #endif
  200. return kk->drv.get_event(kk, ev);
  201. }
  202. #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
  203. void _push_event(caca_t *kk, struct caca_event *ev)
  204. {
  205. if(!ev->type || kk->events.queue == EVENTBUF_LEN)
  206. return;
  207. kk->events.buf[kk->events.queue] = *ev;
  208. kk->events.queue++;
  209. }
  210. int _pop_event(caca_t *kk, struct caca_event *ev)
  211. {
  212. int i;
  213. if(kk->events.queue == 0)
  214. return 0;
  215. *ev = kk->events.buf[0];
  216. for(i = 1; i < kk->events.queue; i++)
  217. kk->events.buf[i - 1] = kk->events.buf[i];
  218. kk->events.queue--;
  219. return 1;
  220. }
  221. #endif