Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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`

OR

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

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?

Solution:

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 "%030s\n",shift' "$line" | aplay &> /dev/null &
done

Lasership version:

#!/bin/bash
MP3=(); for i in mp3/*.mp3; do MP3+=("$i"); done
NMP3=${#MP3[@]}
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 &
done

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

share|improve this question
    
if youve used iornix's solution, you should probably switch accepted answers. –  mikeserv Jul 18 at 13:15

2 Answers 2

up vote 3 down vote accepted

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.

share|improve this answer
    
Thank you that worked very well :). If I only had two accept answer buttons :(. –  polym Jul 18 at 11:51

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 '\003')
    tty_state=$(stty -g)
    stty raw istrip
    while key=$(
        dd bs=1 count=1
    ) ; do : "${key:=
}";     printf " %03o %03d %#x\n\r" \
            "'$key" "'$key" "'$key"
        [ -z "${key#"$exit"}" ] && {
            stty "$tty_state"
            break
        }
    done 2>/dev/null
} </dev/tty
share|improve this answer
    
@polym - I found this answer from a month or two ago that deals with a lot of the same stuff. There are others there, too, that are pretty good. –  mikeserv Jul 14 at 21:50
    
Unfortunately this doesn't work when pressing CTRL and similar :(. –  polym Jul 18 at 9:43
    
@polym - Hmm, I think that is strange, as it does for me. Can you try the update? Quit with CTRL+C. –  mikeserv Jul 18 at 11:01

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.