/*
 * Keylinkd, emulate mouse on keyboard.
 *
 * Copyright 1998 Pavel Machek, distribute under General Public
 * License version 2 or (at your opinion) any later version.
 *
 * This is version 0.0
 */

#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>

void
die( char *s )
{
	printf( s );
	exit(1);
}

int b, x, y; /* Our emulated mouse */
int mousefd;

void
sendupdate( void )
{
	char packet[5];
	packet[0] = 0x87^b;
	packet[1] = packet[3] = x;
	packet[2] = packet[4] = y;
	x = y = 0;
	if (mousefd != -1) {
		int res;
		if ((res =write( mousefd, packet, 5 ))!=5) {
			syslog( LOG_ERR, "Write returned %d (%m)\n", res );
		}
	}
}

void
arrow( int w, int n )
{
	w--;
	if ((w % 3) == 0) x-=n;
	if ((w % 3) == 2) x+=n;
	if ((w / 3) == 0) y-=n;
	if ((w / 3) == 2) y+=n;
	sendupdate();
}

void
button( int w, int n )
{
	w = 4-w;
	w = (1 << (w-1));
	if (!n) { b ^= w; sendupdate(); }
	if (n==2) { b |= w; sendupdate(); b &= ~w; sendupdate(); }
	if (n) { b |= w; sendupdate(); b &= ~w; sendupdate(); }
}

int
main( int argc, char *argv )
{
	int keylink = open( "/dev/keylink", O_RDONLY );
	if (keylink==-1) die( "Could not open keylink: %m\n" );
	if ((mousefd = open( "/dev/keymouse", O_RDWR | O_NONBLOCK ))==-1)
		printf( "Warning: Could not open keymouse: %m\n" );

	chdir( "/" );
	if (fork()) 
		return 0;
	while(1) {
		char c;
		read( keylink, &c, 1 );
		switch (c) {
		case 0: {	/* Paste */
			int fd;
			char func = 3;
			fd=open("/dev/tty0",O_WRONLY);
			if (fd<0) syslog( LOG_ERR, "keylinkd/paste: can't open /dev/tty0: %m.\n" );
			if (ioctl(fd, TIOCLINUX, &func)<0)
				syslog( LOG_ERR, "keylinkd/paste: can't ioctl: %m.\n" );
			close(fd);
			break;
		}
		case 1: case 2: case 3: case 4: case 6: case 7: case 8: case 9:
			arrow( c, 1 );
			break;
		case 10: case 11: case 12: case 13: case 15: case 16: case 17: case 18:
			arrow( c-9, 5 );
			break;
		case 20: case 21: case 22:
			button( c-19, 1 );
			break;
		case 23: case 24: case 25:
			button( c-22, 0 );
			break;
		case 26: case 27: case 28:
			button( c-25, 2 );
			break;
		default:
			syslog( LOG_ERR, "keylinkd: Unknown value from kernel: %d\n", (int) c );
		}
	}

}


