Using USB Keyboard

Here is the Python code that I'm using to read from a barcode scanner. This is a USB device that mimics the operation of a USB keyboard: when you scan a barcode, it sends the raw keystrokes as if you had typed the barcode in on a keyboard. I have the scanner configured to send a comma character at the end of the barcode, so this code collects and buffers data into the "barcode" variable until a comma is seen, and then it prints out the full barcode. For this scanner, I was only interested in the capital letters, so I ignored everything to do with the shift key and other modifiers, and assumed that every alphabetic keystroke was a capital letter. The barcode format I am using does not support many of the punctuation characters, so I left them out of the lookup table as well.

The script starts out by looking at the input parameters. It is expecting a simple number, like 0, 1, 2, etc. It takes that number and builds an input device name from it. For example, if the parameter is 1, it uses device /dev/input/event1. The default if there is no parameter is /dev/input/event0. (I needed to support multiple barcode scanners, so I ran a copy of this script for each scanner.)

The script then sets up a lookup table. The index to the table is the keycode, and the value of a table cell is the corresponding ASCII character.

The main processing of the script is to open the device file, and keep reading events. For each event, if type is 1, and value is 1, it is a normal keypress, so the key code value is passed through the lookup table if it's in the range of the table. The translated value is added to the buffered string. If the key code is out of range, it is ignored. When a terminator character is read, the whole string is sent. If there was an error reading an event (perhaps the scanner got unplugged?) the "while event" loop drops out, the input device file is closed, and the script ends.

You will undoubtedly have to make a bunch of changes to this, and your decoding logic may have to be a bit more involved, but hopefully this gives you another way to approach this. At a minimum, you will likely want to get rid of buffering the keystrokes, and just send them out immediately when they are received.

#!/usr/bin/python -u
# Note -u parameter above, which makes this script run in ubuffered mode
import struct
import time
import sys

# This script expects one argument, the event id number.

# default values
infile_path = "/dev/input/event0"
key = "0"

# Update the values if there is an argument
if len(sys.argv) > 1:
        key = sys.argv[1]
        infile_path = "/dev/input/event" + key

#long int, long int, unsigned short, unsigned short, unsigned int
FORMAT = 'llHHI'
EVENT_SIZE = struct.calcsize(FORMAT)

KeyLookup = [
   '',       #  0   KEY_RESERVED
   '',       #  1   KEY_ESC
   '1',      #  2   KEY_1
   '2',      #  3   KEY_2
   '3',      #  4   KEY_3
   '4',      #  5   KEY_4
   '5',      #  6   KEY_5
   '6',      #  7   KEY_6
   '7',      #  8   KEY_7
   '8',      #  9   KEY_8
   '9',      #  10  KEY_9
   '0',      #  11  KEY_0
   '',       #  12  KEY_MINUS
   '',       #  13  KEY_EQUAL
   '',       #  14  KEY_BACKSPACE
   '',       #  15  KEY_TAB
   'Q',      #  16  KEY_Q
   'W',      #  17  KEY_W
   'E',      #  18  KEY_E
   'R',      #  19  KEY_R
   'T',      #  20  KEY_T
   'Y',      #  21  KEY_Y
   'U',      #  22  KEY_U
   'I',      #  23  KEY_I
   'O',      #  24  KEY_O
   'P',      #  25  KEY_P
   '[',      #  26  KEY_LEFTBRACE
   ']',      #  27  KEY_RIGHTBRACE
   '',       #  28  KEY_ENTER
   '',       #  29  KEY_LEFTCTRL
   'A',      #  30  KEY_A
   'S',      #  31  KEY_S
   'D',      #  32  KEY_D
   'F',      #  33  KEY_F
   'G',      #  34  KEY_G
   'H',      #  35  KEY_H
   'J',      #  36  KEY_J
   'K',      #  37  KEY_K
   'L',      #  38  KEY_L
   '',       #  39  KEY_SEMICOLON
   '',       #  40  KEY_APOSTROPHE
   '',       #  41  KEY_GRAVE
   '',       #  42  KEY_LEFTSHIFT
   '\\',     #  43  KEY_BACKSLASH
   'Z',      #  44  KEY_Z
   'X',      #  45  KEY_X
   'C',      #  46  KEY_C
   'V',      #  47  KEY_V
   'B',      #  48  KEY_B
   'N',      #  49  KEY_N
   'M',      #  50  KEY_M
   '',       #  51  KEY_COMMA
   '.',      #  52  KEY_DOT
   '/' ]     #  53  KEY_SLASH

TERMINATOR = 51 # key code for end of barcode (KEY_COMMA)

barcode = ""


#open file in binary mode
in_file = open(infile_path, "rb")

event = in_file.read(EVENT_SIZE)

while event:
    (tv_sec, tv_usec, type, code, value) = struct.unpack(FORMAT, event)

    if type == 1 and value == 1:
        if code == TERMINATOR:
            # got the end of the barcode
            print barcode
            barcode = ""
        else:
            if code < len(KeyLookup):
                barcode = barcode +  KeyLookup[code]


    event = in_file.read(EVENT_SIZE)

in_file.close()[/quote]

Added: this is an example of the Linux side trying to do as much as possible to make the work of the Arduino sketch as easy as possible. The code you are working with sends out a long string that completely describes each keystroke. While I found that code invaluable for learning how the event interface works, and what events are sent under what conditions, I feel that's too much information to send up to the sketch. Not only does that clog up the relatively slow serial port that is between the two processors, it means much more work for the sketch to decode the data. By doing all of the pre-processing in the Python script, the script sends only complete barcodes up to the sketch, which the sketch can receive by simply reading lines of text from the Process object that is running this Python script.