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.
 
 
 
 
 
 

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