|
/*
* Support for Linux evdevs...the /dev/input/event* devices.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#include "manymouse.h"
#ifdef __linux__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h> /* evdev interface... */
#define test_bit(array, bit) (array[bit/8] & (1<<(bit%8)))
/* linux allows 32 evdev nodes currently. */
#define MAX_MICE 32
typedef struct
{
int fd;
int min_x;
int min_y;
int max_x;
int max_y;
char name[64];
} MouseStruct;
static MouseStruct mice[MAX_MICE];
static unsigned int available_mice = 0;
static int poll_mouse(MouseStruct *mouse, ManyMouseEvent *outevent)
{
int unhandled = 1;
while (unhandled) /* read until failure or valid event. */
{
struct input_event event;
int br = read(mouse->fd, &event, sizeof (event));
if (br == -1)
{
if (errno == EAGAIN)
return(0); /* just no new data at the moment. */
/* mouse was unplugged? */
close(mouse->fd); /* stop reading from this mouse. */
mouse->fd = -1;
outevent->type = MANYMOUSE_EVENT_DISCONNECT;
return(1);
} /* if */
if (br != sizeof (event))
return(0); /* oh well. */
unhandled = 0; /* will reset if necessary. */
outevent->value = event.value;
if (event.type == EV_REL)
{
outevent->type = MANYMOUSE_EVENT_RELMOTION;
if ((event.code == REL_X) || (event.code == REL_DIAL))
outevent->item = 0;
else if (event.code == REL_Y)
outevent->item = 1;
else if (event.code == REL_WHEEL)
{
outevent->type = MANYMOUSE_EVENT_SCROLL;
outevent->item = 0;
} /* else if */
else if (event.code == REL_HWHEEL)
{
outevent->type = MANYMOUSE_EVENT_SCROLL;
outevent->item = 1;
} /* else if */
else
{
unhandled = 1;
} /* else */
} /* if */
else if (event.type == EV_ABS)
{
outevent->type = MANYMOUSE_EVENT_ABSMOTION;
if (event.code == ABS_X)
{
outevent->item = 0;
outevent->minval = mouse->min_x;
outevent->maxval = mouse->max_x;
} /* if */
else if (event.code == ABS_Y)
{
outevent->item = 1;
outevent->minval = mouse->min_y;
outevent->maxval = mouse->max_y;
} /* if */
else
{
unhandled = 1;
} /* else */
} /* else if */
else if (event.type == EV_KEY)
{
outevent->type = MANYMOUSE_EVENT_BUTTON;
if ((event.code >= BTN_LEFT) && (event.code <= BTN_BACK))
outevent->item = event.code - BTN_MOUSE;
/* just in case some device uses this block of events instead... */
else if ((event.code >= BTN_MISC) && (event.code <= BTN_LEFT))
outevent->item = (event.code - BTN_MISC);
else if (event.code == BTN_TOUCH) /* tablet... */
outevent->item = 0;
else if (event.code == BTN_STYLUS) /* tablet... */
outevent->item = 1;
else if (event.code == BTN_STYLUS2) /* tablet... */
outevent->item = 2;
else
{
/*printf("unhandled mouse button: 0x%X\n", event.code);*/
unhandled = 1;
} /* else */
} /* else if */
else
{
unhandled = 1;
} /* else */
} /* while */
return(1); /* got a valid event */
} /* poll_mouse */
static int init_mouse(const char *fname, int fd)
{
MouseStruct *mouse = &mice[available_mice];
int has_absolutes = 0;
int is_mouse = 0;
unsigned char relcaps[(REL_MAX / 8) + 1];
unsigned char abscaps[(ABS_MAX / 8) + 1];
unsigned char keycaps[(KEY_MAX / 8) + 1];
memset(relcaps, '\0', sizeof (relcaps));
memset(abscaps, '\0', sizeof (abscaps));
memset(keycaps, '\0', sizeof (keycaps));
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof (keycaps)), keycaps) == -1)
return 0; /* gotta have some buttons! :) */
if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof (relcaps)), relcaps) != -1)
{
if ( (test_bit(relcaps, REL_X)) && (test_bit(relcaps, REL_Y)) )
{
if (test_bit(keycaps, BTN_MOUSE))
is_mouse = 1;
} /* if */
#if ALLOW_DIALS_TO_BE_MICE
if (test_bit(relcaps, REL_DIAL))
is_mouse = 1; // griffin powermate?
#endif
} /* if */
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof (abscaps)), abscaps) != -1)
{
if ( (test_bit(abscaps, ABS_X)) && (test_bit(abscaps, ABS_Y)) )
{
/* might be a touchpad... */
if (test_bit(keycaps, BTN_TOUCH))
{
is_mouse = 1; /* touchpad, touchscreen, or tablet. */
has_absolutes = 1;
} /* if */
} /* if */
} /* if */
if (!is_mouse)
return 0;
mouse->min_x = mouse->min_y = mouse->max_x = mouse->max_y = 0;
if (has_absolutes)
{
struct input_absinfo absinfo;
if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) == -1)
return 0;
mouse->min_x = absinfo.minimum;
mouse->max_x = absinfo.maximum;
if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) == -1)
return 0;
mouse->min_y = absinfo.minimum;
mouse->max_y = absinfo.maximum;
} /* if */
if (ioctl(fd, EVIOCGNAME(sizeof (mouse->name)), mouse->name) == -1)
snprintf(mouse->name, sizeof (mouse->name), "Unknown device");
mouse->fd = fd;
return 1; /* we're golden. */
} /* init_mouse */
/* Return a file descriptor if this is really a mouse, -1 otherwise. */
static int open_if_mouse(const char *fname)
{
struct stat statbuf;
int fd;
int devmajor, devminor;
if (stat(fname, &statbuf) == -1)
return 0;
if (S_ISCHR(statbuf.st_mode) == 0)
return 0; /* not a character device... */
/* evdev node ids are major 13, minor 64-96. Is this safe to check? */
devmajor = (statbuf.st_rdev & 0xFF00) >> 8;
devminor = (statbuf.st_rdev & 0x00FF);
if ( (devmajor != 13) || (devminor < 64) || (devminor > 96) )
return 0; /* not an evdev. */
if ((fd = open(fname, O_RDONLY | O_NONBLOCK)) == -1)
return 0;
if (init_mouse(fname, fd))
return 1;
close(fd);
return 0;
} /* open_if_mouse */
static int linux_evdev_init(void)
{
DIR *dirp;
struct dirent *dent;
int i;
for (i = 0; i < MAX_MICE; i++)
mice[i].fd = -1;
dirp = opendir("/dev/input");
if (!dirp)
return -1;
while ((dent = readdir(dirp)) != NULL)
{
char fname[128];
snprintf(fname, sizeof (fname), "/dev/input/%s", dent->d_name);
if (open_if_mouse(fname))
available_mice++;
} /* while */
closedir(dirp);
return available_mice;
} /* linux_evdev_init */
static void linux_evdev_quit(void)
{
while (available_mice)
{
int fd = mice[available_mice--].fd;
if (fd != -1)
close(fd);
} /* while */
} /* linux_evdev_quit */
static const char *linux_evdev_name(unsigned int index)
{
if (index < available_mice)
return(mice[index].name);
return(NULL);
} /* linux_evdev_name */
static int linux_evdev_poll(ManyMouseEvent *event)
{
/*
* (i) is static so we iterate through all mice round-robin. This
* prevents a chatty mouse from dominating the queue.
*/
static unsigned int i = 0;
if (i >= available_mice)
i = 0; /* handle reset condition. */
if (event != NULL)
{
while (i < available_mice)
{
MouseStruct *mouse = &mice[i];
if (mouse->fd != -1)
{
if (poll_mouse(mouse, event))
{
event->device = i;
return(1);
} /* if */
} /* if */
i++;
} /* while */
} /* if */
return(0); /* no new events */
} /* linux_evdev_poll */
static const ManyMouseDriver ManyMouseDriver_interface =
{
linux_evdev_init,
linux_evdev_quit,
linux_evdev_name,
linux_evdev_poll
};
const ManyMouseDriver *ManyMouseDriver_evdev = &ManyMouseDriver_interface;
#else
const ManyMouseDriver *ManyMouseDriver_evdev = 0;
#endif /* ifdef Linux blocker */
/* end of linux_evdev.c ... */
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Always trying something new. blog tries to keep up (nwpodcast.blogspot.com)