#!/usr/bin/perl
#
# qt_tslib_inject.pl:
#
#   touch screen input injection tool for use with x11vnc.
#
# example usage:
#
#   x11vnc ... -rawfb console -pipeinput ./qt_tslib_inject_input.pl -env INJECT_OPTIONS=cal=/etc/pointercal
#
# See options below.
#
# tested on qtmoko (neo freerunner) with tslib.

#
# Copyright (c) 2010 by Karl J. Runge <runge@karlrunge.com>
#
# qt_tslib_inject.pl is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
# 
# qt_tslib_inject.pl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with qt_tslib_inject.pl; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
# or see <http://www.gnu.org/licenses/>.
# 

set_constants();

# one can set these env. vars. before running:

# the device file to inject the events into:
#
$dev = $ENV{INJECT_DEV};
$dev = "/dev/input/event1" unless $dev;

# options, see below. useful: cal=/etc/pointercal
#
$options = $ENV{INJECT_OPTIONS};
$options = '' unless $options ne '';

$debug = 0;	# enable debugging output:
$pressure = 1;	# level of touch pad pressure for click.
$btn_touch = 0;	# send BTN_TOUCH on clicks instead of pressure changes.
$absalways = 0;	# send a zero pressure absolute position event whenever mouse moves.
$dragskip = 0;	# how often to skip injecting motion event while dragging.

$a_xform = '';	# tslib's calibration coefficients.
@a = ();

%keycmds = ();	# user defined hotkeys to run external commands.

# separate the options by comma, e.g. pressure=5,cal=/etc/pointercal

if ($options =~ /absalways/i) {
	# set to always send a zero pressure ABS event when mouse moves
	$absalways = 1;
}
if ($options =~ /btn_touch/i) {
	# send BTN_TOUCH on clicks.
	$btn_touch = 1;
}
if ($options =~ /pressure=(\d+)/i) {
	# level of touchpad pressure to use on a touch.
	$pressure = $1;
}
if ($options =~ /dragskip=(\d+)/i) {
	# when dragging with pressure, skip this many events.
	$dragskip = $1;
}
if ($options =~ /cal=([^,]+)/i) {
	# tslib's /etc/pointercal linear transform:
	$a_xform = $1;
	if (-f $a_xform) {
		$a_xform = `head -n 1 '$a_xform'`;
		chomp $a_xform;
		$a_xform =~ s/^\s*//;
		$a_xform =~ s/\s*$//;
	}
}
if ($options =~ /keycmds=([^,]+)/i) {
	# format: keysym1:command1+keysym2:command2+...
	# e.g.: keycmds=F6:date+F7:'./x11vnc-0.9.10 -connect ./ctl.txt -R reset'
	my $str = $1;
	if (-f $str && open(F, "<$str")) {
		$str = '';
		while (<F>) {
			chomp;
			$_ =~ s/^\s*//;
			$_ =~ s/\s*$//;
			next if /^#/;
			next if $_ eq "";
			$str .= '+' if $str ne '';
			$str .= $_;
		}
		close F;
	}
	foreach my $part (split(/\+/, $str)) {
		my ($key, $cmd) = split(/:/, $part, 2);
		if ($key !~ /^\s*$/) {
			$keycmds{$key} = $cmd;
		}
	}
}
if ($options =~ /debug=(\d+)/i) {
	# debug printout
	$debug = $1;
} elsif ($options =~ /debug/i) {
	$debug = 1;
}

# end of the top part that user should read and understand 
# for setting options, etc.
######################################################################

$start = time();

# open the device for writing:
#
$modes = $O_WRONLY;
printf("open modes: 0x%x\n", $modes) if $debug;

sysopen(FD, $dev, $modes) || die "$dev: $!";

my $curr_mask = 0;
my $curr_x = 0;
my $curr_y = 0;
my $down_count = 0;

# read input events from x11vnc through STDIN:
#
while (<>) {
	chomp;
	if (/^Pointer/) {
		my ($p, $client, $x, $y, $mask, $hint) = split(' ', $_, 6);
		do_pointer($client, $x, $y, $mask, $hint);
	} elsif (/^Keysym/) {
		my ($k, $client, $down, $keysym, $name, $hint) = split(' ', $_, 6);
		do_keysym($client, $down, $keysym, $name, $hint);
	}
}

close(FD);

exit(0);

sub do_keysym {
	# qtmoko/neo does not support keystroke input.  so these will be ignored.
	# (one possibility would to be enable qtmoko to read from /dev/tty0.
	# but the injection mechanism would need to be modified.)
        my ($client, $down, $keysym, $name, $hint) = @_;

	$ENV{DO_KEYSYM} = "$client $down $keysym $name $hint";

	# one could implement his own 'hot keys' here.

	# process any keycmds:
	if (%keycmds && (exists $keycmds{$name} || exists $keycmds{ALL})) {
		my $cmd = $keycmds{$name};
		if (!exists $keycmds{$name}) {
			$cmd = $keycmds{ALL};
			print STDERR "keycmds: $name/ALL: running: $cmd\n";
			system("$cmd");
		} elsif ($down) {
			print STDERR "keycmds: $name: running: $cmd\n";
			system("$cmd");
		}
		return;
	}

	$name = "XK_$name";
	my $nolookup = 0;
	if (! exists $key_lookup{$name}) {
		$nolookup = 1;
	} elsif (! defined $key_lookup{$name}) {
		$nolookup = 2;
	} elsif ($key_lookup{$name} =~ /^\s*$/) {
		$nolookup = 3;
	}
	if ($nolookup) {
		print STDERR "do_keysym: key not implemented-$nolookup $down $keysym $name $hint.\n" if $debug;
		return;
	}

	print STDERR gettime() . " do_keysym: $name\n" if $debug;
	do_key($key_lookup{$name}, $down);
}

