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 need to check some notebooks for bad keyboard keys, and so I'd like to speed that up as much as possible.

I found nothing for this specific task, so my idea is a script that reads the pressed keys and knows all the keyboard keys, so I can bash them quickly and it reports which ones are not pressed yet. I suppose I could accomplish that with either showkey or xev, grepping the output:

xev | grep keysym

Sample output:

state 0x10, keycode 46 (keysym 0x6c, l), same_screen YES,
state 0x10, keycode 33 (keysym 0x70, p), same_screen YES,
state 0x11, keycode 50 (keysym 0xffe1, Shift_L), same_screen YES,
state 0x10, keycode 51 (keysym 0x5d, bracketright), same_screen YES,
state 0x10, keycode 36 (keysym 0xff0d, Return), same_screen YES,

The readable keysym is quite useful, but I keed to test keycodes, as they do not change as modifier keys are switched on/off (caps lock, num lock). I'm new to bash, so I'm putting something together. This is best result so far:

#!/bin/bash

function findInArray() {
    local n=$#
    local value=${!n}
    for ((i=1;i < $#;i++)) {
    if [[ ${!i} == ${value}* ]]; then
    echo "${!i}"
    return 0
    fi
    }
    echo
    return 1
}

list=( 38:a 56:b 54:c 40:d 26:e 36:Return 50:Shift_L )
xev | \
# old grep solution
# grep -Po '(?<=keycode )[0-9]+(?= \(keysym 0x)' | \
# 200_success' suggestion
awk '/state 0x.*, keycode / { print $4; fflush() }' | \
while read keycode ; 
do
  found=$(findInArray "${list[@]}" ${keycode})
  if [[ $found ]]; then
    echo Pressed $found
    list=(${list[@]/${keycode}\:*/})
    echo 'Remaining ===>' ${list[@]}
    if [[ ${#list[@]} == 0 ]]; then
      echo All keys successfully tested!
      pkill xev
      exit 0
    fi
  fi
done

While I used grep it was only printing the output when I closed xev and it wouldn't kill it at the end too. The awk suggestion from @200_success solved these issues, but it does not print the output immediatelly: it takes 5-6 keystrokes for the output to be "flushed". How can I fix that?

Note: I know that this script would require a different list of keys for each different model of keyboard, but this is OK, as I only have a couple models to test.


Edit 1: I edited the question with my latest script code.

Edit 2: script updated according to @200_success suggestion.

share|improve this question
3  
array should like this list=( a b c d e f Shift_L Return ) isn't it ? –  Rahul Patil Sep 16 '13 at 15:43
1  
paste.ubuntu.com/6115446 –  Rahul Patil Sep 16 '13 at 15:44
    
@Rahul yes, what I posted is a string. My tests just worked first with it, so I posted anyway. But surely, a list is more appropriate for this. Thanks for your snippet. –  mdrg Sep 16 '13 at 17:10
    
@Rahul After some testing, I have a nearly functional script. I edited the question with it. –  mdrg Sep 16 '13 at 18:43

2 Answers 2

up vote 4 down vote accepted

Try replacing your grep line with an awk script that flushes its output.

xev | \
awk '/state 0x.*, keycode / { print $4; fflush() }' | \
while read keycode ; do
    # etc.
done
share|improve this answer
    
Great! I could say it's done, but I was wondering why is it taking so many keystrokes to print the output, like that 'flush' is not working. If I press 'b', it takes 5-6 other keystrokes for the Pressed 56:b to appear. –  mdrg Sep 17 '13 at 12:12
    
Found it: awk -W interactive. Thanks for your help, it was essential. –  mdrg Sep 17 '13 at 18:37

After some more trial-and-error, Google and man, this version works as I expected:

#!/bin/bash

function findInArray() {
  local n=$#
  local value=${!n}
  for ((i=1;i < $#;i++)) {
    if [[ ${!i} == ${value}:* ]]; then
      echo "${!i}"
      return 0
    fi
  }
  echo
  return 1
}

list=( 10:1 11:2 12:3 36:Return 37:Control_L 38:a 39:s 134:Super_R 135:Menu )
clear
echo -e "${#list[@]} keys to test\n\n${list[@]}"
xev | \
awk -W interactive '/state 0x.*, keycode / { print $4; fflush() }' | \
while read keycode ; 
do
  found=$(findInArray "${list[@]}" ${keycode})
  if [[ $found ]]; then
    clear
    echo Pressed $found
    list=(${list[@]/$found/})
    remaining=${#list[@]}
    stdbuf -oL -eL echo -e "$remaining keys remaining\n\n${list[@]}"
    if [[ $remaining == 0 ]]; then
      clear
      echo All keys successfully tested!
      pkill xev
      exit 0
    fi
  fi
done

Create your list based on xev output (I hastefully used xev | grep keycode, keyboard smash and regex replacements on a text editor) and replace it.

share|improve this answer

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.