Bad-ass hackers
Modified: 2017-08-19
Status: thrown to the winds
Hollywood has made sure we all know it - hackers type fast into blazing terminals, with dark colour schemes.
Heh.
In comparison this keyboard chimp feels like most of their terminal type is spent slowly poking in sudo apt-get install thisprogramwillfulfillmydreams-0.21-dev
the majority of the time.
Instant truth check1:
history|awk '{print $4}'|awk 'BEGIN {FS="|"} {print $1}'|sort|uniq -c|sort -rn|head -30
955 ls
573 git
446 cd
348 sudo (followed by "apt-get" 67 times)
296 cat
204 nano
189 stack
158 grep
115 python3
98 rm
So I’m telling fibs; it is actually ls
that takes the title2.
At any rate, I would like to be as cool as the movie hackers, but only when I deserve it.
What if…
any CLI user was just a heart-racing, keyboard pounding, step away from being movie-cool?
I set out to make a terminal that graphically changes depending on the current typing speed. Give me a lowly black on white terminal when I’m slow, and a green on black one when I’m typing fast.
Ideally this would be a general purpose terminal - e.g. bash, that has some kind of overlay that does the shenanigans.
Make the things
What’s going on
The first lesson I had was that I wasn’t just using Bash. This should have been obvious because I put gnome-terminal
in my startup list to open what I called a ‘terminal’. Actually I had a terminal-emulator: gnome-terminal, and a shell: bash. I definitely can’t fault the program names for my ignorance.
How should it work?
I want to run gnome-terminal, just because.
Q. Do I want to:
Make a program that is a wrapper for bash:
gnome-terminal<->wrapper<->bash
- Make a program that picks up all low level HID input
Make a program that wraps gnome-terminal
A. A wrapper for bash seems most sensible. That way, only input to the specific terminal being used would be captured.
Unfortunately I’m not sure how to go about implementing this, and my random search for solutions (below) lead to a different design.
Toolbox…
Search keywords to proceed: “wrapper for interactive shell”
Leads:
script
logs a sessionYou can use
script
to write all terminal input and output to a file. Except it doesn’t work? Well ok it does, butcat
can’t handle it. It also doesn’t write constantly.cat - | bash
does something.(Takes stdin and pipes it to a bash process. Magically, stdout makes its way back to the parent bash shell. But we lose pretty terminal colours…)
expect
ooh ooh oh
Pexpect
!It has an example that works like
script
.
xinput test
Let’s you access the input stream, and provides stats.
what is that?
Well, I made something.
#!/bin/bash
# Try to change gnome-terminal profile colours based on rough keypress rate
# jank_level = High
# Response dynamics are magical and atrocious
# fast to start with, then /really/ damped
# I blame my usage of pv
# there is also a horrible contrast period when green is coming up
# bash profile to modify dynamically
bprofile="t37621as-3343-1dds-ffe3-2bj4uf87sd3h"
# This doesn't do what I hoped
buffersize=10
# This kinda sets the translation speed
delay=0.01 # 0.1s seems OK
# Green channel of text when bg is dark. Red and Blue always = 0
greenMax=160
# spawn a subshell to get keypresses using xinput.
(xinput test 10 | pv -lfa -s "$buffersize" > /dev/null 2> keylog.log) &
# Init things for the Big Ol' Loop
# 255 = white background
# 0 = black background
background=0
backgroundLast=0
bg=255
fgG=0
# Big Ol' Loop. We stay in here and update the background colour
while true; do
typeRate=$(grep "[0-9]*\.[0-9]*" --only-matching keylog.log | tail -1)
# do math with python
# get blacker as we get faster
# magic number breakdown:
# -2 is an attempt to compensate for the latency of typeRates
# 40 is a scaling factor
background=$(echo "print(255-min(255,int((float($typeRate)-2)*40)))" | python)
# adjust background at the same rate
if [ $background -lt $backgroundLast ]
then
let bg-=1
fi
if [ $background -gt $backgroundLast ]
then
let bg+=1
fi
# Change the text colour if we get quite dark
if [ $bg -lt 40 ]
then
let fgG+=1
elif [ $bg -lt 100 ]
then
let fgG+=2
else
let fgG-=1
fi
# Limit the allowable ranges
if [ $bg -gt 255 ]
then
let bg=255
fi
if [ $bg -lt 0 ]
then
let bg=0
fi
if [ $fgG -gt $greenMax ]
then
let fgG=$greenMax
fi
if [ $fgG -lt 0 ]
then
let fgG=0
fi
printf "Type Rate: % 10.2f\tBackground Target: % 10.2f\tBackground Current: % 10.2f\tForeground G: % 10.2f\n" "$typeRate" "$background" "$bg" "$fgG"
# write the background to gnome-shell profile
dconf write /org/gnome/terminal/legacy/profiles:/:"$bprofile"/background-color "'rgb($bg,$bg,$bg)'"
# write the foreground to gnome-shell profile
dconf write /org/gnome/terminal/legacy/profiles:/:"$bprofile"/foreground-color "'rgb(0,$fgG,0)'"
backgroundLast=$bg
sleep $delay
done
This script monitors the keyboard input using xinput test
3, and writes the type rate to a file, alarmingly called keylog.log. A loop is run which does some bad math and clunky edge-case handling to determine what colours to set in a gnome-terminal
profile.
Tangled source is available here: ../projects/littleProjects/code/badass_hacker.
Usage
Don’t4.
Demo
Improvements
- Everything
- Find a way of ensuring there is constant / rapid motion of the terminal window- make it more exciting
- The dynamics of the process is broken - it slows down after as more keys are pressed
The inevitable
(…discovery that nothing is new under the sun)
Courtesy of https://news.ycombinator.com/item?id=15537112:
- http://www.hackertyper.com/
- http://geektyper.com/
- https://atom.io/packages/activate-power-mode
- https://github.com/codeinthedark/editor
http://stackoverflow.com/a/6355236
Note I had to change the column of the first print to 4, as my bash history has a couple more columns than the default.↩
Maybe I could see what life is like if I get bash to perform an
ls
following eachcd
or similar. That would cut down on 1527 keystrokes right?. Or you could have a split view with a constantly updated file list separate from the command prompt - I’ll bet this exists.↩You’ll need to figure out what number you keyboard shows up as. I don’t know an intelligent way of doing this.↩
Alternatively; Do. It kinda works. Running this script will usually require sudo to access keyboard input. Be sure to change the
bprofile
variable to suit.↩