
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <asm/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <linux/input.h>

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

/* this macro is used to tell if "bit" is set in "array"
 * it selects a byte from the array, and does a boolean AND 
 * operation with a byte that only has the relevant bit set. 
 * eg. to check for the 12th bit, we do (array[1] & 1<<4)
 */
#define test_bit(array, bit)    (array[bit/8] & (1<<(bit%8)))
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)

int roll_event(int * current){
	if(*current == 1){
		*current = 0;
		printf("ButtonRelease\n");
      		return ButtonRelease;
	} else {
		*current = 1;
		printf("ButtonPress\n");
		return ButtonPress;
	}
}

int main (int argc, char **argv) {

	int fd = -1;
	uint8_t abs_bitmask[ABS_MAX/8 + 1];
	int yalv;

	/* ioctl() requires a file descriptor, so we check we got one, and then open it */
	if (argc != 2) {
		fprintf(stderr, "usage: %s event-device - probably /dev/input/evdev0\n", argv[0]);
		exit(1);
	}
	if ((fd = open(argv[1], O_RDONLY)) < 0) {
		perror("evdev open");
		exit(1);
	}

	int has_absolutes = 0;
	int is_mouse = 0;
	int running = 1;
	int current = 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){
		perror("evdev");
		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){
		Display *display;
		Window root;
		Window fromroot, tmpwin;
		XEvent xevent;
		XWindowAttributes attrib;

		if ((display = XOpenDisplay(NULL)) == NULL) {
			fprintf(stderr, "Cannot open local X-display.\n");
			exit(1);
		}
		root = DefaultRootWindow(display);
		int x, y, tmp, x2, y2;
		int last_code = -1;


		while(running){
			struct input_event event;
			int br = read(fd, &event, sizeof (event));
			if (br == -1)
			{
				if (errno == EAGAIN)
					continue;
			}
			if (br != sizeof (event))
				continue;
			if (event.type == EV_REL)
			{
				XQueryPointer(display, root, &fromroot, &tmpwin, &x, &y, &tmp, &tmp, &tmp);
				if ((event.code == REL_X) || (event.code == REL_DIAL))
					x += event.value * 10;
				else if (event.code == REL_Y)
					y += event.value * 10;
				else if (event.code == REL_WHEEL)
				{
					printf("REL_WHEEL\n");
				} /* else if */

				XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
				XFlush(display);
			} else if (event.type == EV_KEY){
				printf("EV_KEY %x\n", event.code);
				if (event.code == BTN_LEFT){
					bzero(&xevent,sizeof(XEvent));
					xevent.type = roll_event(&current);
					xevent.xbutton.button = Button1;
					xevent.xbutton.same_screen = True;
					xevent.xbutton.time = CurrentTime;


					XQueryPointer(display, root,
							&xevent.xbutton.root, &xevent.xbutton.window,
							&xevent.xbutton.x_root, &xevent.xbutton.y_root,
							&xevent.xbutton.x, &xevent.xbutton.y,
							&xevent.xbutton.state);

					xevent.xbutton.subwindow = xevent.xbutton.window;
					xevent.xbutton.state = Button1Mask;


					while (xevent.xbutton.subwindow) {
						xevent.xbutton.window = xevent.xbutton.subwindow;

						XQueryPointer(display, xevent.xbutton.window,
								&xevent.xbutton.root, &xevent.xbutton.subwindow,
								&xevent.xbutton.x_root, &xevent.xbutton.y_root,
								&xevent.xbutton.x, &xevent.xbutton.y,
								&xevent.xbutton.state);
					}
					/* Send a ButtonPress and ButtonRelease (of button 1) to the middle screen window */
					if( XSendEvent(display, xevent.xbutton.subwindow, True, ButtonPressMask, &xevent) == 0)
						printf("Error: XSendEvent error on ButtonPress event\n");
					XFlush(display);

				}
			}
			XFlush(display);

		}
	}
	close(fd);
	exit(0);
}
