168 lines
4.2 KiB
Plaintext
168 lines
4.2 KiB
Plaintext
|
#!/usr/bin/perl -w
|
||
|
|
||
|
# screenspy - Linux desktop monitoring daemon. Must be run as root.
|
||
|
|
||
|
# This script monitors one or more hardware devices (usually under /dev) for
|
||
|
# Linux systems running an X window manager.
|
||
|
#
|
||
|
# This script must be run as root because usually only root can read from
|
||
|
# hardware devices directly. You can set up a panel launcher to run this
|
||
|
# script with `sudo` if you previously set up the sudoers file to let your
|
||
|
# user run this script with no password.
|
||
|
#
|
||
|
# --Kirsle
|
||
|
# http://sh.kirsle.net/
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
use threads;
|
||
|
use threads::shared;
|
||
|
|
||
|
#################
|
||
|
# Configuration #
|
||
|
#################
|
||
|
|
||
|
# X display to grab screenshots from.
|
||
|
$ENV{DISPLAY} ||= ":0.0";
|
||
|
|
||
|
# Devices to monitor.
|
||
|
our @devices = (
|
||
|
"/dev/console", # keyboard input
|
||
|
"/dev/input/mice", # mouse input
|
||
|
);
|
||
|
|
||
|
# Screenshot command.
|
||
|
our $screenshot = 'scrot -q 85 "%s"';
|
||
|
|
||
|
# Output directory for screenshots.
|
||
|
our $outdir = '/home/kirsle/Pictures/screenspy';
|
||
|
|
||
|
# Calibration: number of seconds (after no activity) for it to take a screenshot.
|
||
|
our $threshold = 2; # I found that 2 seconds is the best for my system, 1 second and it takes screenshots too often.
|
||
|
|
||
|
# Calibration: if there's too much activity after the threshold, take screenshots every N seconds.
|
||
|
our $prolonged = 5;
|
||
|
|
||
|
# If you want some indication that the app is running, put the command to run in here.
|
||
|
# This command will be repeatedly run. Recommended is to use zenity and put an icon in
|
||
|
# your system tray. Leave blank for no command.
|
||
|
our $notify = "zenity --notification --window-icon=/usr/share/pixmaps/gnome-spider.png --text 'Running...'";
|
||
|
|
||
|
#####################
|
||
|
# End Configuration #
|
||
|
#####################
|
||
|
|
||
|
# Only let this script run once.
|
||
|
&checkdupes();
|
||
|
|
||
|
# Each thread will report the time when the last event happened.
|
||
|
my %lastEvent : shared;
|
||
|
my %changed : shared;
|
||
|
|
||
|
# Spawn a thread for each device.
|
||
|
my @threads = ();
|
||
|
foreach my $dev (@devices) {
|
||
|
# Make sure we can read the device.
|
||
|
if (!-r $dev) {
|
||
|
system("zenity --error --text \"Don't have permission to read from device $dev\"");
|
||
|
}
|
||
|
push (@threads, threads->create (\&monitor, $dev));
|
||
|
}
|
||
|
|
||
|
# If they want a command run, spawn a thread for it too.
|
||
|
if (length $notify) {
|
||
|
push (@threads, threads->create (\¬ify));
|
||
|
}
|
||
|
|
||
|
# Loop forever and let the threads do their thing.
|
||
|
while (1) {
|
||
|
# See if any events have stopped for longer than the threshold.
|
||
|
foreach my $dev (keys %lastEvent) {
|
||
|
if ($lastEvent{$dev} > 0 && time() - $lastEvent{$dev} >= $threshold) {
|
||
|
# take screenshot
|
||
|
print "$dev: idle, taking screenshot (" . (time() - $lastEvent{$dev}) . "; $threshold)\n";
|
||
|
&screenshot();
|
||
|
$lastEvent{$dev} = 0;
|
||
|
$changed{$dev} = 0;
|
||
|
}
|
||
|
}
|
||
|
select(undef,undef,undef,0.01);
|
||
|
}
|
||
|
|
||
|
sub monitor {
|
||
|
my $device = shift;
|
||
|
print "Monitoring device: $device\n";
|
||
|
|
||
|
# Store the time when the last event was seen.
|
||
|
$lastEvent{$device} = 0;
|
||
|
|
||
|
# When the lastEvent is first set (away from 0), record the time it was changed.
|
||
|
# This way for prolonged activity we can still take screenshots.
|
||
|
$changed{$device} = 0;
|
||
|
|
||
|
open (READ, $device);
|
||
|
my $buffer;
|
||
|
while (read(READ, $buffer, 1)) {
|
||
|
# Store the last event time
|
||
|
if ($lastEvent{$device} == 0) {
|
||
|
$changed{$device} = time();
|
||
|
}
|
||
|
$lastEvent{$device} = time();
|
||
|
|
||
|
# Too much activity?
|
||
|
if ($changed{$device} > 0 && time() - $changed{$device} > $prolonged) {
|
||
|
# Take screenshot.
|
||
|
print "$device: prolonged activity (> $prolonged seconds)\n";
|
||
|
&screenshot();
|
||
|
$changed{$device} = time();
|
||
|
}
|
||
|
}
|
||
|
close (READ);
|
||
|
}
|
||
|
|
||
|
sub notify {
|
||
|
while (1) {
|
||
|
system($notify);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub screenshot {
|
||
|
print "Taking screenshot!\n";
|
||
|
|
||
|
my @time = localtime(time());
|
||
|
my $date = join(" ",
|
||
|
join("-",
|
||
|
sprintf("%04d", $time[5] + 1900),
|
||
|
sprintf("%02d", $time[4] + 1),
|
||
|
sprintf("%02d", $time[3]),
|
||
|
),
|
||
|
join(":",
|
||
|
sprintf("%02d", $time[2]),
|
||
|
sprintf("%02d", $time[1]),
|
||
|
sprintf("%02d", $time[0]),
|
||
|
),
|
||
|
);
|
||
|
|
||
|
my $fname = $date;
|
||
|
my $i = 1;
|
||
|
while (-f "$outdir/$fname.png") {
|
||
|
$fname = $date . " [$i]";
|
||
|
$i++;
|
||
|
}
|
||
|
my $cmd = $screenshot;
|
||
|
$cmd =~ s/%s/$outdir\/$fname\.png/ig;
|
||
|
system($cmd);
|
||
|
}
|
||
|
|
||
|
sub checkdupes {
|
||
|
my $ps = `ps aux | grep screenspy`;
|
||
|
foreach my $line (split(/\n/,$ps)) {
|
||
|
chomp $line;
|
||
|
next if $line =~ /grep/i;
|
||
|
next if $line =~ /$$/i;
|
||
|
if ($line) {
|
||
|
die "Script is already running!\n";
|
||
|
}
|
||
|
}
|
||
|
}
|