#!/usr/bin/perl -w
#this came from http://samengstrom.com/p1510

use X11::GUITest ("SetEventSendDelay","MoveMouseAbs","PressMouseButton","ClickMouseButton","ReleaseMouseButton","IsMouseButtonPressed",":CONST");
use Time::HiRes;

use strict;
use warnings;

#NOTE: you may need to calibrate these (in the normal landscape mode)
use constant TOPLEFT=>(0.74,1.78);
#use constant TOPLEFT=>(0.70,1.06);
use constant BOTTOMRIGHT=>(31.51,31.25);
#use constant BOTTOMRIGHT=>(31.47,31.21);

use constant SCREEN=>(1280,768);
use constant DIGITIZER=>((BOTTOMRIGHT)[0]-(TOPLEFT)[0],(BOTTOMRIGHT)[1]-(TOPLEFT)[1]);

my $prevx=8;
my $prevy=0;
my $rot=0;

sub translate(@) {
	my $xmaj=$_[1];
	my $xmin=$_[0];
	my $ymaj=$_[3];
	my $ymin=$_[2];
	my $xdec=$xmaj+$xmin/128;
	my $ydec=$ymaj+$ymin/128;
	#NOTE: uncomment this to find out the values for TOPLEFT and BOTTOMRIGHT
	print $xdec."\t".$ydec."\n";
	my $xn=($xdec-(TOPLEFT)[0])/(DIGITIZER)[0];
	my $yn=($ydec-(TOPLEFT)[1])/(DIGITIZER)[1];
	my $x=$xn;
	my $y=$yn;
	my $sw=(SCREEN)[0];
	my $sh=(SCREEN)[1];
	if ($rot==1) {
		$x=$yn;
		$y=1-$xn;
		$sw=(SCREEN)[1];
		$sh=(SCREEN)[0];
	} elsif ($rot==-2) {
		$x=1-$xn;
		$y=1-$yn;
	} elsif ($rot==-1) {
		$x=1-$yn;
		$y=$xn;
		$sw=(SCREEN)[1];
		$sh=(SCREEN)[0];
	}
	$x=int($x*$sw);
	$y=int($y*$sh);
	if ($x<0) { $x=0; }
	if ($y<0) { $y=0; }
	if ($x>$sw) { $x=$sw; }
	if ($y>$sh) { $y=$sh; }
	return ($x,$y);
}

sub movemouse(@) {
	(my $x,my $y)=@_;
	if (($x ne $prevx)||($y ne $prevy)) {
		print "$x\t$y\n";
		$prevx=$x;
		$prevy=$y;
		MoveMouseAbs($x,$y);
	}
}

sub press() {
	print "press\n";
	#print 
	PressMouseButton(M_LEFT);
	#print ClickMouseButton(M_LEFT);
	#sleep 1;
	#print ClickMouseButton(M_LEFT);
}

sub rightpress() {
	print "rightpress\n";
	#print 
	PressMouseButton(M_RIGHT);
}

sub release() {
	#print PressMouseButton(M_LEFT);
	if (IsMouseButtonPressed(M_LEFT)) {
		#print 
		print "release left\n";
		ReleaseMouseButton(M_LEFT);
	} elsif (IsMouseButtonPressed(M_RIGHT)) {
		#print 
		print "release right\n";
		ReleaseMouseButton(M_RIGHT);
	}
}

sub click() {
	print "click\n";
	ClickMouseButton(M_LEFT);
}

sub rightclick() {
	print "rightclick\n";
	ClickMouseButton(M_RIGHT);
}

sub simpleprocess(\@) {
	my @block=@{$_[0]};
	my $action=$block[0];
	movemouse(translate(@block[1..5]));
	if (!$action) { return; }
	if ($action==1) {
		press();
		return;
	}
	if ($action==2) {
		release(); 
		return;
	}
}

my $pressx=0;
my $pressy=0;
my $presstime=0;
use constant DRAG=>(5,5);
use constant RIGHTCLICKDURATION=>0.5;#seconds
my $dragging=0;

sub twobuttonprocess(\@) {
	my @block=@{$_[0]};
	my $action=$block[0];
	(my $x,my $y)=translate(@block[1..5]);
	my $now=Time::HiRes::time;
	if ($action==1) {
		#touchscreen press
		movemouse($x,$y);
		$pressx=$x;
		$pressy=$y;
		$presstime=Time::HiRes::time;
		$dragging=0;
	} elsif ($action==2) {
		#touchscreen release
		if ($dragging) {
			movemouse($x,$y);
			release();
		#} elsif ($presstime && ($now>$presstime+RIGHTCLICKDURATION)) {
		#	movemouse($pressx,$pressy);
		#	rightclick();	
		} else {
			movemouse($pressx,$pressy);
			click();
		}
		$dragging=0;
		$presstime=0;
	} elsif ($dragging) {
		print "d";
		movemouse($x,$y);
	} elsif ($presstime && ($now>$presstime+RIGHTCLICKDURATION)) {
		movemouse($pressx,$pressy);
		rightpress();
		$dragging=1;
	}
	if ($presstime && !$dragging) {
		if (	(abs($x-$pressx)>(DRAG)[0]) ||
			(abs($y-$pressy)>(DRAG)[1])) {
			movemouse($pressx,$pressy);
			press();
			movemouse($x,$y);
			$dragging=1;
		}
	}
}

sub process(\@) {
	my @a=@{$_[0]};
	#simpleprocess(@a);
	twobuttonprocess(@a);
}

use constant SCREENTIMEOUT=>10*60;#seconds
my $screenlast=time - SCREENTIMEOUT;
sub displayon() {
	my $now=time;
	if ($now>$screenlast+SCREENTIMEOUT) {
		print "enabling display!\n";
		system "xset dpms force on";
	}
	$screenlast=$now;
}

######################## main
SetEventSendDelay(0);
$|=1;

my $doinit=1;
foreach my $v (@ARGV) {
	if ($v eq "-ni") { $doinit=0; }
	elsif ($v eq "-cw") { $rot=1; }
	elsif ($v eq "-ccw") { $rot=-1; }
	elsif ($v eq "-inv") { $rot=-2; }
	else {
		print "Invalid option '$v'\n";
		print "Usage:\n";
		print "\t$0 [options]\n";
		print "Options are:\n";
		print "\t-ni\tSkip serial port initialization with wacdump\n";
		print "\t-cw\tThe screen has been rotated clockwise\n";
		print "\t-ccw\tThe screen has been rotated counterclockwise\n";
		print "\t-inv\tThe screen has been rotated 180 degrees\n";
		exit(0);
	}
}

if ($doinit) {
	print "Initializing... (please don't touch the screen)\n";
	system "wacdump /dev/ttyS0 &> /dev/null";
	sleep 1;
} else {
	print "Skipping initialization...\n";
}
print "Ready!\n";

open FILEH,"/dev/ttyS0";
my $last=0;
my @block=();
my @pending=();
while(read(FILEH,my $data,1)) {
	#print $c." ";
	#$c++;
	#next;
	my $o=ord($data);
	if ($o>130) {
		@block=();
		if ($o==136) { push @block,1; }
		elsif ($o==138) { push @block,2; }
		else { push @block,0; }
		#print "\n$o\t";#
	} else {
		push @block,$o;
		#print "$o\t";
		if (@block==5) {
			process(@block);
			displayon();
		}
	}
	$last=$o;
}
close FILEH;
