PageRenderTime 65ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/interfaces/ManyMouse/linux_evdev.c

http://b207.googlecode.com/
C | 343 lines | 260 code | 64 blank | 19 comment | 95 complexity | cb1b45f98bffc94e16cb174fb1acc5a1 MD5 | raw file
  1. /*
  2. * Support for Linux evdevs...the /dev/input/event* devices.
  3. *
  4. * Please see the file LICENSE in the source's root directory.
  5. *
  6. * This file written by Ryan C. Gordon.
  7. */
  8. #include "manymouse.h"
  9. #ifdef __linux__
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. #include <dirent.h>
  15. #include <errno.h>
  16. #include <sys/types.h>
  17. #include <unistd.h>
  18. #include <sys/stat.h>
  19. #include <fcntl.h>
  20. #include <linux/input.h> /* evdev interface... */
  21. #define test_bit(array, bit) (array[bit/8] & (1<<(bit%8)))
  22. /* linux allows 32 evdev nodes currently. */
  23. #define MAX_MICE 32
  24. typedef struct
  25. {
  26. int fd;
  27. int min_x;
  28. int min_y;
  29. int max_x;
  30. int max_y;
  31. char name[64];
  32. } MouseStruct;
  33. static MouseStruct mice[MAX_MICE];
  34. static unsigned int available_mice = 0;
  35. static int poll_mouse(MouseStruct *mouse, ManyMouseEvent *outevent)
  36. {
  37. int unhandled = 1;
  38. while (unhandled) /* read until failure or valid event. */
  39. {
  40. struct input_event event;
  41. int br = read(mouse->fd, &event, sizeof (event));
  42. if (br == -1)
  43. {
  44. if (errno == EAGAIN)
  45. return(0); /* just no new data at the moment. */
  46. /* mouse was unplugged? */
  47. close(mouse->fd); /* stop reading from this mouse. */
  48. mouse->fd = -1;
  49. outevent->type = MANYMOUSE_EVENT_DISCONNECT;
  50. return(1);
  51. } /* if */
  52. if (br != sizeof (event))
  53. return(0); /* oh well. */
  54. unhandled = 0; /* will reset if necessary. */
  55. outevent->value = event.value;
  56. if (event.type == EV_REL)
  57. {
  58. outevent->type = MANYMOUSE_EVENT_RELMOTION;
  59. if ((event.code == REL_X) || (event.code == REL_DIAL))
  60. outevent->item = 0;
  61. else if (event.code == REL_Y)
  62. outevent->item = 1;
  63. else if (event.code == REL_WHEEL)
  64. {
  65. outevent->type = MANYMOUSE_EVENT_SCROLL;
  66. outevent->item = 0;
  67. } /* else if */
  68. else if (event.code == REL_HWHEEL)
  69. {
  70. outevent->type = MANYMOUSE_EVENT_SCROLL;
  71. outevent->item = 1;
  72. } /* else if */
  73. else
  74. {
  75. unhandled = 1;
  76. } /* else */
  77. } /* if */
  78. else if (event.type == EV_ABS)
  79. {
  80. outevent->type = MANYMOUSE_EVENT_ABSMOTION;
  81. if (event.code == ABS_X)
  82. {
  83. outevent->item = 0;
  84. outevent->minval = mouse->min_x;
  85. outevent->maxval = mouse->max_x;
  86. } /* if */
  87. else if (event.code == ABS_Y)
  88. {
  89. outevent->item = 1;
  90. outevent->minval = mouse->min_y;
  91. outevent->maxval = mouse->max_y;
  92. } /* if */
  93. else
  94. {
  95. unhandled = 1;
  96. } /* else */
  97. } /* else if */
  98. else if (event.type == EV_KEY)
  99. {
  100. outevent->type = MANYMOUSE_EVENT_BUTTON;
  101. if ((event.code >= BTN_LEFT) && (event.code <= BTN_BACK))
  102. outevent->item = event.code - BTN_MOUSE;
  103. /* just in case some device uses this block of events instead... */
  104. else if ((event.code >= BTN_MISC) && (event.code <= BTN_LEFT))
  105. outevent->item = (event.code - BTN_MISC);
  106. else if (event.code == BTN_TOUCH) /* tablet... */
  107. outevent->item = 0;
  108. else if (event.code == BTN_STYLUS) /* tablet... */
  109. outevent->item = 1;
  110. else if (event.code == BTN_STYLUS2) /* tablet... */
  111. outevent->item = 2;
  112. else
  113. {
  114. /*printf("unhandled mouse button: 0x%X\n", event.code);*/
  115. unhandled = 1;
  116. } /* else */
  117. } /* else if */
  118. else
  119. {
  120. unhandled = 1;
  121. } /* else */
  122. } /* while */
  123. return(1); /* got a valid event */
  124. } /* poll_mouse */
  125. static int init_mouse(const char *fname, int fd)
  126. {
  127. MouseStruct *mouse = &mice[available_mice];
  128. int has_absolutes = 0;
  129. int is_mouse = 0;
  130. unsigned char relcaps[(REL_MAX / 8) + 1];
  131. unsigned char abscaps[(ABS_MAX / 8) + 1];
  132. unsigned char keycaps[(KEY_MAX / 8) + 1];
  133. memset(relcaps, '\0', sizeof (relcaps));
  134. memset(abscaps, '\0', sizeof (abscaps));
  135. memset(keycaps, '\0', sizeof (keycaps));
  136. if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof (keycaps)), keycaps) == -1)
  137. return 0; /* gotta have some buttons! :) */
  138. if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof (relcaps)), relcaps) != -1)
  139. {
  140. if ( (test_bit(relcaps, REL_X)) && (test_bit(relcaps, REL_Y)) )
  141. {
  142. if (test_bit(keycaps, BTN_MOUSE))
  143. is_mouse = 1;
  144. } /* if */
  145. #if ALLOW_DIALS_TO_BE_MICE
  146. if (test_bit(relcaps, REL_DIAL))
  147. is_mouse = 1; // griffin powermate?
  148. #endif
  149. } /* if */
  150. if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof (abscaps)), abscaps) != -1)
  151. {
  152. if ( (test_bit(abscaps, ABS_X)) && (test_bit(abscaps, ABS_Y)) )
  153. {
  154. /* might be a touchpad... */
  155. if (test_bit(keycaps, BTN_TOUCH))
  156. {
  157. is_mouse = 1; /* touchpad, touchscreen, or tablet. */
  158. has_absolutes = 1;
  159. } /* if */
  160. } /* if */
  161. } /* if */
  162. if (!is_mouse)
  163. return 0;
  164. mouse->min_x = mouse->min_y = mouse->max_x = mouse->max_y = 0;
  165. if (has_absolutes)
  166. {
  167. struct input_absinfo absinfo;
  168. if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) == -1)
  169. return 0;
  170. mouse->min_x = absinfo.minimum;
  171. mouse->max_x = absinfo.maximum;
  172. if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) == -1)
  173. return 0;
  174. mouse->min_y = absinfo.minimum;
  175. mouse->max_y = absinfo.maximum;
  176. } /* if */
  177. if (ioctl(fd, EVIOCGNAME(sizeof (mouse->name)), mouse->name) == -1)
  178. snprintf(mouse->name, sizeof (mouse->name), "Unknown device");
  179. mouse->fd = fd;
  180. return 1; /* we're golden. */
  181. } /* init_mouse */
  182. /* Return a file descriptor if this is really a mouse, -1 otherwise. */
  183. static int open_if_mouse(const char *fname)
  184. {
  185. struct stat statbuf;
  186. int fd;
  187. int devmajor, devminor;
  188. if (stat(fname, &statbuf) == -1)
  189. return 0;
  190. if (S_ISCHR(statbuf.st_mode) == 0)
  191. return 0; /* not a character device... */
  192. /* evdev node ids are major 13, minor 64-96. Is this safe to check? */
  193. devmajor = (statbuf.st_rdev & 0xFF00) >> 8;
  194. devminor = (statbuf.st_rdev & 0x00FF);
  195. if ( (devmajor != 13) || (devminor < 64) || (devminor > 96) )
  196. return 0; /* not an evdev. */
  197. if ((fd = open(fname, O_RDONLY | O_NONBLOCK)) == -1)
  198. return 0;
  199. if (init_mouse(fname, fd))
  200. return 1;
  201. close(fd);
  202. return 0;
  203. } /* open_if_mouse */
  204. static int linux_evdev_init(void)
  205. {
  206. DIR *dirp;
  207. struct dirent *dent;
  208. int i;
  209. for (i = 0; i < MAX_MICE; i++)
  210. mice[i].fd = -1;
  211. dirp = opendir("/dev/input");
  212. if (!dirp)
  213. return -1;
  214. while ((dent = readdir(dirp)) != NULL)
  215. {
  216. char fname[128];
  217. snprintf(fname, sizeof (fname), "/dev/input/%s", dent->d_name);
  218. if (open_if_mouse(fname))
  219. available_mice++;
  220. } /* while */
  221. closedir(dirp);
  222. return available_mice;
  223. } /* linux_evdev_init */
  224. static void linux_evdev_quit(void)
  225. {
  226. while (available_mice)
  227. {
  228. int fd = mice[available_mice--].fd;
  229. if (fd != -1)
  230. close(fd);
  231. } /* while */
  232. } /* linux_evdev_quit */
  233. static const char *linux_evdev_name(unsigned int index)
  234. {
  235. if (index < available_mice)
  236. return(mice[index].name);
  237. return(NULL);
  238. } /* linux_evdev_name */
  239. static int linux_evdev_poll(ManyMouseEvent *event)
  240. {
  241. /*
  242. * (i) is static so we iterate through all mice round-robin. This
  243. * prevents a chatty mouse from dominating the queue.
  244. */
  245. static unsigned int i = 0;
  246. if (i >= available_mice)
  247. i = 0; /* handle reset condition. */
  248. if (event != NULL)
  249. {
  250. while (i < available_mice)
  251. {
  252. MouseStruct *mouse = &mice[i];
  253. if (mouse->fd != -1)
  254. {
  255. if (poll_mouse(mouse, event))
  256. {
  257. event->device = i;
  258. return(1);
  259. } /* if */
  260. } /* if */
  261. i++;
  262. } /* while */
  263. } /* if */
  264. return(0); /* no new events */
  265. } /* linux_evdev_poll */
  266. #else
  267. static int linux_evdev_init(void) { return(-1); }
  268. static void linux_evdev_quit(void) {}
  269. static const char *linux_evdev_name(unsigned int index) { return(0); }
  270. static int linux_evdev_poll(ManyMouseEvent *event) { return(0); }
  271. #endif /* defined __linux__ */
  272. ManyMouseDriver ManyMouseDriver_evdev =
  273. {
  274. linux_evdev_init,
  275. linux_evdev_quit,
  276. linux_evdev_name,
  277. linux_evdev_poll
  278. };
  279. /* end of linux_evdev.c ... */