libcaca  0.99.beta19
About: libcaca is a graphics library that outputs text instead of pixels, so that it can work on older video cards or text terminals (something like an advanced AAlib library).
  Fossies Dox: libcaca-0.99.beta19.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

event.c
Go to the documentation of this file.
1 /*
2  * libcaca Colour ASCII-Art library
3  * Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
4  * All Rights Reserved
5  *
6  * This library is free software. It comes without any warranty, to
7  * the extent permitted by applicable law. You can redistribute it
8  * and/or modify it under the terms of the Do What the Fuck You Want
9  * to Public License, Version 2, as published by Sam Hocevar. See
10  * http://www.wtfpl.net/ for more details.
11  */
12 
13 /*
14  * This file contains event handling functions for keyboard and mouse input.
15  */
16 
17 #include "config.h"
18 
19 #if !defined(__KERNEL__)
20 # include <stdio.h>
21 # include <string.h>
22 #endif
23 
24 #include "caca.h"
25 #include "caca_internals.h"
26 
29 
30 #if !defined(_DOXYGEN_SKIP_ME)
31 /* If no new key was pressed after AUTOREPEAT_THRESHOLD usec, assume the
32  * key was released */
33 #define AUTOREPEAT_THRESHOLD 100000
34 /* Start repeating key after AUTOREPEAT_TRIGGER usec and send keypress
35  * events every AUTOREPEAT_RATE usec. */
36 #define AUTOREPEAT_TRIGGER 300000
37 #define AUTOREPEAT_RATE 20000
38 #endif
39 
63 int caca_get_event(caca_display_t *dp, int event_mask,
64  caca_event_t *ev, int timeout)
65 {
66  caca_privevent_t privevent;
67  caca_timer_t timer = {0, 0};
68 #if defined PROF
69  caca_timer_t proftimer = {0, 0};
70  int profsys = 0, profwait = 0;
71 #endif
72  int ret = 0, usec = 0;
73 
74 #if defined PROF
75  _caca_getticks(&proftimer);
76 #endif
77 
78  if(!event_mask)
79  goto end;
80 
81  if(timeout > 0)
83 
84  for( ; ; )
85  {
86 #if defined PROF
87  profwait += _caca_getticks(&proftimer);
88 #endif
89  ret = _get_next_event(dp, &privevent);
90 #if defined PROF
91  profsys += _caca_getticks(&proftimer);
92 #endif
93 
94  /* If we got the event we wanted, return */
95  if(privevent.type & event_mask)
96  {
97  if(ev)
98  memcpy(ev, &privevent, sizeof(privevent));
99  goto end;
100  }
101 
102  /* If there is no timeout, sleep and try again. */
103  if(timeout < 0)
104  {
105  _caca_sleep(1000);
106  continue;
107  }
108 
109  /* If we timeouted, return an empty event */
110  if(usec >= timeout)
111  {
112  privevent.type = CACA_EVENT_NONE;
113  if(ev)
114  memcpy(ev, &privevent, sizeof(privevent));
115  ret = 0;
116  goto end;
117  }
118 
119  /* Otherwise sleep a bit. Our granularity is far too high for values
120  * below 10000 microseconds so we cheat a bit. */
121  _caca_sleep(usec > 10000 ? 10000 : 1000);
122 
123  usec += _caca_getticks(&timer);
124  }
125 
126 end:
127 #if defined PROF
128  profwait += _caca_getticks(&proftimer);
129  STAT_IADD(&dp->ev_sys_stat, profsys);
130  STAT_IADD(&dp->ev_wait_stat, profwait);
131 #endif
132 
133  return ret;
134 }
135 
149 {
150  int width = caca_get_canvas_width(dp->cv);
151 
152  if(dp->mouse.x >= width)
153  return width - 1;
154 
155  return dp->mouse.x;
156 }
157 
171 {
172  int height = caca_get_canvas_height(dp->cv);
173 
174  if(dp->mouse.y >= height)
175  return height - 1;
176 
177  return dp->mouse.y;
178 }
179 
203 {
204  return ((caca_privevent_t const *)ev)->type;
205 }
206 
220 {
221  return ((caca_privevent_t const *)ev)->data.key.ch;
222 }
223 
237 {
238  return ((caca_privevent_t const *)ev)->data.key.utf32;
239 }
240 
256 int caca_get_event_key_utf8(caca_event_t const *ev, char *utf8)
257 {
258  memcpy(utf8, ((caca_privevent_t const *)ev)->data.key.utf8, 8);
259  return 0;
260 }
261 
277 {
278  return ((caca_privevent_t const *)ev)->data.mouse.button;
279 }
280 
293 {
294  return ((caca_privevent_t const *)ev)->data.mouse.x;
295 }
296 
309 {
310  return ((caca_privevent_t const *)ev)->data.mouse.y;
311 }
312 
325 {
326  return ((caca_privevent_t const *)ev)->data.resize.w;
327 }
328 
341 {
342  return ((caca_privevent_t const *)ev)->data.resize.h;
343 }
344 
345 /*
346  * XXX: The following functions are local.
347  */
348 
350 {
351 #if defined(USE_SLANG) || defined(USE_NCURSES)
352  int ticks;
353 #endif
354  int ret;
355 
356  /* If we are about to return a resize event, acknowledge it */
357  if(dp->resize.resized)
358  {
359  dp->resize.resized = 0;
361  ev->type = CACA_EVENT_RESIZE;
364  return 1;
365  }
366 
367  ret = _lowlevel_event(dp, ev);
368 
369 #if defined(USE_SLANG)
370  if(dp->drv.id != CACA_DRIVER_SLANG)
371 #endif
372 #if defined(USE_NCURSES)
373  if(dp->drv.id != CACA_DRIVER_NCURSES)
374 #endif
375  return ret;
376 
377 #if defined(USE_SLANG) || defined(USE_NCURSES)
378  /* Simulate long keypresses using autorepeat features */
379  ticks = _caca_getticks(&dp->events.key_timer);
380  dp->events.last_key_ticks += ticks;
381  dp->events.autorepeat_ticks += ticks;
382 
383  /* Handle autorepeat */
384  if(dp->events.last_key_event.type
385  && dp->events.autorepeat_ticks > AUTOREPEAT_TRIGGER
386  && dp->events.autorepeat_ticks > AUTOREPEAT_THRESHOLD
387  && dp->events.autorepeat_ticks > AUTOREPEAT_RATE)
388  {
389  _push_event(dp, ev);
390  dp->events.autorepeat_ticks -= AUTOREPEAT_RATE;
391  *ev = dp->events.last_key_event;
392  return 1;
393  }
394 
395  /* We are in autorepeat mode and the same key was just pressed, ignore
396  * this event and return the next one by calling ourselves. */
397  if(ev->type == CACA_EVENT_KEY_PRESS
398  && dp->events.last_key_event.type
399  && ev->data.key.ch == dp->events.last_key_event.data.key.ch
400  && ev->data.key.utf32 == dp->events.last_key_event.data.key.utf32)
401  {
402  dp->events.last_key_ticks = 0;
403  return _get_next_event(dp, ev);
404  }
405 
406  /* We are in autorepeat mode, but key has expired or a new key was
407  * pressed - store our event and return a key release event first */
408  if(dp->events.last_key_event.type
409  && (dp->events.last_key_ticks > AUTOREPEAT_THRESHOLD
410  || (ev->type & CACA_EVENT_KEY_PRESS)))
411  {
412  _push_event(dp, ev);
413  *ev = dp->events.last_key_event;
415  dp->events.last_key_event.type = CACA_EVENT_NONE;
416  return 1;
417  }
418 
419  /* A new key was pressed, enter autorepeat mode */
420  if(ev->type & CACA_EVENT_KEY_PRESS)
421  {
422  dp->events.last_key_ticks = 0;
423  dp->events.autorepeat_ticks = 0;
424  dp->events.last_key_event = *ev;
425  }
426 
427  return ev->type ? 1 : 0;
428 #endif
429 }
430 
432 {
433 #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO)
434  int ret = _pop_event(dp, ev);
435 
436  if(ret)
437  return ret;
438 #endif
439 
440  return dp->drv.get_event(dp, ev);
441 }
442 
443 #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
444 void _push_event(caca_display_t *dp, caca_privevent_t *ev)
445 {
446  if(!ev->type || dp->events.queue == EVENTBUF_LEN)
447  return;
448  dp->events.buf[dp->events.queue] = *ev;
449  dp->events.queue++;
450 }
451 
452 int _pop_event(caca_display_t *dp, caca_privevent_t *ev)
453 {
454  int i;
455 
456  if(dp->events.queue == 0)
457  return 0;
458 
459  *ev = dp->events.buf[0];
460  for(i = 1; i < dp->events.queue; i++)
461  dp->events.buf[i - 1] = dp->events.buf[i];
462  dp->events.queue--;
463 
464  return 1;
465 }
466 #endif
467 
caca_privevent::type
enum caca_event_type type
Definition: caca_internals.h:156
caca_display::drv::id
enum caca_driver id
Definition: caca_internals.h:181
caca_get_event_resize_height
int caca_get_event_resize_height(caca_event_t const *ev)
Return a resize event's display height value.
Definition: event.c:340
caca_display::drv::get_event
int(* get_event)(caca_display_t *, caca_privevent_t *)
Definition: caca_internals.h:191
caca_display::drv
struct caca_display::drv drv
caca_get_event_key_utf8
int caca_get_event_key_utf8(caca_event_t const *ev, char *utf8)
Return a key press or key release event's UTF-8 value.
Definition: event.c:256
caca_display::mouse::y
int y
Definition: caca_internals.h:199
caca_display::cv
caca_canvas_t * cv
Definition: caca_internals.h:170
caca_display::resize
struct caca_display::resize resize
caca_event
Handling of user events.
Definition: caca.h:129
caca_display
Definition: caca_internals.h:167
caca_timer
Definition: caca_internals.h:140
caca_get_event_type
enum caca_event_type caca_get_event_type(caca_event_t const *ev)
Return an event's type.
Definition: event.c:202
caca_get_canvas_height
int caca_get_canvas_height(caca_canvas_t const *)
Get the canvas height.
Definition: canvas.c:253
_caca_handle_resize
void _caca_handle_resize(caca_display_t *)
Definition: graphics.c:259
caca_get_event_mouse_y
int caca_get_event_mouse_y(caca_event_t const *ev)
Return a mouse motion event's Y coordinate.
Definition: event.c:308
caca_get_canvas_width
int caca_get_canvas_width(caca_canvas_t const *)
Get the canvas width.
Definition: canvas.c:239
caca_privevent::resize
struct caca_privevent::@5::@7 resize
_lowlevel_event
static int _lowlevel_event(caca_display_t *, caca_privevent_t *)
Definition: event.c:431
caca_get_event_mouse_button
int caca_get_event_mouse_button(caca_event_t const *ev)
Return a mouse press or mouse release event's button.
Definition: event.c:276
caca_display::mouse::x
int x
Definition: caca_internals.h:199
caca_display::mouse
struct caca_display::mouse mouse
AUTOREPEAT_RATE
#define AUTOREPEAT_RATE
Definition: event.c:37
caca_get_event
int caca_get_event(caca_display_t *dp, int event_mask, caca_event_t *ev, int timeout)
Get the next mouse or keyboard input event.
Definition: event.c:63
caca_get_event_resize_width
int caca_get_event_resize_width(caca_event_t const *ev)
Return a resize event's display width value.
Definition: event.c:324
CACA_EVENT_RESIZE
Definition: caca.h:116
caca_get_mouse_x
int caca_get_mouse_x(caca_display_t const *dp)
Return the X mouse coordinate.
Definition: event.c:148
caca_get_event_key_utf32
uint32_t caca_get_event_key_utf32(caca_event_t const *ev)
Return a key press or key release event's Unicode value.
Definition: event.c:236
_get_next_event
static int _get_next_event(caca_display_t *, caca_privevent_t *)
Definition: event.c:349
CACA_EVENT_NONE
Definition: caca.h:109
_caca_getticks
int _caca_getticks(caca_timer_t *)
Definition: time.c:47
caca_privevent::data
union caca_privevent::@5 data
caca_internals.h
caca_display::events
struct caca_display::events events
caca_display::resize::resized
int resized
Definition: caca_internals.h:205
CACA_EVENT_KEY_RELEASE
Definition: caca.h:112
caca.h
The libcaca public header.
caca_privevent::key
struct caca_privevent::@5::@8 key
caca_get_event_mouse_x
int caca_get_event_mouse_x(caca_event_t const *ev)
Return a mouse motion event's X coordinate.
Definition: event.c:292
caca_get_mouse_y
int caca_get_mouse_y(caca_display_t const *dp)
Return the Y mouse coordinate.
Definition: event.c:170
timer
static caca_timer_t timer
Generate a random integer within a range.
Definition: canvas.c:344
AUTOREPEAT_TRIGGER
#define AUTOREPEAT_TRIGGER
Definition: event.c:36
config.h
AUTOREPEAT_THRESHOLD
#define AUTOREPEAT_THRESHOLD
Definition: event.c:33
CACA_EVENT_KEY_PRESS
Definition: caca.h:111
caca_privevent
Definition: caca_internals.h:154
EVENTBUF_LEN
#define EVENTBUF_LEN
Definition: caca_internals.h:25
STAT_IADD
#define STAT_IADD(_s, _n)
Definition: caca_prof.h:40
dp
caca_display_t * dp
Definition: cacaview.c:45
caca_get_event_key_ch
int caca_get_event_key_ch(caca_event_t const *ev)
Return a key press or key release event's value.
Definition: event.c:219
_caca_sleep
void _caca_sleep(int)
Definition: time.c:36
caca_event_type
caca_event_type
User event type enumeration.
Definition: caca.h:107