sub do_pointer {
        my ($client, $x, $y, $mask, $hint) = @_;
	my $x2 = $x;
	my $y2 = $y;
	if ($a_xform ne '') {
		# this is tslib's /etc/pointercal format.
		if (! @a) {
			# -528 33408 -3417516 -44200 408 40292028 56541
			@a = split(' ', $a_xform);
			foreach my $a (@a) {
				$a += 0.0;
			}
		}
		# this is the inverse of the tslib transformation:
		#
		$x2 = ( $a[4] * ($a[6] * $x - $a[2]) - $a[1] * ($a[6] * $y - $a[5]) )
			/ ( $a[4] * $a[0] - $a[1] * $a[3]);
		$y2 = ( $a[0] * ($a[6] * $y - $a[5]) - $a[3] * ($a[6] * $x - $a[2]) )
			/ ( $a[4] * $a[0] - $a[1] * $a[3]);
		$x2 = int($x2);
		$y2 = int($y2);
	}

	print STDERR gettime() . " do_pointer $x $y (=> $x2 $y2) $mask $hint.\n" if $debug;

	if (! $btn_touch) {
		if ($curr_mask == 0 && $mask == 0) {
			do_abs($x2, $y2, 0) if $absalways;
		} elsif ($curr_mask == 0 && $mask != 0) {
			do_abs($x2, $y2, $pressure);
			$down_count = 0;
		} elsif ($curr_mask != 0 && $mask == 0) {
			do_abs($x2, $y2, 0);
		} elsif ($curr_mask != 0 && $mask != 0) {
			$down_count++;
			if ($dragskip > 0) {
				if ($down_count % $dragskip == 0) {
					do_abs($x2, $y2, $pressure);
				} else {
					print STDERR "dragskip $down_count $dragskip\n" if $debug;
				}
			} else {
				do_abs($x2, $y2, $pressure);
			}
		}
	} else {
		if ($curr_mask == 0 && $mask == 0) {
			do_abs($x2, $y2, 0) if $absalways;
		} elsif ($curr_mask == 0 && $mask != 0) {
			do_abs($x2, $y2, 0);
			do_btn($BTN_TOUCH, 1);
		} elsif ($curr_mask != 0 && $mask == 0) {
			do_abs($x2, $y2, 0);
			do_btn($BTN_TOUCH, 0);
		} elsif ($curr_mask != 0 && $mask != 0) {
			;
		}
	}

	$curr_mask = $mask;
	$curr_x = $x2;
	$curr_y = $y2;
}

# struct input_event {
#         struct timeval time;
#         __u16 type;
#         __u16 code;
#         __s32 value;
# };

sub do_syn {
	my $ev = gtod();
	$ev .= pack("S", $EV_SYN);
	$ev .= pack("S", $SYN_REPORT);
	$ev .= pack("i", 0);
	print STDERR "do_syn EV_SYN\n" if $debug;
	my $ret = syswrite(FD, $ev, length($ev));
	if (!defined $ret) {
		print STDERR "do_syn: $!\n";
	}
}

sub do_key {
	# not supported by qtmoko
	my ($key, $down) = @_;
	my $ev = gtod();
	$ev .= pack("S", $EV_KEY);
	$ev .= pack("S", $key);
	$ev .= pack("i", $down);
	print STDERR "do_key $key $down\n" if $debug;
	my $ret = syswrite(FD, $ev, length($ev));
	if (!defined $ret) {
		print STDERR "do_key: $!\n";
	}
	do_syn();
}

sub do_btn {
	# only BTN_TOUCH supported by qtmoko (but it seems to be ignored??)
	my ($button, $down) = @_;
	my $ev = gtod();
	$ev .= pack("S", $EV_KEY);
	$ev .= pack("S", $button);
	$ev .= pack("i", $down);
	print STDERR "do_btn $button $down\n" if $debug;
	my $ret = syswrite(FD, $ev, length($ev));
	if (!defined $ret) {
		print STDERR "do_btn: $!\n";
	}
	do_syn();
}

sub do_abs {
	# absolute method is the workhorse for the touchscreen.
	my ($x, $y, $p) = @_;
	my $ev = gtod();
	$ev .= pack("S", $EV_ABS);
	$ev .= pack("S", $ABS_Y);
	$ev .= pack("i", $y);
	print STDERR "do_abs y=$y\n" if $debug;
	my $ret = syswrite(FD, $ev, length($ev));
	if (!defined $ret) {
		print STDERR "do_abs: $!\n";
	}
	$ev = gtod();
	$ev .= pack("S", $EV_ABS);
	$ev .= pack("S", $ABS_X);
	$ev .= pack("i", $x);
	print STDERR "do_abs x=$x\n" if $debug;
	$ret = syswrite(FD, $ev, length($ev));
	if (!defined $ret) {
		print STDERR "do_abs: $!\n";
	}
	$ev = gtod();
	$ev .= pack("S", $EV_ABS);
	$ev .= pack("S", $ABS_PRESSURE);
	$ev .= pack("i", $p);
	print STDERR "do_abs p=$p\n" if $debug;
	$ret = syswrite(FD, $ev, length($ev));
	if (!defined $ret) {
		print STDERR "do_abs: $!\n";
	}
	do_syn();
}

