Search code examples
pythonhid

How can I get a String from HID device in Python with evdev?


I am new to python but have experience with HID devices and evdev. I have a 2D barcode scanner which interfaces as HID device. The goal is to get the string from a QR code. I am able to recognize the scanner in Linux and even found its location in /dev/input.

I found evdev and have implemented the example below with my scanner. This is just the default code on their site. It reads the values but it prints long event codes with downs and ups. I can't see an easy way to turn this into string. All I want to do is read in a string from the HID scanner in Python. Any help or direction would be appreciated (maybe evdev isnt the answer).

Here is my current python code with some example output:

from evdev import *
dev = InputDevice('/dev/input/event1')

print(dev)

for event in dev.read_loop():
    if event.type == ecodes.EV_KEY:
        print(categorize(event))

Here is the output from some barcodes:

key event at 1383327570.147000, 2 (KEY_1), down
key event at 1383327570.147990, 2 (KEY_1), up
key event at 1383327570.148997, 3 (KEY_2), down
key event at 1383327570.150010, 3 (KEY_2), up
key event at 1383327570.151009, 29 (KEY_LEFTCTRL), down
key event at 1383327570.151009, 42 (KEY_LEFTSHIFT), down
key event at 1383327570.152017, 36 (KEY_J), down
key event at 1383327570.153005, 36 (KEY_J), up
key event at 1383327570.154004, 29 (KEY_LEFTCTRL), up
key event at 1383327570.155005, 32 (KEY_D), down
key event at 1383327570.155993, 32 (KEY_D), up
key event at 1383327570.157002, 48 (KEY_B), down
key event at 1383327570.158015, 48 (KEY_B), up
key event at 1383327570.158997, 48 (KEY_B), down
key event at 1383327570.282002, 18 (KEY_E), up
key event at 1383327570.283004, 49 (KEY_N), down
key event at 1383327570.284005, 49 (KEY_N), up
key event at 1383327570.284968, 18 (KEY_E), down

Many thanks!


Solution

  • There's a conversion step you're missing here. Your output is already in a pretty format, so i'll help you break it down a little more:

                 Timestamp        , scancode, keycode, keystate
    key event at 1383327570.147000, 2         (KEY_1), down
    key event at 1383327570.147990, 2         (KEY_1), up
    

    To make any useful sense of this, you need to do a couple of things:

    1. Only listen to key_down type events by filter only for keystate of a specific type (Down = 1, Up = 0)
    2. Convert the scancode into a ASCII code, which can vary by device and vary by how it's mapped to the system!

    There's a simple-ish way to map them however. Generate a known barcode with all useable characters using an online service, then scan that barcode and map each scancode outputted to the correct letter/number for your scanner. You can use the following slightly modified piece of code to take better control of the output:

    import evdev
    from evdev import InputDevice, categorize  # import * is evil :)
    dev = InputDevice('/dev/input/event1')
    
    # Provided as an example taken from my own keyboard attached to a Centos 6 box:
    scancodes = {
        # Scancode: ASCIICode
        0: None, 1: u'ESC', 2: u'1', 3: u'2', 4: u'3', 5: u'4', 6: u'5', 7: u'6', 8: u'7', 9: u'8',
        10: u'9', 11: u'0', 12: u'-', 13: u'=', 14: u'BKSP', 15: u'TAB', 16: u'Q', 17: u'W', 18: u'E', 19: u'R',
        20: u'T', 21: u'Y', 22: u'U', 23: u'I', 24: u'O', 25: u'P', 26: u'[', 27: u']', 28: u'CRLF', 29: u'LCTRL',
        30: u'A', 31: u'S', 32: u'D', 33: u'F', 34: u'G', 35: u'H', 36: u'J', 37: u'K', 38: u'L', 39: u';',
        40: u'"', 41: u'`', 42: u'LSHFT', 43: u'\\', 44: u'Z', 45: u'X', 46: u'C', 47: u'V', 48: u'B', 49: u'N',
        50: u'M', 51: u',', 52: u'.', 53: u'/', 54: u'RSHFT', 56: u'LALT', 100: u'RALT'
    }
    for event in dev.read_loop():
        if event.type == evdev.ecodes.EV_KEY:
            data = evdev.categorize(event)  # Save the event temporarily to introspect it
            if data.keystate == 1:  # Down events only
                key_lookup = scancodes.get(data.scancode) or u'UNKNOWN:{}'.format(data.scancode)  # Lookup or return UNKNOWN:XX
                print u'You Pressed the {} key!'.format(key_lookup)  # Print it all out!
    

    Here's some sample output from this script for me

    You Pressed the A key!
    You Pressed the B key!
    You Pressed the C key!
    You Pressed the UNKNOWN:99 key!
    

    Once you generate some barcodes online, you'll know which scancode gets mapped to which value! Build your own table and profit!

    HTH