[libhid-discuss] reading from a barcode scanner that acts like a keyboard

Charles Lepple clepple at ghz.cc
Mon Nov 6 12:26:47 CET 2006


On Nov 5, 2006, at 9:53 PM, Brice Rebsamen wrote:

> $ test_libhid
> parse tree of HIDInterface 002/004[0]:
>  path: 0x00010006.0x00000000; type: 0x80

Unfortunately, the HIDParser portion of libhid does not properly dump  
descriptors with ranges of Usage codes, hence the zeroes in the last  
position. The 0x0001 is the "Generic Desktop Controls" page, and  
0x0006 is the Keyboard collection.

> $ lsusb -s 2:4 -vvv
[...]
>          Report Descriptor: (length is 65)
>            Item(Global): Usage Page, data= [ 0x01 ] 1
>                            Generic Desktop Controls
>            Item(Local ): Usage, data= [ 0x06 ] 6
>                            Keyboard
>            Item(Main  ): Collection, data= [ 0x01 ] 1
>                            Application
>            Item(Global): Usage Page, data= [ 0x07 ] 7
>                            Keyboard
>            Item(Local ): Usage Minimum, data= [ 0xe0 ] 224
>                            Control Left
>            Item(Local ): Usage Maximum, data= [ 0xe7 ] 231
>                            GUI Right
>            Item(Global): Logical Minimum, data= [ 0x00 ] 0
>            Item(Global): Logical Maximum, data= [ 0x01 ] 1
>            Item(Global): Report Size, data= [ 0x01 ] 1
>            Item(Global): Report Count, data= [ 0x08 ] 8
>            Item(Main  ): Input, data= [ 0x02 ] 2
>                            Data Variable Absolute No_Wrap Linear
>                            Preferred_State No_Null_Position
> Non_Volatile Bitfield

The preceding portion represents the state of modifier keys ranging  
from Control Left to GUI Right (probably the Windows key), and each  
modifier key gets a bit. So the first byte you read is probably not  
going to change, unless the barcode scanner sends mixed upper- and  
lower-case letters or something.

>            Item(Global): Report Count, data= [ 0x01 ] 1
>            Item(Global): Report Size, data= [ 0x08 ] 8
>            Item(Main  ): Input, data= [ 0x01 ] 1
>                            Constant Array Absolute No_Wrap Linear
>                            Preferred_State No_Null_Position
> Non_Volatile Bitfield

8 bits of padding.

>            Item(Global): Report Count, data= [ 0x05 ] 5
>            Item(Global): Report Size, data= [ 0x01 ] 1
>            Item(Global): Usage Page, data= [ 0x08 ] 8
>                            LEDs
>            Item(Local ): Usage Minimum, data= [ 0x01 ] 1
>                            NumLock
>            Item(Local ): Usage Maximum, data= [ 0x05 ] 5
>                            Kana
>            Item(Main  ): Output, data= [ 0x02 ] 2
>                            Data Variable Absolute No_Wrap Linear
>                            Preferred_State No_Null_Position
> Non_Volatile Bitfield

5 LEDs that you can set; not sure if these will correspond to actual  
LEDs or if they are just emulated so that keyboard drivers feel at  
home with this device.

>            Item(Global): Report Count, data= [ 0x01 ] 1
>            Item(Global): Report Size, data= [ 0x03 ] 3
>            Item(Main  ): Output, data= [ 0x01 ] 1
>                            Constant Array Absolute No_Wrap Linear
>                            Preferred_State No_Null_Position
> Non_Volatile Bitfield

3 bits of padding

>            Item(Global): Report Count, data= [ 0x06 ] 6
>            Item(Global): Report Size, data= [ 0x08 ] 8
>            Item(Global): Logical Minimum, data= [ 0x00 ] 0
>            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
>            Item(Global): Usage Page, data= [ 0x07 ] 7
>                            Keyboard
>            Item(Local ): Usage Minimum, data= [ 0x00 ] 0
>                            No Event
>            Item(Local ): Usage Maximum, data= [ 0xff 0x00 ] 255
>                            (null)
>            Item(Main  ): Input, data= [ 0x00 ] 0
>                            Data Array Absolute No_Wrap Linear
>                            Preferred_State No_Null_Position
> Non_Volatile Bitfield

This portion represents which "keys" are down, up to a maximum of six  
total.

Usage codes are basically page 0x0007, with the lower bits being the  
scan code. So you will need to find a table of PC keyboard scan codes  
and map these to ASCII based on the state of the shift bit earlier in  
the report.

Have you had a chance to read the HID spec yet? It's not too hard to  
read, and it is freely available from the USB Forum web site.

http://www.usb.org/developers/hidpage/ (see the Device Class  
Definition, and possibly the HID Usage Tables for the scan code tables)

>            Item(Main  ): End Collection, data=none
>      Endpoint Descriptor:
>        bLength                 7
>        bDescriptorType         5
>        bEndpointAddress     0x81  EP 1 IN
>        bmAttributes            3
>          Transfer Type            Interrupt
>          Synch Type               None
>          Usage Type               Data
>        wMaxPacketSize     0x0008  1x 8 bytes
>        bInterval              10
>

bInterval suggests that you poll the device every 10 milliseconds.  
Sometimes, you need to send a SET_IDLE request to start the data  
flowing:

    http://www.ghz.cc/~clepple/libhid/doc/html/ 
hid__exchange_8c.html#c96f8781c3ce92199eda3d18c98406e3

Then, you can use hid_interrupt_read() to read reports.  
Unfortunately, this function does not integrate well with the rest of  
libhid, so you will need to calculate byte offsets by hand as I have  
done above.

-- 
Charles Lepple
clepple at ghz.cc





More information about the libhid-discuss mailing list