sub do_rel {
	# not supported by qtmoko
	my ($dx, $dy) = @_;
	my $ev = gtod();
	$ev .= pack("S", $EV_REL);
	$ev .= pack("S", $REL_Y);
	$ev .= pack("i", $dy);
	print STDERR "do_rel dy=$dy\n" if $debug;
	my $ret = syswrite(FD, $ev, length($ev));
	if (!defined $ret) {
		print STDERR "do_rel: $!\n";
	}
	$ev = gtod();
	$ev .= pack("S", $EV_REL);
	$ev .= pack("S", $REL_X);
	$ev .= pack("i", $dx);
	print STDERR "do_rel dx=$dx\n";
	$ret = syswrite(FD, $ev, length($ev));
	if (!defined $ret) {
		print STDERR "do_rel: $!\n";
	}
	do_syn();
}

sub gtod {
	# 32 bit machines.  TBD use perl module Time:HiRes.
	$tv = ("\0" x 4) x 2;   # assumes long is 4 bytes. should use pack.
	$tz = ("\0" x 4) x 2;
	syscall($linux_gettimeofday_syscall, $tv, $tz);
	return $tv;
}

sub gettime {
	my $tv = gtod();
	my ($tv_sec, $tv_usec) = unpack("L2", $tv);
	$tv_usec2 = sprintf("%8.6f", $tv_usec/1000000.0);
	if ( $tv_usec2 =~ /^0\./ ) {
		$tv_usec2 =~ s/^0\././;
		$tv_sec = "$tv_sec$tv_usec2";
	} else {
		$tv_sec = $tv_sec + ($tv_usec/1000000.0);
	}
	return sprintf("%.3f", $tv_sec - $start);
}

sub fsleep {
        my ($time) = @_; 
        select(undef, undef, undef, $time) if $time;
}

