#!/usr/bin/perl
#Written by Jarett Stevens
#MacBook5,1 (Late 2008 Aluminum Macbook)
#ls -l on /dev/input/by-path to identify keyboard EVENT_DEV if necessary
#applesmc kernel module must be loaded for LED control
#$TIMEOUT can be adjust below to suit; default 60 seconds before dimming
#add to /etc/rc.local 

use strict ;
use warnings ;
use Time::HiRes qw ( sleep );
use POSIX 'setsid';

#Your event device may differ
my $EVENT_DEV = "usb-Apple__Inc._Apple_Internal_Keyboard___Trackpad-event-kbd" ;
my $BACKLIGHT_DIR="/sys/class/leds/smc::kbd_backlight" ;
my $TIMEOUT = 60 ;
my $BUFF ;
my $LED_LAST ;
my $LED_MAX ;

#daemonize
#http://snippets.dzone.com/posts/show/359
chdir '/'					or die "Can't chdir to /: $!";
open STDIN, '/dev/null'		or die "Can't read /dev/null: $!";
open STDOUT, '>/dev/null'	or die "Can't write to /dev/null: $!";
defined(my $pid = fork)		or die "Can't fork: $!";
exit if $pid;
setsid						or die "Can't start a new session: $!";
open STDERR, '>&STDOUT'		or die "Can't dup stdout: $!";


open(EVENT_DEV, "<", "/dev/input/by-id/$EVENT_DEV") or
	die("Could not open /dev/input/by-id/$EVENT_DEV for reading.\n") ;

binmode EVENT_DEV ;

sub led_dim {

	#get the value of the LED brightness before dimming
	open(LED_LAST, "<", "$BACKLIGHT_DIR/brightness") or
		die("Coult not open $BACKLIGHT_DIR/brightness for reading\n") ;

	for (<LED_LAST>) {
		chomp($_) ;
		$LED_LAST = $_ ;
	}

	#dim the LEDs
	for (my $CT = $LED_LAST ; $CT >= 0 ; $CT--) {
		open(LED_BRIGHT, ">", "$BACKLIGHT_DIR/brightness") ;
		print LED_BRIGHT "$CT\n" ;
		close(LED_BRIGHT) ;
		sleep(0.005) ;
	}
	
	#wait for a keyboard event
	read (EVENT_DEV, $BUFF, 8) ;


	#return the LEDs to the same brightness as before
	for (my $CT = 0 ; $CT <= $LED_LAST ; $CT++) {
		open(LED_BRIGHT, ">", "$BACKLIGHT_DIR/brightness") ;
		print LED_BRIGHT "$CT\n" ;
		close(LED_BRIGHT) ;
		sleep(0.005) ;
	}
	
	return ;

}
# get max brightness for startup
open(LED_MAX, "<", "$BACKLIGHT_DIR/max_brightness") or
	die("Could not open $BACKLIGHT_DIR/max_brightness\n") ;
for (<LED_MAX>) {
	chomp($_) ;
	$LED_MAX = $_ ;
	last ;
}

close(LED_MAX) ;

# set initial brightness (should be 255)
open(LED_BRIGHT, ">", "$BACKLIGHT_DIR/brightness") ;
print LED_BRIGHT "$LED_MAX\n" ;
close(LED_BRIGHT) ;


#infinite loop...
while (1) {

	eval {
		local $SIG{ALRM} = sub{ die("blank\n") };
		alarm($TIMEOUT) ;
		read(EVENT_DEV, $BUFF, 8) ;
		alarm(0) ;
	}; 

	if ($@) {
		led_dim ;
	}
}

# can't get here
close(EVENT_DEV) ;
exit(1) ;

