Print currently pressed keys to stdout and read them line by line

I want to know which keys are pressed on my keyboard and print the information to stdout.

A tool that can do this is showkey. However, if I want to pass the data of showkey to read:

while read line; do
  echo "$line" | otherprog
done <`showkey -a`


showkey -a | while read line; do
  echo "$line" | otherprog

Then showkey waits until a sum of 140 characters is typed in and then sends the buffered information to read.

showkey -a prints the pressed keys line by line, without any buffering.

  1. Why does it buffer?
  2. How do I avoid this buffering, so that I can read showkey‘s output truly line by line?
  3. Is there an alternative to showkey?
  4. Is there a file I can read the pressed keys directly from?
  5. What is the correct way to pass data to read?


I’ve used lornix’s solution and included it into my simple keyboard keyboard :D!

stdbuf -o0 showkey -a | while read line; do
  perl -e 'print sprintf "%030sn",shift' "$line" | aplay &> /dev/null &

Lasership version:

MP3=(); for i in mp3/*.mp3; do MP3+=("$i"); done
stdbuf -o0 showkey -a 2>/dev/null | while read line; do
    [ -z "$line" ] || ! [[ $line =~ ^[0-9] ]] && continue
    NUM="$(echo "$line" | awk '{print $2}')"
    mplayer "${MP3[$(($NUM % $NMP3))]}" &>/dev/null &

In the same folder, download some laser mp3 files into a folder called mp3.

Asked By: polym


It buffers because your terminal is set to a line-oriented line-discipline. You need stty raw. Try this:

state=$(stty -g) 
key=$( (stty raw ; dd bs=1 count=1; stty $state) </dev/tty 2>/dev/null) 

But that will only work for single-byte keypresses. It might be a good idea to doLC_ALL=C first if there’s a chance that the input could contain multi-byte kepresses. A more sophisticated example might look more like this:

{   exit=$(printf '03')
    tty_state=$(stty -g)
    stty raw istrip
    while key=$(
        dd bs=1 count=1
    ) ; do : "${key:=
}";     printf " %03o %03d %#xnr" 
            "'$key" "'$key" "'$key"
        [ -z "${key#"$exit"}" ] && {
            stty "$tty_state"
    done 2>/dev/null
} </dev/tty
Answered By: mikeserv

Try setting showkey output to non-buffering with the stdbuf command:

stdbuf -o0 showkey -a | cat -

Will show the output as keys are pressed, rather than buffering a line.

stdbuf can adjust the buffering of stdin, stdout and stderr, setting them to none, line buffered, or block buffered, with a choosable block size. Very handy.

Answered By: lornix
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.