Last active
August 29, 2015 14:08
-
-
Save bentglasstube/92b1641310c32b8bf723 to your computer and use it in GitHub Desktop.
Keylogger and associated keyboard heatmap generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
id=$(xinput --list |grep 'USB Keyboard' |head -1 |grep -oP '(?<=id=)\d+') | |
xinput --test $id >> ~/Documents/keylog.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
package KeyMap; | |
use 5.010; | |
use strict; | |
use warnings; | |
use SVG; | |
sub new { | |
my ($class, @args) = @_; | |
my $self = bless { | |
presses => [], | |
total => 0, | |
svg => SVG->new( | |
width => 940, | |
height => 300, | |
@args, | |
), | |
}, $class; | |
} | |
sub svg { shift->{svg} } | |
sub make_key { | |
my ($self, $x, $y, $w, $h, $text, $color) = @_; | |
my ($r, $g, $b) = @$color; | |
my $tcol = $color->[3] ? '#fff' : '#000'; | |
$self->svg->rectangle( | |
x => $x + 2, | |
y => $y + 2, | |
width => $w - 4, | |
height => $h - 4, | |
rx => 5, | |
ry => 5, | |
style => { | |
stroke => '#000', | |
fill => "rgb($r,$g,$b)", | |
}); | |
$self->svg->text( | |
x => $x + $w / 2, | |
y => $y + $h / 2 + 3, | |
style => { | |
'fill' => $tcol, | |
'text-align' => 'center', | |
'text-anchor' => 'middle', | |
'font-family' => 'Noto Sans', | |
'font-size' => '10px', | |
}, | |
)->cdata($text); | |
} | |
sub make_row { | |
my ($self, $x, $y, @keys) = @_; | |
foreach (@keys) { | |
$_ = [ $_, 1, 1 ] unless ref $_; | |
my ($code, $w, $h) = @$_; | |
$w ||= 1; | |
$h ||= 1; | |
$self->make_key($x, $y, $w * 40, $h * 40, | |
sprintf('%0.2f', $self->percent($code)), | |
$self->color($code)); | |
$x += $w * 40; | |
} | |
} | |
sub add_key_press { | |
my ($self, $code) = @_; | |
$self->{presses}[$code]++; | |
$self->{total}++; | |
delete $self->{max_percent}; | |
} | |
sub presses { shift->{presses}[shift] || 0 } | |
sub total { shift->{total} } | |
sub max_percent { | |
my ($self) = @_; | |
return $self->{max_percent} if exists $self->{max_percent}; | |
my $max = 0; | |
for (@{ $self->{presses} }) { | |
$max = $_ if $_ and $_ > $max; | |
} | |
return $self->{max_percent} = $max / $self->total * 100; | |
} | |
sub percent { | |
my ($self, $code) = @_; | |
return $self->presses($code) / $self->total * 100; | |
} | |
sub color { | |
my ($self, $code) = @_; | |
# Crazy exponential scaling gotten experimentally | |
my $scale = ($self->percent($code) / $self->max_percent) ** 0.3; | |
my ($r, $gb, $t); | |
if ($scale > 0.66) { | |
$r = 255 - int(128 * ($scale - 0.66) / 0.33); | |
$gb = 0; | |
$t = 1; | |
} else { | |
$r = 255; | |
$gb = 255 - int(255 * $scale / 0.66); | |
$t = 0; | |
} | |
return [ $r, $gb, $gb, $t ]; | |
} | |
sub render { | |
my ($self) = @_; | |
# base keys | |
$self->make_row(20, 80, 49, 10 .. 21, [ 22, 2 ]); | |
$self->make_row(20, 120, [ 23, 1.5 ], 24 .. 35, [ 51, 1.5 ]); | |
$self->make_row(20, 160, [ 66, 1.75 ], 38 .. 48, [ 36, 2.25 ]); | |
$self->make_row(20, 200, [ 50, 2.25 ], 52 .. 61, [ 62, 2.75 ]); | |
$self->make_row( | |
20, | |
240, | |
[ 37, 1.25 ], | |
[ 133, 1.25 ], | |
[ 64, 1.25 ], | |
[ 65, 6.25 ], | |
[ 108, 1.25 ], | |
[ 134, 1.25 ], | |
[ 135, 1.25 ], | |
[ 105, 1.25 ]); | |
# function keys | |
$self->make_row(20, 20, 9); | |
$self->make_row(100, 20, 67 .. 70); | |
$self->make_row(280, 20, 71 .. 74); | |
$self->make_row(460, 20, 75, 76, 95, 96); | |
# navigation | |
$self->make_row(630, 20, 107, 78, 127); | |
$self->make_row(630, 80, 118, 110, 112); | |
$self->make_row(630, 120, 119, 115, 117); | |
$self->make_row(670, 200, 111); | |
$self->make_row(630, 240, 113, 116, 114); | |
# number pad | |
$self->make_row(760, 80, 77, 106, 63, 82); | |
$self->make_row(760, 120, 79 .. 81, [ 86, 1, 2 ]); | |
$self->make_row(760, 160, 83 .. 85); | |
$self->make_row(760, 200, 87 .. 89, [ 104, 1, 2 ]); | |
$self->make_row(760, 240, [ 90, 2 ], 91); | |
} | |
sub xmlify { | |
my ($self, @args) = @_; | |
return $self->svg->xmlify(@args); | |
} | |
package main; | |
use strict; | |
use warnings; | |
use autodie; | |
my $INPUT = "$ENV{HOME}/Documents/keylog.txt"; | |
my $OUTPUT = "$ENV{HOME}/Documents/keyfreq.svg"; | |
open my $output, '>', $OUTPUT; | |
open my $input, '<', $INPUT; | |
my $map = KeyMap->new(); | |
while (<$input>) { | |
$map->add_key_press($1) if /^key release\s+(\d+)\s+$/; | |
} | |
close $input; | |
$map->render; | |
print $output $map->xmlify; | |
close $output; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment