36

I need to record every keystroke and store in a file in the user directory ~, when using my account, I am not sudoer and I cannot install programs (like logKeys) in any way. How could I do so using terminal?

NOTE: This question it's not a duplicate of the other mention question; in this question I'm asking about every keystroke, while in the other the asker asked about keystroke in terminal session.

Mitro
  • 1,091

2 Answers2

57

xinput test can report all keyboard events to the X server. On a GNU system:

xinput list |
  grep -Po 'id=\K\d+(?=.*slave\s*keyboard)' |
  xargs -P0 -n1 xinput test

If you want to get key names from the key codes, you could post-process that output with:

awk 'BEGIN{while (("xmodmap -pke" | getline) > 0) k[$2]=$4}
     {print $0 "[" k[$NF] "]"}'

Add > file.log to store in a log file. Or | tee file.log to both log and see it.

xinput queries the XinputExtension of the X server. That's as close as you're going to get as a standard (I am not aware of any standard that covers X utilities) or common command to do that. That also does not require root privileges.

If the X server and xinput support version 2 of the XinputExtension, you can use test-xi2 instead of test which gives more information, in particular the state of the modifiers (shift, ctrl, alt...). Example:

$ xinput test-xi2 --root
EVENT type 2 (KeyPress)
    device: 11 (11)
    detail: 54
    flags:
    root: 846.80/451.83
    event: 846.80/451.83
    buttons:
    modifiers: locked 0 latched 0 base 0x4 effective: 0x4
    group: locked 0 latched 0 base 0 effective: 0
    valuators:
    windows: root 0x26c event 0x26c child 0x10006e6

You can translate the keycode (in detail) to a keysym with the help of xmodmap -pke again, and the effective modifier bitmask to something more helpful with the help of xmodmap -pm. For instance:

xinput test-xi2 --root | perl -lne '
  BEGIN{$"=",";
    open X, "-|", "xmodmap -pke";
    while (<X>) {$k{$1}=$2 if /^keycode\s+(\d+) = (\w+)/}
    open X, "-|", "xmodmap -pm"; <X>;<X>;
    while (<X>) {if (/^(\w+)\s+(\w*)/){($k=$2)=~s/_[LR]$//;$m[$i++]=$k||$1}}
    close X;
  }
  if (/^EVENT type.*\((.*)\)/) {$e = $1}
  elsif (/detail: (\d+)/) {$d=$1}
  elsif (/modifiers:.*effective: (.*)/) {
    $m=$1;
    if ($e =~ /^Key/){
      my @mods;
      for (0..$#m) {push @mods, $m[$_] if (hex($m) & (1<<$_))}
      print "$e $d [$k{$d}] $m [@mods]"
    }
  }'

would output:

KeyPress 24 [q] 0x19 [Shift,Alt,Num_Lock]

when I press Shift+Alt+q when num-lock is on.

Note that you don't need to have super-user privileges to install a program. If you have write access to somewhere on the file system where execute permission is granted (your home directory, /tmp, /var/tmp...) then you can copy an xinput command from a compatible system there and execute it.

  • It is very good, the output is key press n1 key press n2 key release ..Is there a way to show the letter instad of number? And how to store in a file the "log"? PS: unfortunatelly my PC doesn't have this program installed by default, and I can't install anything at the moment, I tried on another PC. – Mitro May 13 '14 at 13:33
  • Moreover the number can't recognize if I'm using 2 or " – Mitro May 13 '14 at 13:44
  • 2
    @AlessioMTX, all key presses will be logged though including the Shift and Capslock ones. See also my edit for key labels/symbols instead of keycodes. – Stéphane Chazelas May 13 '14 at 13:52
  • Ok, I'm taking a look! – Mitro May 13 '14 at 13:55
  • Me too, he deserve +50, but unfortunatelly I haven't finished tests with his solution. – Mitro May 16 '14 at 06:39
  • What should I do if I get this error message? "unable to find device --root" – Mitro May 17 '14 at 11:18
  • 1
    @AlessioMTX, you'll need xinput 1.6.1 or newer for --root. X utilities can be downloaded individually from http://xorg.freedesktop.org/releases/individual/app/. If you don't want to compile from source. Debian has a xinput 1.6.1 for several architectures for Linux or kfreebsd. – Stéphane Chazelas May 17 '14 at 12:38
  • awk result is /bin/sh: 1: xmodmap: not found. What should I do? – Mitro May 17 '14 at 13:22
  • 1
    @AlessioMTX, that's meant for events to the X server. xmodmap has been in the reference X implementation since 1987 at least. What system are we talking about here? Could it be that xmodmap is not in your $PATH (/usr/dt/bin or other?). – Stéphane Chazelas May 19 '14 at 08:44
  • @StéphaneChazelas May I use a lightly modified version of this perl script in a program that I'm writing? – Nonny Moose Jun 09 '17 at 23:57
  • When piping through awk to tee, I found it necessary to prevent output buffering, either by calling awk with stdbuf (stdbuf -o0 awk ...) or by adding a system("") call within the awk script. – ivan Feb 18 '18 at 02:50
  • @ivan What awk implementation did you use? I found that neither of your tricks did not work with mawk (1.3.4), but you could use -Winteractive option with it or unbuffer -p from expect package (in Ubuntu at least). For other implementations I tried also stdbuf -oL works (and the unbuffer -p trick) . – jarno Jul 12 '20 at 17:36
  • Do all recent systems support version 2 of the XinputExtension? At least Ubuntu seems to support it, but what can you expect? – jarno Jul 12 '20 at 18:49
3

Have you considered using the script command?

Thomas Nyman
  • 30,502
etherfish
  • 1,274
  • It is not what I'm looking for. I read from the link but it is only for terminal session. – Mitro May 13 '14 at 13:53