The wireless keyboard, again (part deux)

For last week’s entry, I wrote a small script to monitor my wireless keyboard’s activity, logging keys, and mode changes. This week, let’s have a look at the data we can grab, and what we can do with it.

pigeon-camera

So, after grabbing keyboard activity for a bit more than a week (from 2014-10-12 22:47:31.059636 to 2014-10-20 08:45:06.733120), we’re ready to preprocess the logs and extract useful information.

One surprise the logs gave me is that when the keyboard is not used, it eventually goes into some kind of “sleep mode”, and this severs the link with the computer until one presses a key, which “wakes” the keyboard back to life. This, however, shows up in the hcidump log as events that are not all exactly 3 lines long. It messes up last’s weeks script quite a bit. So I had to repair the “flatten” script quite a bit.

#!/usr/bin/env bash

filename=$1

if [ "$filename" != "" ]
then
    line_pos=$(grep -n -e ^device: "$filename" | cut -d: -f 1)
    line_pos=$((line_pos+1))
    
    tail -n +$line_pos "$filename" | \
        ( 
        # disable word splitting for read
        # by unsetting IFS
        while IFS= read line
        do
            #echo "[$line]"
            # if it begins by a space
            if [[ "$line" =~ ^\  ]]
            then
                buffer="${buffer[@]} $line"
            else
                echo $buffer
                buffer="$line"
            fi
        done
    )
else
    echo provide a file name
    exit 1
fi

This lovely script “flattens” the log so that one event fits on one line. For example, it outputs something like this

2014-10-13 10:35:58.630766 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 02 00 00 00 00 00 00 00
2014-10-13 10:35:58.631984 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 00 00 00 00 00 00
2014-10-13 10:36:06.235849 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 05 00 00 00 00 00
2014-10-13 10:36:06.348474 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 00 00 00 00 00 00
2014-10-13 10:36:06.460853 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 08 00 00 00 00 00
2014-10-13 10:36:06.573485 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 00 00 00 00 00 00
2014-10-13 10:36:06.685857 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 0F 00 00 00 00 00

And you’ll also find in there events when the keyboard wakes up, etc. But this log is just a long list of Bluetooth events. I was initially interested in counting the number of keystrokes I do in a day. Looking at the log, we see that, every 2-3 rows, there’s a row there the data is 01 00 00 00 00 00 00 00 00. That’s the message of the keyboard returning to a neutral state, when all keys are released. Basically, the end of a keypress event. So we’ll split the log on these to get keystrokes.

#!/usr/bin/env bash

filename=$1

if [ "$filename" != "" ]
then
    lines=( $(grep -n "report .1 00 00 00" "$filename" | cut -d: -f 1 ) )
    nb_bundles=${#lines[@]}

    for ((b=0;b<nb_bundles-1;b++))
    do
        start=$((${lines[b]}+1))
        stop=${lines[((b+1))]}
        echo \#$start--$stop
        sed -n "$start,$stop p" "$filename"
    done
    
else
    echo provide a file name
fi

This script isn’t really efficient (sed probably has to reread the whole file every time) but it gets the job done. It chunks the log into bits like this:

#1199--1200
2014-10-13 11:22:59.690548 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 28 00 00 00 00 00
2014-10-13 11:22:59.869306 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 00 00 00 00 00 00
#1201--1202
2014-10-13 11:23:22.212043 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 50 00 00 00 00 00
2014-10-13 11:23:22.369545 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 00 00 00 00 00 00
#1203--1204
2014-10-13 11:23:22.527076 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 50 00 00 00 00 00
2014-10-13 11:23:22.707086 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 00 00 00 00 00 00
#1205--1210
2014-10-13 11:23:27.252098 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 39 00 00 00 00 00
2014-10-13 11:23:27.567085 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 39 06 00 00 00 00
2014-10-13 11:23:27.702067 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 39 00 00 00 00 00
2014-10-13 11:23:27.949601 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 39 17 00 00 00 00
2014-10-13 11:23:28.039597 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 39 00 00 00 00 00
2014-10-13 11:23:29.704653 > ACL data: handle 21 flags 0x02 dlen 14 L2CAP(d): cid 0x0041 len 10 [psm 19] HIDP: Data: Input report 01 00 00 00 00 00 00 00 00
#1211--1214

This underestimates the number of keys pressed because, like in the last example, it chops on the “zero message”, but key combinations such as ctrl-x ctrl-s (to save in Emacs) are treated as one key. Because you press ctrl, hold it, press x then s, then release ctrl. The three get bundled to one. The same happens when YOU TYPE ALL CAPS. You press shift and keep it pressed for the whole word. But I don’t do that often, anyways.

OK, now, the only thing left is to extract time stamps. Let’s get the first time stamp of a keypress event.

#!/usr/bin/env bash

filename=$1

if [ "$filename" != "" ]
then
    grep -A1 \# "$filename" \
        | grep -v \# \
        | grep -v -- "--" \
        | cut -d\> -f 1 \
        | ( while read line;
            do
              date -d "$line" "+%s.%N"
            done
          )
else
    echo provide a file name
fi

This script greps the time stamps and spews Unix times.

1413210966.460853000
1413210966.685857000
1413210966.843485000
1413210967.045893000
1413210967.630895000
1413210967.900889000
1413210969.183430000
1413210986.913657000

*
* 

Now that we have raw data, let’s do something with it. The first thing to do is to plot the daily usage.

key-daily-histogram

I’m not going to lie. I’m a night owl. I work at night. Well, that’s not like I didn’t know that already. In this data set (from 2014-10-12 22:47:31.059636 to 2014-10-20 08:45:06.733120) I hit more than 87490 keys (remember, this number is somewhat underestimated by the way strokes are parsed). It averages a bit more than 10K a day. OK, how fast do I type? Let’s draw the histogram of the times between keystrokes.

keyspacing-histogram

This one is hard to interpret. That’s how many keystrokes per seconds?

keyspacing-histogram-fps

According to this thing, I typically type at about 6 keys/s. The 15 kps (and above) is spurious. Sometimes the keyboard locks on a key (especially then the batteries are low) and it repeats uncontrollablyyyyyyyyyyyyyyyyyyyyyyyy the last key.

*
* 

The keyboard has proven itself to be mostly reliable unless the batteries are low. However, as soon as it is exposed to some light, the keyboard comes back to life and so the weird loooooooooow power problems do not occur too often. It’d probably be a bummer for people that like to work in the dark, but just a few hours of direct sunshine seem to be doing their magic.

*
* 

hcidump works well, but ultimately poses a security threat. Ran as root, it does allow you to capture everything that is typed, including passwords.

2 Responses to The wireless keyboard, again (part deux)

  1. LdaQuirm says:

    I’m curious, Do you think there is enough variance btw different peoples typing to reliably detect a new user by their tying style?
    (And maybe lock the computer if the new typing comes after a significant time lapse from the main user.)

    • That’s a good question. Probably not just first-order (i.e., time spacing between strokes) but maybe in combination of strokes? I would guess that it would be possible to detect the user, but to do so, we’d need a good number of tests subjects. Let’s write a paper on this!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: