Tachyon (current)  Current Main Branch
eventio.c
Go to the documentation of this file.
1 /*
2  * eventio.c - Input device event I/O for modern Linux kernels,
3  * for joysticks and other input devices connected by
4  * hot-plug USB and Bluetooth interfaces
5  *
6  * (C) Copyright 1994-2022 John E. Stone
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  * $Id: eventio.c,v 1.4 2022/02/18 18:18:36 johns Exp $
10  *
11  */
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <sys/time.h>
20 #include <linux/input.h>
21 
22 #include "eventio.h"
23 
24 /*
25  * Docs for low-level Linux kernel event I/O API:
26  * https://www.kernel.org/doc/Documentation/input/event-codes.txt
27  #
28  * Compile stand-alone test program:
29  * cc -DTEST_MAIN=1 eventio.c -o /tmp/evtest
30  */
31 
32 /*
33  * xorg.conf entry to prevent X from using a joystick to control the pointer
34  */
35 /*
36  /etc/X11/xorg.conf.d/50-joystick.conf
37  Section "InputClass"
38  Identifier "joystick catchall"
39  MatchIsJoystick "on"
40  MatchDevicePath "/dev/input/event*"
41  Driver "joystick"
42  Option "StartKeysEnabled" "False" #Disable mouse
43  Option "StartMouseEnabled" "False" #support
44  EndSection
45 
46  Another scheme to disable X interference:
47  sudo apt-get install xserver-xorg-input-joystick
48  xinput list
49  xinput --set-prop "DEVICE NAME" "Device Enabled" 0
50 
51 */
52 
53 
54 #ifdef __cplusplus
55 extern "C" {
56 #endif
57 
58 /*
59  * Add macros that are missing for older linux kernels
60  */
61 #if !defined(REL_RX)
62 #define REL_RX 0x03
63 #endif
64 #if !defined(REL_RY)
65 #define REL_RY 0x04
66 #endif
67 #if !defined(REL_RZ)
68 #define REL_RZ 0x05
69 #endif
70 
71 /* macro to round up bit count into next whole long, avoid use of */
72 /* linux kernel header macros that are not universally available */
73 #define EVIO_LBIT (8*sizeof(long))
74 #define EVIO_BITSTOLONGS(bnr) (((bnr) + EVIO_LBIT - 1) / EVIO_LBIT)
75 
76 /* mask off selected bit in array of longs and test it */
77 #define EVIO_TESTBIT(bnr, array) \
78  (((1UL << ((bnr)&(EVIO_LBIT-1))) & ((array)[(bnr)/EVIO_LBIT]))!=0)
79 
80 typedef struct {
81  int fd;
82  char devpath[2048];
83  char devname[2048];
84  struct input_id devid;
85  unsigned long evbit[EVIO_BITSTOLONGS( EV_MAX)];
86  unsigned long keybit[EVIO_BITSTOLONGS(KEY_MAX)];
87  unsigned long keystate[EVIO_BITSTOLONGS(KEY_MAX)];
88  unsigned long absbit[EVIO_BITSTOLONGS(ABS_MAX)];
89  unsigned long relbit[EVIO_BITSTOLONGS(REL_MAX)];
90  struct input_event inpev;
93 } evio;
94 
95 
96 evio_handle evio_open(const char *devpath) {
97  evio *evp = NULL;
98  int fd;
99  if ((fd = open(devpath, O_RDONLY, 0)) < 0) {
100  printf("Failed to open device '%s' ...\n", devpath);
101  return NULL;
102  }
103 
104  evp = (evio *) calloc(1, sizeof(evio));
105  evp->fd = fd;
106  strncpy(evp->devpath, devpath, sizeof(evp->devpath));
107 
108  if (ioctl(evp->fd, EVIOCGNAME(sizeof(evp->devname)), evp->devname) < 0) {
109  printf("Error) EVIOCGNAME ...\n");
110  free(evp);
111  return NULL;
112  }
113 
114  if ((ioctl(evp->fd, EVIOCGBIT(0, sizeof(evp->evbit)), evp->evbit) < 0) ||
115  (ioctl(evp->fd, EVIOCGBIT(EV_KEY, sizeof(evp->keybit)), evp->keybit) < 0) ||
116  (ioctl(evp->fd, EVIOCGBIT(EV_ABS, sizeof(evp->absbit)), evp->absbit) < 0) ||
117  (ioctl(evp->fd, EVIOCGBIT(EV_REL, sizeof(evp->relbit)), evp->relbit) < 0)) {
118  printf("Error) ioctl() calls ...\n");
119  free(evp);
120  return NULL;
121  }
122 
123  /*
124  * classify device as joystick, spaceball, or something else
125  * see if it has buttons and absolute x/y position at a minimum
126  */
127  if (EVIO_TESTBIT(EV_KEY, evp->evbit) && EVIO_TESTBIT(EV_ABS, evp->evbit) &&
128  EVIO_TESTBIT(ABS_X, evp->absbit) && EVIO_TESTBIT(ABS_Y, evp->absbit) &&
129  EVIO_TESTBIT(ABS_RX, evp->absbit) && EVIO_TESTBIT(ABS_RY, evp->absbit)) {
131  }
132 
133  if (!evp->devjoystick &&
134  EVIO_TESTBIT(EV_KEY, evp->evbit) && EVIO_TESTBIT(EV_ABS, evp->evbit) &&
135  EVIO_TESTBIT(ABS_X, evp->absbit) && EVIO_TESTBIT(ABS_Y, evp->absbit) &&
136  EVIO_TESTBIT(ABS_Z, evp->absbit) && EVIO_TESTBIT(ABS_RZ, evp->absbit)) {
138  }
139 
140  if (!evp->devjoystick &&
141  EVIO_TESTBIT(EV_KEY, evp->evbit) && EVIO_TESTBIT(EV_ABS, evp->evbit) &&
142  EVIO_TESTBIT(ABS_X, evp->absbit) && EVIO_TESTBIT(ABS_Y, evp->absbit)) {
144  }
145 
146  /* see if it has buttons and relative x/y/z rx/ry/rz at a minimum */
147  if (!evp->devjoystick &&
148  EVIO_TESTBIT(EV_KEY, evp->evbit) &&
149  EVIO_TESTBIT(EV_REL, evp->evbit) &&
150  EVIO_TESTBIT(REL_X, evp->relbit) &&
151  EVIO_TESTBIT(REL_Y, evp->relbit) &&
152  EVIO_TESTBIT(REL_Z, evp->relbit) &&
153  EVIO_TESTBIT(REL_RX, evp->relbit) &&
154  EVIO_TESTBIT(REL_RY, evp->relbit) &&
155  EVIO_TESTBIT(REL_RZ, evp->relbit)) {
157  }
158 
159  /* query device ID info */
160  if (ioctl(evp->fd, EVIOCGID, &evp->devid) < 0) {
161  printf("Error) EVIOCGID ...\n");
162  free(evp);
163  return NULL;
164  }
165 
166  fcntl(evp->fd, F_SETFL, O_NONBLOCK); /* set device to non-blocking I/O */
167 
168  return evp;
169 }
170 
171 
173  evio *evp = (evio *) v;
174  close(evp->fd);
175  free(evp);
176 
177  return 0;
178 }
179 
180 
182  evio *evp = (evio *) v;
183 
184  /* see if it has buttons and absolute x/y position at a minimum */
185  if (evp->devjoystick)
186  return 1;
187 
188  return 0;
189 }
190 
191 
193  evio *evp = (evio *) v;
194 
195  /* see if it has buttons and relative x/y/z rx/ry/rz at a minimum */
196  if (evp->devspaceball)
197  return 1;
198 
199  return 0;
200 }
201 
202 
204  evio *evp = (evio *) v;
205 
206  if (evp->devjoystick || evp->devspaceball)
207  return 1;
208 
209  return 0;
210 }
211 
212 
214  evio *evp = (evio *) v;
215  int bcnt=0;
216  int rc=0;
217 
218  do {
219  bcnt = read(evp->fd, &evp->inpev, sizeof(evp->inpev));
220  } while (bcnt == -1 && errno == EINTR);
221 
222  if (bcnt > 0) {
223  switch (evp->inpev.type) {
224  case EV_SYN:
225  printf("EV_SYN: '%s' %ld:%ld s \n",
226  (evp->inpev.code == SYN_REPORT) ? "SYN_REPORT" : "Other",
227  evp->inpev.time.tv_sec, evp->inpev.time.tv_usec);
228  rc=1;
229  break;
230 
231  case EV_KEY:
232  printf("EV_KEY[0x%04x]: %d \n",
233  evp->inpev.code, evp->inpev.value);
234  rc=1;
235  break;
236 
237  case EV_ABS:
238  printf("EV_ABS[%d]: %d \n",
239  evp->inpev.code - ABS_X, evp->inpev.value);
240  rc=1;
241  break;
242 
243  case EV_REL:
244  printf("EV_REL[%d]: %d \n",
245  evp->inpev.code - REL_X, evp->inpev.value);
246  rc=1;
247  break;
248 
249  case EV_MSC:
250  printf("EV_MSC[%d] \n", evp->inpev.code);
251  rc=1;
252  break;
253 
254  default:
255  printf("Unknown event type: 0x%x \n",
256  evp->inpev.code - REL_X);
257  rc=1;
258  break;
259 
260  }
261  } else {
262  /* handle unexpected device disconnects and similar */
263  if (errno != EAGAIN) {
264  printf("Error reading events from input device\n");
265  return -1;
266  }
267  }
268 
269  return rc;
270 }
271 
272 
273 #if 0
274 int evio_print_absinfo(void) {
275  printf("REL_X Values = { %d, %d, %d, %d, %d }\n",
276  absinfo.value, absinfo.minimum, absinfo.maximum,
277  absinfo.fuzz, absinfo.flat);
278 }
279 #endif
280 
281 
282 float evio_absinfo2float(struct input_absinfo *absinfo) {
283  int val = absinfo->value - absinfo->minimum;
284  int range = absinfo->maximum - absinfo->minimum;
285  return 2.0f * ((float) val / (float) range) - 1.0f;
286 }
287 
288 
289 int evio_get_button_status(evio_handle v, int evbtn, int btnflag) {
290  evio *evp = (evio *) v;
291  int btmp=0;
292 
293  if (EVIO_TESTBIT(evbtn, evp->keystate))
294  btmp |= btnflag;
295 
296  return btmp;
297 }
298 
299 
300 int evio_get_joystick_status(evio_handle v, float *abs_x1, float *abs_y1,
301  float *abs_x2, float *abs_y2, int *buttons) {
302  struct input_absinfo absinfo;
303  int xax2, yax2;
304  evio *evp = (evio *) v;
305  int rc=0;
306 
307  memset(&absinfo, 0, sizeof(absinfo));
308 
309  *abs_x1 = 0;
310  *abs_y1 = 0;
311  *abs_x2 = 0;
312  *abs_y2 = 0;
313  *buttons = 0;
314 
315  if (ioctl(evp->fd, EVIOCGABS(ABS_X), &absinfo) < 0) {
316  return 0;
317  } else {
318  rc |= 1;
319  *abs_x1 = evio_absinfo2float(&absinfo);
320  }
321  if (ioctl(evp->fd, EVIOCGABS(ABS_Y), &absinfo) < 0) {
322  return 0;
323  } else {
324  rc |= 1;
325  *abs_y1 = evio_absinfo2float(&absinfo);
326  }
327 
328  switch (evp->devjoystick) {
330  xax2 = ABS_RX;
331  yax2 = ABS_RY;
332  break;
333 
335  xax2 = ABS_Z;
336  yax2 = ABS_RZ;
337  break;
338 
339  default:
341  xax2 = 0;
342  yax2 = 0;
343  break;
344  }
345 
346  if (xax2 && yax2) {
347  if (ioctl(evp->fd, EVIOCGABS(xax2), &absinfo) < 0) {
348  return 0;
349  } else {
350  rc |= 1;
351  *abs_x2 = evio_absinfo2float(&absinfo);
352  }
353  if (ioctl(evp->fd, EVIOCGABS(yax2), &absinfo) < 0) {
354  return 0;
355  } else {
356  rc |= 1;
357  *abs_y2 = evio_absinfo2float(&absinfo);
358  }
359  }
360 
361 
362  if (ioctl(evp->fd, EVIOCGKEY(sizeof(evp->keystate)), evp->keystate) >= 0) {
363 #if 1
364  int btmp=0;
365  btmp |= evio_get_button_status(v, BTN_BACK, EVENTIO_BACK);
366  btmp |= evio_get_button_status(v, BTN_TASK, EVENTIO_TASK);
367  btmp |= evio_get_button_status(v, BTN_START, EVENTIO_START);
368 
369  btmp |= evio_get_button_status(v, BTN_A, EVENTIO_GAMEPAD_A);
370  btmp |= evio_get_button_status(v, BTN_B, EVENTIO_GAMEPAD_B);
371  btmp |= evio_get_button_status(v, BTN_X, EVENTIO_GAMEPAD_X);
372  btmp |= evio_get_button_status(v, BTN_Y, EVENTIO_GAMEPAD_Y);
373 
374  btmp |= evio_get_button_status(v, BTN_TL, EVENTIO_TL);
375  btmp |= evio_get_button_status(v, BTN_TR, EVENTIO_TR);
376  btmp |= evio_get_button_status(v, BTN_THUMBL, EVENTIO_THUMBL);
377  btmp |= evio_get_button_status(v, BTN_THUMBR, EVENTIO_THUMBR);
378 #else
379  int i, btmp=0;
380  for (i=0; i<31; i++) {
381  if (EVIO_TESTBIT(BTN_GAMEPAD+i, evp->keybit))
382  btmp |= (1 << i);
383  }
384 #endif
385 
386  *buttons = btmp;
387  }
388 
389  return rc;
390 }
391 
392 
394  int *rel_x,
395  int *rel_y,
396  int *rel_z,
397  int *rel_rx,
398  int *rel_ry,
399  int *rel_rz,
400  int *buttons) {
401  struct input_absinfo absinfo;
402  evio *evp = (evio *) v;
403  int rc=0;
404 
405  *rel_x = 0;
406  *rel_y = 0;
407  *rel_z = 0;
408  *rel_rx = 0;
409  *rel_ry = 0;
410  *rel_rz = 0;
411  *buttons = 0;
412 
413  memset(&absinfo, 0, sizeof(absinfo));
414 
415  if (ioctl(evp->fd, EVIOCGABS(REL_X), &absinfo) < 0) {
416  return 0;
417  } else {
418  rc |= 1;
419  *rel_x = absinfo.value;
420  }
421  if (ioctl(evp->fd, EVIOCGABS(REL_Y), &absinfo) < 0) {
422  return 0;
423  } else {
424  rc |= 1;
425  *rel_y = absinfo.value;
426  }
427  if (ioctl(evp->fd, EVIOCGABS(REL_Z), &absinfo) < 0) {
428  return 0;
429  } else {
430  rc |= 1;
431  *rel_z = absinfo.value;
432  }
433 
434  if (ioctl(evp->fd, EVIOCGABS(REL_RX), &absinfo) < 0) {
435  return 0;
436  } else {
437  rc |= 1;
438  *rel_rx = absinfo.value;
439  }
440  if (ioctl(evp->fd, EVIOCGABS(REL_RY), &absinfo) < 0) {
441  return 0;
442  } else {
443  rc |= 1;
444  *rel_ry = absinfo.value;
445  }
446  if (ioctl(evp->fd, EVIOCGABS(REL_RZ), &absinfo) < 0) {
447  return 0;
448  } else {
449  rc |= 1;
450  *rel_rz = absinfo.value;
451  }
452 
453 
454  if (ioctl(evp->fd, EVIOCGBIT(EV_KEY, sizeof(evp->keybit)), evp->keybit) >= 0) {
455  int i, btmp=0;
456  for (i=0; i<31; i++) {
457  if (EVIO_TESTBIT(BTN_MISC+i, evp->keybit))
458  btmp |= (1 << i);
459  }
460  *buttons = btmp;
461  }
462 
463  return rc;
464 }
465 
466 
468  evio *evp = (evio *) v;
469  const char *busstr;
470 
471  if (!evio_dev_recognized(v)) {
472  printf("Unrecognized device type\n");
473  return EVENTIO_ERROR;
474  }
475 
476  if (evp->devid.bustype == BUS_USB) {
477  busstr = "USB";
478  } else if (evp->devid.bustype == BUS_BLUETOOTH) {
479  busstr = "Bluetooth";
480  } else if (evp->devid.bustype == BUS_PCI) {
481  busstr = "PCI";
482  } else {
483  busstr = "Other";
484  }
485 
486  if (evp->devjoystick) {
487  printf("Joystick at '%s':\n", evp->devpath);
488  } else if (evp->devspaceball) {
489  printf("Spaceball at '%s':\n", evp->devpath);
490  }
491 
492  printf(" '%s'\n", evp->devname);
493  printf(" bus: %s ", busstr);
494  printf(" vendor: 0x%x", evp->devid.vendor);
495  printf(" product: 0x%x \n", evp->devid.product);
496 
497  return EVENTIO_SUCCESS;
498 }
499 
500 
501 
502 #if defined(TEST_MAIN)
503 
504 int dev_valid(const char *devpath) {
505  evio * evp = (evio *) evio_open(devpath);
506  if (!evp)
507  return EVENTIO_ERROR;
508 
509  if (evio_dev_recognized(evp)) {
510  evio_print_devinfo(evp);
511  } else {
512  printf("Unrecognized device type: '%s' (%s)\n", evp->devpath, evp->devname);
513  }
514 
515  evio_close(evp);
516  return EVENTIO_SUCCESS;
517 }
518 
519 
520 int dev_test(const char *devpath) {
521  evio * evp = (evio *) evio_open(devpath);
522  if (!evp)
523  return EVENTIO_ERROR;
524 
525  if (!evio_dev_recognized(evp)) {
526  printf("Unrecognized device type: '%s' (%s)\n", evp->devpath, evp->devname);
527  evio_close(evp);
528  return EVENTIO_ERROR;
529  }
530 
531  printf("Running loop test on device '%s'...\n", devpath);
532 
533 #if 1
534  if (evio_dev_joystick(evp)) {
535  while (1) {
536  float ax1, ay1, ax2, ay2;
537  int buttons;
538  if (evio_get_joystick_status(evp, &ax1, &ay1, &ax2, &ay2, &buttons)) {
539  printf("Joystick: %5.2f %5.2f %5.2f %5.2f 0x%08x \r",
540  ax1, ay1, ax2, ay2, buttons);
541  }
542  if (buttons)
543  break;
544  }
545  }
546 #endif
547 
548 #if 0
549  if (evio_dev_spaceball(evp)) {
550  while (1) {
551  int tx, ty, tz, rx, ry, rz, buttons;
552  if (evio_get_spaceball_status(evp, &tx, &ty, &tz,
553  &rx, &ry, &rz, &buttons)) {
554  printf("Spaceball: %6d %6d %6d %6d %6d %6d 0x%08x \r",
555  tx, ty, tz, rx, ry, rz, buttons);
556 
557  if (buttons)
558  break;
559  }
560  }
561  }
562 #endif
563 
564 
565 #if 1
566  if (!evio_dev_joystick(evp) && !evio_dev_spaceball(evp)) {
567  while (1) {
568  int ev=0, hadev=0;
569  do {
570  ev=evio_read_events(evp);
571  hadev |= (ev > 0);
572  } while (ev);
573  if (hadev)
574  printf("End of event report\n");
575  }
576  }
577 #endif
578 
579  evio_close(evp);
580  return EVENTIO_SUCCESS;
581 }
582 
583 
584 int main(int argc, char **argv) {
585  int rc, i;
586 
587  if (argc < 2) {
588  for (i=0; i<40; i++) {
589  char devpath[2048];
590  sprintf(devpath, "/dev/input/event%d", i);
591  if (dev_valid(devpath) == EVENTIO_SUCCESS)
592  dev_test(devpath);
593  }
594  } else {
595  for (i=1; i<argc; i++) {
596  char *devpath=argv[i];
597  if (dev_valid(devpath) == EVENTIO_SUCCESS)
598  dev_test(devpath);
599  }
600  }
601 
602  return 0;
603 }
604 
605 #endif
606 
607 
608 #ifdef __cplusplus
609 }
610 #endif
611 
612 
char devname[2048]
Definition: eventio.c:83
int evio_get_button_status(evio_handle v, int evbtn, int btnflag)
Definition: eventio.c:289
#define EVENTIO_TL
Definition: eventio.h:38
#define REL_RY
Definition: eventio.c:65
#define EVENTIO_GAMEPAD_X
Definition: eventio.h:35
struct input_event inpev
Definition: eventio.c:90
int evio_read_events(evio_handle v)
Definition: eventio.c:213
#define EVIO_TESTBIT(bnr, array)
Definition: eventio.c:77
int devjoystick
Definition: eventio.c:91
unsigned long absbit[EVIO_BITSTOLONGS(ABS_MAX)]
Definition: eventio.c:88
#define EVENTIO_START
Definition: eventio.h:25
#define EVENTIO_THUMBR
Definition: eventio.h:41
#define EVENTIO_THUMBL
Definition: eventio.h:40
unsigned long keybit[EVIO_BITSTOLONGS(KEY_MAX)]
Definition: eventio.c:86
#define EVIO_BITSTOLONGS(bnr)
Definition: eventio.c:74
#define EVENTIO_GAMEPAD_B
Definition: eventio.h:34
int main(int argc, char **argv)
Definition: animskull.c:40
#define EVENTIO_GAMEPAD_A
Definition: eventio.h:33
int fd
Definition: eventio.c:81
float evio_absinfo2float(struct input_absinfo *absinfo)
Definition: eventio.c:282
#define REL_RZ
Definition: eventio.c:68
int evio_dev_joystick(evio_handle v)
Definition: eventio.c:181
int evio_get_joystick_status(evio_handle v, float *abs_x1, float *abs_y1, float *abs_x2, float *abs_y2, int *buttons)
Definition: eventio.c:300
evio_handle evio_open(const char *devpath)
Definition: eventio.c:96
int devspaceball
Definition: eventio.c:92
int evio_dev_spaceball(evio_handle v)
Definition: eventio.c:192
unsigned long relbit[EVIO_BITSTOLONGS(REL_MAX)]
Definition: eventio.c:89
#define REL_RX
Definition: eventio.c:62
#define EVENTIO_JOYSTICK_LOGIF310
Definition: eventio.h:44
struct input_id devid
Definition: eventio.c:84
int evio_close(evio_handle v)
Definition: eventio.c:172
#define EVENTIO_TR
Definition: eventio.h:39
#define EVENTIO_JOYSTICK_STD
Definition: eventio.h:43
unsigned long keystate[EVIO_BITSTOLONGS(KEY_MAX)]
Definition: eventio.c:87
#define EVENTIO_SPACEBALL_STD
Definition: eventio.h:47
int evio_print_devinfo(evio_handle v)
Definition: eventio.c:467
#define EVENTIO_SUCCESS
Definition: eventio.h:20
#define EVENTIO_JOYSTICK_NYKO
Definition: eventio.h:45
#define EVENTIO_TASK
Definition: eventio.h:24
#define EVENTIO_BACK
Definition: eventio.h:23
char devpath[2048]
Definition: eventio.c:82
Definition: eventio.c:80
unsigned long evbit[EVIO_BITSTOLONGS(EV_MAX)]
Definition: eventio.c:85
#define EVENTIO_ERROR
Definition: eventio.h:21
#define EVENTIO_GAMEPAD_Y
Definition: eventio.h:36
int evio_dev_recognized(evio_handle v)
Definition: eventio.c:203
int evio_get_spaceball_status(evio_handle v, int *rel_x, int *rel_y, int *rel_z, int *rel_rx, int *rel_ry, int *rel_rz, int *buttons)
Definition: eventio.c:393
void * evio_handle
Definition: eventio.h:49