sub set_constants {

# from /usr/include/linux/uinput.h /usr/include/linux/input.h and x11vnc. 

# #define ABS_MAX                 0x3f = 63
# 
# #define UINPUT_MAX_NAME_SIZE    80
# 
# struct input_id {
#         __u16 bustype;
#         __u16 vendor;
#         __u16 product;
#         __u16 version;
# };
# 
# struct uinput_user_dev {
#         char name[UINPUT_MAX_NAME_SIZE];
#         struct input_id id;
#         int ff_effects_max;
#         int absmax[ABS_MAX + 1];
#         int absmin[ABS_MAX + 1];
#         int absfuzz[ABS_MAX + 1];
#         int absflat[ABS_MAX + 1];
# };
# #endif  /* __UINPUT_H_ */

$EV_SYN                  = 0x00;
$EV_KEY                  = 0x01;
$EV_REL                  = 0x02;
$EV_ABS                  = 0x03;
$EV_MSC                  = 0x04;
$EV_SW                   = 0x05;
$EV_LED                  = 0x11;
$EV_SND                  = 0x12;
$EV_REP                  = 0x14;
$EV_FF                   = 0x15;
$EV_PWR                  = 0x16;
$EV_FF_STATUS            = 0x17;
$EV_MAX                  = 0x1f;

$ID_BUS                  = 0;
$ID_VENDOR               = 1;
$ID_PRODUCT              = 2;
$ID_VERSION              = 3;

$BUS_PCI                 = 0x01;
$BUS_ISAPNP              = 0x02;
$BUS_USB                 = 0x03;
$BUS_HIL                 = 0x04;
$BUS_BLUETOOTH           = 0x05;
$BUS_VIRTUAL             = 0x06;

$BUS_ISA                 = 0x10;
$BUS_I8042               = 0x11;
$BUS_XTKBD               = 0x12;
$BUS_RS232               = 0x13;
$BUS_GAMEPORT            = 0x14;
$BUS_PARPORT             = 0x15;
$BUS_AMIGA               = 0x16;
$BUS_ADB                 = 0x17;
$BUS_I2C                 = 0x18;
$BUS_HOST                = 0x19;
$BUS_GSC                 = 0x1A;
$BUS_ATARI               = 0x1B;

$REL_X                   = 0x00;
$REL_Y                   = 0x01;
$REL_Z                   = 0x02;
$REL_RX                  = 0x03;
$REL_RY                  = 0x04;
$REL_RZ                  = 0x05;
$REL_HWHEEL              = 0x06;
$REL_DIAL                = 0x07;
$REL_WHEEL               = 0x08;
$REL_MISC                = 0x09;

$ABS_X                   = 0x00;
$ABS_Y                   = 0x01;
$ABS_Z                   = 0x02;
$ABS_RX                  = 0x03;
$ABS_RY                  = 0x04;
$ABS_RZ                  = 0x05;
$ABS_THROTTLE            = 0x06;
$ABS_RUDDER              = 0x07;
$ABS_WHEEL               = 0x08;
$ABS_GAS                 = 0x09;
$ABS_BRAKE               = 0x0a;
$ABS_HAT0X               = 0x10;
$ABS_HAT0Y               = 0x11;
$ABS_HAT1X               = 0x12;
$ABS_HAT1Y               = 0x13;
$ABS_HAT2X               = 0x14;
$ABS_HAT2Y               = 0x15;
$ABS_HAT3X               = 0x16;
$ABS_HAT3Y               = 0x17;
$ABS_PRESSURE            = 0x18;
$ABS_DISTANCE            = 0x19;
$ABS_TILT_X              = 0x1a;
$ABS_TILT_Y              = 0x1b;
$ABS_TOOL_WIDTH          = 0x1c;
$ABS_VOLUME              = 0x20;
$ABS_MISC                = 0x28;
$ABS_MT_TOUCH_MAJOR      = 0x30;
$ABS_MT_TOUCH_MINOR      = 0x31;
$ABS_MT_WIDTH_MAJOR      = 0x32;
$ABS_MT_WIDTH_MINOR      = 0x33;
$ABS_MT_ORIENTATION      = 0x34;
$ABS_MT_POSITION_X       = 0x35;
$ABS_MT_POSITION_Y       = 0x36;
$ABS_MT_TOOL_TYPE        = 0x37;
$ABS_MT_BLOB_ID          = 0x38;
$ABS_MT_TRACKING_ID      = 0x39;
#$ABS_MAX = 0x3f;


$BTN_MISC                = 0x100;
$BTN_0                   = 0x100;
$BTN_1                   = 0x101;
$BTN_2                   = 0x102;
$BTN_3                   = 0x103;
$BTN_4                   = 0x104;
$BTN_5                   = 0x105;
$BTN_6                   = 0x106;
$BTN_7                   = 0x107;
$BTN_8                   = 0x108;
$BTN_9                   = 0x109;

$BTN_MOUSE               = 0x110;
$BTN_LEFT                = 0x110;
$BTN_RIGHT               = 0x111;
$BTN_MIDDLE              = 0x112;
$BTN_SIDE                = 0x113;
$BTN_EXTRA               = 0x114;
$BTN_FORWARD             = 0x115;
$BTN_BACK                = 0x116;
$BTN_TASK                = 0x117;

$BTN_JOYSTICK            = 0x120;
$BTN_TRIGGER             = 0x120;
$BTN_THUMB               = 0x121;
$BTN_THUMB2              = 0x122;
$BTN_TOP                 = 0x123;
$BTN_TOP2                = 0x124;
$BTN_PINKIE              = 0x125;
$BTN_BASE                = 0x126;
$BTN_BASE2               = 0x127;
$BTN_BASE3               = 0x128;
$BTN_BASE4               = 0x129;
$BTN_BASE5               = 0x12a;
$BTN_BASE6               = 0x12b;
$BTN_DEAD                = 0x12f;

$BTN_GAMEPAD             = 0x130;
$BTN_A                   = 0x130;
$BTN_B                   = 0x131;
$BTN_C                   = 0x132;
$BTN_X                   = 0x133;
$BTN_Y                   = 0x134;
$BTN_Z                   = 0x135;
$BTN_TL                  = 0x136;
$BTN_TR                  = 0x137;
$BTN_TL2                 = 0x138;
$BTN_TR2                 = 0x139;
$BTN_SELECT              = 0x13a;
$BTN_START               = 0x13b;
$BTN_MODE                = 0x13c;
$BTN_THUMBL              = 0x13d;
$BTN_THUMBR              = 0x13e;

$BTN_DIGI                = 0x140;
$BTN_TOOL_PEN            = 0x140;
$BTN_TOOL_RUBBER         = 0x141;
$BTN_TOOL_BRUSH          = 0x142;
$BTN_TOOL_PENCIL         = 0x143;
$BTN_TOOL_AIRBRUSH       = 0x144;
$BTN_TOOL_FINGER         = 0x145;
$BTN_TOOL_MOUSE          = 0x146;
$BTN_TOOL_LENS           = 0x147;
$BTN_TOUCH               = 0x14a;
$BTN_STYLUS              = 0x14b;
$BTN_STYLUS2             = 0x14c;
$BTN_TOOL_DOUBLETAP      = 0x14d;
$BTN_TOOL_TRIPLETAP      = 0x14e;

$BTN_WHEEL               = 0x150;
$BTN_GEAR_DOWN           = 0x150;
$BTN_GEAR_UP             = 0x151;

$SYN_REPORT              = 0;
$SYN_CONFIG              = 1;
$SYN_MT_REPORT           = 2;

$KEY_RESERVED = 0;
$KEY_ESC =      1;
$KEY_1 =        2;
$KEY_2 =        3;
$KEY_3 =        4;
$KEY_4 =        5;
$KEY_5 =        6;
$KEY_6 =        7;
$KEY_7 =        8;
$KEY_8 =        9;
$KEY_9 =        10;
$KEY_0 =        11;
$KEY_MINUS =    12;
$KEY_EQUAL =    13;
$KEY_BACKSPACE =        14;
$KEY_TAB =      15;
$KEY_Q =        16;
$KEY_W =        17;
$KEY_E =        18;
$KEY_R =        19;
$KEY_T =        20;
$KEY_Y =        21;
$KEY_U =        22;
$KEY_I =        23;
$KEY_O =        24;
$KEY_P =        25;
$KEY_LEFTBRACE =        26;
$KEY_RIGHTBRACE =       27;
$KEY_ENTER =    28;
$KEY_LEFTCTRL = 29;
$KEY_A =        30;
$KEY_S =        31;
$KEY_D =        32;
$KEY_F =        33;
$KEY_G =        34;
$KEY_H =        35;
$KEY_J =        36;
$KEY_K =        37;
$KEY_L =        38;
$KEY_SEMICOLON =        39;
$KEY_APOSTROPHE =       40;
$KEY_GRAVE =    41;
$KEY_LEFTSHIFT =        42;
$KEY_BACKSLASH =        43;
$KEY_Z =        44;
$KEY_X =        45;
$KEY_C =        46;
$KEY_V =        47;
$KEY_B =        48;
$KEY_N =        49;
$KEY_M =        50;
$KEY_COMMA =    51;
$KEY_DOT =      52;
$KEY_SLASH =    53;
$KEY_RIGHTSHIFT =       54;
$KEY_KPASTERISK =       55;
$KEY_LEFTALT =  56;
$KEY_SPACE =    57;
$KEY_CAPSLOCK = 58;
$KEY_F1 =       59;
$KEY_F2 =       60;
$KEY_F3 =       61;
$KEY_F4 =       62;
$KEY_F5 =       63;
$KEY_F6 =       64;
$KEY_F7 =       65;
$KEY_F8 =       66;
$KEY_F9 =       67;
$KEY_F10 =      68;
$KEY_NUMLOCK =  69;
$KEY_SCROLLLOCK =       70;
$KEY_KP7 =      71;
$KEY_KP8 =      72;
$KEY_KP9 =      73;
$KEY_KPMINUS =  74;
$KEY_KP4 =      75;
$KEY_KP5 =      76;
$KEY_KP6 =      77;
$KEY_KPPLUS =   78;
$KEY_KP1 =      79;
$KEY_KP2 =      80;
$KEY_KP3 =      81;
$KEY_KP0 =      82;
$KEY_KPDOT =    83;
$KEY_103RD =    84;
$KEY_F13 =      85;
$KEY_102ND =    86;
$KEY_F11 =      87;
$KEY_F12 =      88;
$KEY_F14 =      89;
$KEY_F15 =      90;
$KEY_F16 =      91;
$KEY_F17 =      92;
$KEY_F18 =      93;
$KEY_F19 =      94;
$KEY_F20 =      95;
$KEY_KPENTER =  96;
$KEY_RIGHTCTRL =        97;
$KEY_KPSLASH =  98;
$KEY_SYSRQ =    99;
$KEY_RIGHTALT = 100;
$KEY_LINEFEED = 101;
$KEY_HOME =     102;
$KEY_UP =       103;
$KEY_PAGEUP =   104;
$KEY_LEFT =     105;
$KEY_RIGHT =    106;
$KEY_END =      107;
$KEY_DOWN =     108;
$KEY_PAGEDOWN = 109;
$KEY_INSERT =   110;
$KEY_DELETE =   111;
$KEY_MACRO =    112;
$KEY_MUTE =     113;
$KEY_VOLUMEDOWN =       114;
$KEY_VOLUMEUP = 115;
$KEY_POWER =    116;
$KEY_KPEQUAL =  117;
$KEY_KPPLUSMINUS =      118;
$KEY_PAUSE =    119;
$KEY_F21 =      120;
$KEY_F22 =      121;
$KEY_F23 =      122;
$KEY_F24 =      123;
$KEY_KPCOMMA =  124;
$KEY_LEFTMETA = 125;
$KEY_RIGHTMETA =        126;
$KEY_COMPOSE =  127;
$KEY_STOP =     128;
$KEY_AGAIN =    129;
$KEY_PROPS =    130;
$KEY_UNDO =     131;
$KEY_FRONT =    132;
$KEY_COPY =     133;
$KEY_OPEN =     134;
$KEY_PASTE =    135;
$KEY_FIND =     136;
$KEY_CUT =      137;
$KEY_HELP =     138;
$KEY_MENU =     139;
$KEY_CALC =     140;
$KEY_SETUP =    141;
$KEY_SLEEP =    142;
$KEY_WAKEUP =   143;
$KEY_FILE =     144;
$KEY_SENDFILE = 145;
$KEY_DELETEFILE =       146;
$KEY_XFER =     147;
$KEY_PROG1 =    148;
$KEY_PROG2 =    149;
$KEY_WWW =      150;
$KEY_MSDOS =    151;
$KEY_COFFEE =   152;
$KEY_DIRECTION =        153;
$KEY_CYCLEWINDOWS =     154;
$KEY_MAIL =     155;
$KEY_BOOKMARKS =        156;
$KEY_COMPUTER = 157;
$KEY_BACK =     158;
$KEY_FORWARD =  159;
$KEY_CLOSECD =  160;
$KEY_EJECTCD =  161;
$KEY_EJECTCLOSECD =     162;
$KEY_NEXTSONG = 163;
$KEY_PLAYPAUSE =        164;
$KEY_PREVIOUSSONG =     165;
$KEY_STOPCD =   166;
$KEY_RECORD =   167;
$KEY_REWIND =   168;
$KEY_PHONE =    169;
$KEY_ISO =      170;
$KEY_CONFIG =   171;
$KEY_HOMEPAGE = 172;
$KEY_REFRESH =  173;
$KEY_EXIT =     174;
$KEY_MOVE =     175;
$KEY_EDIT =     176;
$KEY_SCROLLUP = 177;
$KEY_SCROLLDOWN =       178;
$KEY_KPLEFTPAREN =      179;
$KEY_KPRIGHTPAREN =     180;
$KEY_INTL1 =    181;
$KEY_INTL2 =    182;
$KEY_INTL3 =    183;
$KEY_INTL4 =    184;
$KEY_INTL5 =    185;
$KEY_INTL6 =    186;
$KEY_INTL7 =    187;
$KEY_INTL8 =    188;
$KEY_INTL9 =    189;
$KEY_LANG1 =    190;
$KEY_LANG2 =    191;
$KEY_LANG3 =    192;
$KEY_LANG4 =    193;
$KEY_LANG5 =    194;
$KEY_LANG6 =    195;
$KEY_LANG7 =    196;
$KEY_LANG8 =    197;
$KEY_LANG9 =    198;
$KEY_PLAYCD =   200;
$KEY_PAUSECD =  201;
$KEY_PROG3 =    202;
$KEY_PROG4 =    203;
$KEY_SUSPEND =  205;
$KEY_CLOSE =    206;
$KEY_PLAY =     207;
$KEY_FASTFORWARD =      208;
$KEY_BASSBOOST =        209;
$KEY_PRINT =    210;
$KEY_HP =       211;
$KEY_CAMERA =   212;
$KEY_SOUND =    213;
$KEY_QUESTION = 214;
$KEY_EMAIL =    215;
$KEY_CHAT =     216;
$KEY_SEARCH =   217;
$KEY_CONNECT =  218;
$KEY_FINANCE =  219;
$KEY_SPORT =    220;
$KEY_SHOP =     221;
$KEY_ALTERASE = 222;
$KEY_CANCEL =   223;
$KEY_BRIGHTNESSDOWN =   224;
$KEY_BRIGHTNESSUP =     225;
$KEY_MEDIA =    226;
$KEY_UNKNOWN =  240;
$KEY_OK =       0x160;
$KEY_SELECT =   0x161;
$KEY_GOTO =     0x162;
$KEY_CLEAR =    0x163;
$KEY_POWER2 =   0x164;
$KEY_OPTION =   0x165;
$KEY_INFO =     0x166;
$KEY_TIME =     0x167;
$KEY_VENDOR =   0x168;
$KEY_ARCHIVE =  0x169;
$KEY_PROGRAM =  0x16a;
$KEY_CHANNEL =  0x16b;
$KEY_FAVORITES =        0x16c;
$KEY_EPG =      0x16d;
$KEY_PVR =      0x16e;
$KEY_MHP =      0x16f;
$KEY_LANGUAGE = 0x170;
$KEY_TITLE =    0x171;
$KEY_SUBTITLE = 0x172;
$KEY_ANGLE =    0x173;
$KEY_ZOOM =     0x174;
$KEY_MODE =     0x175;
$KEY_KEYBOARD = 0x176;
$KEY_SCREEN =   0x177;
$KEY_PC =       0x178;
$KEY_TV =       0x179;
$KEY_TV2 =      0x17a;
$KEY_VCR =      0x17b;
$KEY_VCR2 =     0x17c;
$KEY_SAT =      0x17d;
$KEY_SAT2 =     0x17e;
$KEY_CD =       0x17f;
$KEY_TAPE =     0x180;
$KEY_RADIO =    0x181;
$KEY_TUNER =    0x182;
$KEY_PLAYER =   0x183;
$KEY_TEXT =     0x184;
$KEY_DVD =      0x185;
$KEY_AUX =      0x186;
$KEY_MP3 =      0x187;
$KEY_AUDIO =    0x188;
$KEY_VIDEO =    0x189;
$KEY_DIRECTORY =        0x18a;
$KEY_LIST =     0x18b;
$KEY_MEMO =     0x18c;
$KEY_CALENDAR = 0x18d;
$KEY_RED =      0x18e;
$KEY_GREEN =    0x18f;
$KEY_YELLOW =   0x190;
$KEY_BLUE =     0x191;
$KEY_CHANNELUP =        0x192;
$KEY_CHANNELDOWN =      0x193;
$KEY_FIRST =    0x194;
$KEY_LAST =     0x195;
$KEY_AB =       0x196;
$KEY_NEXT =     0x197;
$KEY_RESTART =  0x198;
$KEY_SLOW =     0x199;
$KEY_SHUFFLE =  0x19a;
$KEY_BREAK =    0x19b;
$KEY_PREVIOUS = 0x19c;
$KEY_DIGITS =   0x19d;
$KEY_TEEN =     0x19e;
$KEY_TWEN =     0x19f;
$KEY_DEL_EOL =  0x1c0;
$KEY_DEL_EOS =  0x1c1;
$KEY_INS_LINE = 0x1c2;
$KEY_DEL_LINE = 0x1c3;
$KEY_MAX =      0x1ff;


        $key_lookup{XK_Escape}  = $KEY_ESC;
        $key_lookup{XK_1}               = $KEY_1;
        $key_lookup{XK_2}               = $KEY_2;
        $key_lookup{XK_3}               = $KEY_3;
        $key_lookup{XK_4}               = $KEY_4;
        $key_lookup{XK_5}               = $KEY_5;
        $key_lookup{XK_6}               = $KEY_6;
        $key_lookup{XK_7}               = $KEY_7;
        $key_lookup{XK_8}               = $KEY_8;
        $key_lookup{XK_9}               = $KEY_9;
        $key_lookup{XK_0}               = $KEY_0;
        $key_lookup{XK_exclam}  = $KEY_1;
        $key_lookup{XK_at}              = $KEY_2;
        $key_lookup{XK_numbersign}      = $KEY_3;
        $key_lookup{XK_dollar}  = $KEY_4;
        $key_lookup{XK_percent} = $KEY_5;
        $key_lookup{XK_asciicircum}     = $KEY_6;
        $key_lookup{XK_ampersand}       = $KEY_7;
        $key_lookup{XK_asterisk}        = $KEY_8;
        $key_lookup{XK_parenleft}       = $KEY_9;
        $key_lookup{XK_parenright}      = $KEY_0;
        $key_lookup{XK_minus}   = $KEY_MINUS;
        $key_lookup{XK_underscore}      = $KEY_MINUS;
        $key_lookup{XK_equal}   = $KEY_EQUAL;
        $key_lookup{XK_plus}    = $KEY_EQUAL;
        $key_lookup{XK_BackSpace}       = $KEY_BACKSPACE;
        $key_lookup{XK_Tab}             = $KEY_TAB;
        $key_lookup{XK_q}               = $KEY_Q;
        $key_lookup{XK_Q}               = $KEY_Q;
        $key_lookup{XK_w}               = $KEY_W;
        $key_lookup{XK_W}               = $KEY_W;
        $key_lookup{XK_e}               = $KEY_E;
        $key_lookup{XK_E}               = $KEY_E;
        $key_lookup{XK_r}               = $KEY_R;
        $key_lookup{XK_R}               = $KEY_R;
        $key_lookup{XK_t}               = $KEY_T;
        $key_lookup{XK_T}               = $KEY_T;
        $key_lookup{XK_y}               = $KEY_Y;
        $key_lookup{XK_Y}               = $KEY_Y;
        $key_lookup{XK_u}               = $KEY_U;
        $key_lookup{XK_U}               = $KEY_U;
        $key_lookup{XK_i}               = $KEY_I;
        $key_lookup{XK_I}               = $KEY_I;
        $key_lookup{XK_o}               = $KEY_O;
        $key_lookup{XK_O}               = $KEY_O;
        $key_lookup{XK_p}               = $KEY_P;
        $key_lookup{XK_P}               = $KEY_P;
        $key_lookup{XK_braceleft}       = $KEY_LEFTBRACE;
        $key_lookup{XK_braceright}      = $KEY_RIGHTBRACE;
        $key_lookup{XK_bracketleft}     = $KEY_LEFTBRACE;
        $key_lookup{XK_bracketright}    = $KEY_RIGHTBRACE;
        $key_lookup{XK_Return}  = $KEY_ENTER;
        $key_lookup{XK_Control_L}       = $KEY_LEFTCTRL;
        $key_lookup{XK_a}               = $KEY_A;
        $key_lookup{XK_A}               = $KEY_A;
        $key_lookup{XK_s}               = $KEY_S;
        $key_lookup{XK_S}               = $KEY_S;
        $key_lookup{XK_d}               = $KEY_D;
        $key_lookup{XK_D}               = $KEY_D;
        $key_lookup{XK_f}               = $KEY_F;
        $key_lookup{XK_F}               = $KEY_F;
        $key_lookup{XK_g}               = $KEY_G;
        $key_lookup{XK_G}               = $KEY_G;
        $key_lookup{XK_h}               = $KEY_H;
        $key_lookup{XK_H}               = $KEY_H;
        $key_lookup{XK_j}               = $KEY_J;
        $key_lookup{XK_J}               = $KEY_J;
        $key_lookup{XK_k}               = $KEY_K;
        $key_lookup{XK_K}               = $KEY_K;
        $key_lookup{XK_l}               = $KEY_L;
        $key_lookup{XK_L}               = $KEY_L;
        $key_lookup{XK_semicolon}       = $KEY_SEMICOLON;
        $key_lookup{XK_colon}   = $KEY_SEMICOLON;
        $key_lookup{XK_apostrophe}      = $KEY_APOSTROPHE;
        $key_lookup{XK_quotedbl}        = $KEY_APOSTROPHE;
        $key_lookup{XK_grave}   = $KEY_GRAVE;
        $key_lookup{XK_asciitilde}      = $KEY_GRAVE;
        $key_lookup{XK_Shift_L} = $KEY_LEFTSHIFT;
        $key_lookup{XK_backslash}       = $KEY_BACKSLASH;
        $key_lookup{XK_bar}             = $KEY_BACKSLASH;
        $key_lookup{XK_z}               = $KEY_Z;
        $key_lookup{XK_Z}               = $KEY_Z;
        $key_lookup{XK_x}               = $KEY_X;
        $key_lookup{XK_X}               = $KEY_X;
        $key_lookup{XK_c}               = $KEY_C;
        $key_lookup{XK_C}               = $KEY_C;
        $key_lookup{XK_v}               = $KEY_V;
        $key_lookup{XK_V}               = $KEY_V;
        $key_lookup{XK_b}               = $KEY_B;
        $key_lookup{XK_B}               = $KEY_B;
        $key_lookup{XK_n}               = $KEY_N;
        $key_lookup{XK_N}               = $KEY_N;
        $key_lookup{XK_m}               = $KEY_M;
        $key_lookup{XK_M}               = $KEY_M;
        $key_lookup{XK_comma}   = $KEY_COMMA;
        $key_lookup{XK_less}    = $KEY_COMMA;
        $key_lookup{XK_period}  = $KEY_DOT;
        $key_lookup{XK_greater} = $KEY_DOT;
        $key_lookup{XK_slash}   = $KEY_SLASH;
        $key_lookup{XK_question}        = $KEY_SLASH;
        $key_lookup{XK_Shift_R} = $KEY_RIGHTSHIFT;
        $key_lookup{XK_KP_Multiply}     = $KEY_KPASTERISK;
        $key_lookup{XK_Alt_L}   = $KEY_LEFTALT;
        $key_lookup{XK_space}   = $KEY_SPACE;
        $key_lookup{XK_Caps_Lock}       = $KEY_CAPSLOCK;
        $key_lookup{XK_F1}              = $KEY_F1;
        $key_lookup{XK_F2}              = $KEY_F2;
        $key_lookup{XK_F3}              = $KEY_F3;
        $key_lookup{XK_F4}              = $KEY_F4;
        $key_lookup{XK_F5}              = $KEY_F5;
        $key_lookup{XK_F6}              = $KEY_F6;
        $key_lookup{XK_F7}              = $KEY_F7;
        $key_lookup{XK_F8}              = $KEY_F8;
        $key_lookup{XK_F9}              = $KEY_F9;
        $key_lookup{XK_F10}             = $KEY_F10;
        $key_lookup{XK_Num_Lock}        = $KEY_NUMLOCK;
        $key_lookup{XK_Scroll_Lock}     = $KEY_SCROLLLOCK;
        $key_lookup{XK_KP_7}            = $KEY_KP7;
        $key_lookup{XK_KP_8}            = $KEY_KP8;
        $key_lookup{XK_KP_9}            = $KEY_KP9;
        $key_lookup{XK_KP_Subtract}     = $KEY_KPMINUS;
        $key_lookup{XK_KP_4}            = $KEY_KP4;
        $key_lookup{XK_KP_5}            = $KEY_KP5;
        $key_lookup{XK_KP_6}            = $KEY_KP6;
        $key_lookup{XK_KP_Add}  = $KEY_KPPLUS;
        $key_lookup{XK_KP_1}            = $KEY_KP1;
        $key_lookup{XK_KP_2}            = $KEY_KP2;
        $key_lookup{XK_KP_3}            = $KEY_KP3;
        $key_lookup{XK_KP_0}            = $KEY_KP0;
        $key_lookup{XK_KP_Decimal}      = $KEY_KPDOT;
        $key_lookup{XK_F13}             = $KEY_F13;
        $key_lookup{XK_F11}             = $KEY_F11;
        $key_lookup{XK_F12}             = $KEY_F12;
        $key_lookup{XK_F14}             = $KEY_F14;
        $key_lookup{XK_F15}             = $KEY_F15;
        $key_lookup{XK_F16}             = $KEY_F16;
        $key_lookup{XK_F17}             = $KEY_F17;
        $key_lookup{XK_F18}             = $KEY_F18;
        $key_lookup{XK_F19}             = $KEY_F19;
        $key_lookup{XK_F20}             = $KEY_F20;
        $key_lookup{XK_KP_Enter}        = $KEY_KPENTER;
        $key_lookup{XK_Control_R}       = $KEY_RIGHTCTRL;
        $key_lookup{XK_KP_Divide}       = $KEY_KPSLASH;
        $key_lookup{XK_Sys_Req} = $KEY_SYSRQ;
        $key_lookup{XK_Alt_R}   = $KEY_RIGHTALT;
        $key_lookup{XK_Linefeed}        = $KEY_LINEFEED;
        $key_lookup{XK_Home}            = $KEY_HOME;
        $key_lookup{XK_Up}              = $KEY_UP;
        $key_lookup{XK_Page_Up} = $KEY_PAGEUP;
        $key_lookup{XK_Left}            = $KEY_LEFT;
        $key_lookup{XK_Right}   = $KEY_RIGHT;
        $key_lookup{XK_End}             = $KEY_END;
        $key_lookup{XK_Down}            = $KEY_DOWN;
        $key_lookup{XK_Page_Down}       = $KEY_PAGEDOWN;
        $key_lookup{XK_Insert}  = $KEY_INSERT;
        $key_lookup{XK_Delete}  = $KEY_DELETE;
        $key_lookup{XK_KP_Equal}        = $KEY_KPEQUAL;
        $key_lookup{XK_Pause}   = $KEY_PAUSE;
        $key_lookup{XK_F21}             = $KEY_F21;
        $key_lookup{XK_F22}             = $KEY_F22;
        $key_lookup{XK_F23}             = $KEY_F23;
        $key_lookup{XK_F24}             = $KEY_F24;
        $key_lookup{XK_KP_Separator}    = $KEY_KPCOMMA;
        $key_lookup{XK_Meta_L}  = $KEY_LEFTMETA;
        $key_lookup{XK_Meta_R}  = $KEY_RIGHTMETA;
        $key_lookup{XK_Multi_key}       = $KEY_COMPOSE;

$ABS_MAX = 63;

$UI_DEV_CREATE  = 0x5501;
$UI_DEV_DESTROY = 0x5502;
$UI_SET_EVBIT   = 0x40045564;
$UI_SET_KEYBIT  = 0x40045565;
$UI_SET_RELBIT  = 0x40045566;
$UI_SET_ABSBIT  = 0x40045567;

# FIXME: time hires, etc.
$linux_gettimeofday_syscall = 78;

$O_RDONLY = 00;
$O_WRONLY = 01;
$O_RDWR   = 02;
$O_NDELAY = 04000;

}
