Help with USB Host Shield + keyboard

Hello. I’m trying to make the following project with Arduino UNO: Arduino should process the input from a keyboard, and when a particular string is found, it should send it to my computer as a HID device.
In other words, what I’m trying to do is a sort of filter between a keyboard and a computer. This “filter” only allows data from the keyboard to reach the computer if a particular string is found.

I thought this can be achieved in two steps:

  1. get the keyboard input to the Arduino using a USB Host Shield;
  2. process the input and send the output to the computer as a HID device (to do this, I will have to load a different firmware on the Arduino).

For step 1, since I’m a very beginner at Arduino programming, I thought it could be useful to start from some ready-made project and then modify it to make it work as I want. The closest project I could find is this Arduino keyboard pass-throught project, in which Arduino should receive input from the keyboard and transparently send the same keys to the computer.

Here is the full code, took from the website I linked:

/* Arduino Keyboard HID driver and USB host shield pass through */

 * Copyright (c) 2011 Darran Hunt (darran [at] hunt dot net dot nz)
 * All rights reserved.

#include <Spi.h>
#include <Max3421e.h>
#include <Usb.h>

/* keyboard data taken from configuration descriptor */
#define KBD_ADDR        1
#define KBD_EP          1
#define KBD_IF          0
#define EP_MAXPKTSIZE   8
#define EP_POLL         0x0a

/* Sticky keys */
#define CAPSLOCK    0x39
#define NUMLOCK     0x53
#define SCROLLLOCK  0x47

/* Sticky keys output report bitmasks */
#define REP_NUMLOCK       0x01
#define REP_CAPSLOCK      0x02
#define REP_SCROLLLOCK    0x04

EP_RECORD ep_record[2];  //endpoint record structure for the keyboard

uint8_t buf[8] = { 0 };      // keyboard buffer
uint8_t old_buf[8] = { 0 };  // last poll

/* Sticky key state */
bool numLock = false;
bool capsLock = false;
bool scrollLock = false;

void setup();
void loop();
bool key_is_new(byte key, byte *report);

MAX3421E Max;
USB Usb;

void setup() 

void loop() 

    if (Usb.getUsbTaskState() == USB_STATE_CONFIGURING) {
        Usb.setUsbTaskState( USB_STATE_RUNNING);

    if (Usb.getUsbTaskState() == USB_STATE_RUNNING) {

/* Initialize keyboard */
void kbd_init( void )
    byte rcode = 0;  //return code

    /* Initialize data structures */
    ep_record[0] = *(Usb.getDevTableEntry(0,0));  //copy endpoint 0 parameters
    ep_record[1].MaxPktSize = EP_MAXPKTSIZE;
    ep_record[1].Interval  = EP_POLL;
    ep_record[1].sndToggle = bmSNDTOG0;
    ep_record[1].rcvToggle = bmRCVTOG0;
    Usb.setDevTableEntry(1, ep_record);              //plug kbd.endpoint parameters to devtable

    /* Configure device */
    rcode = Usb.setConf(KBD_ADDR, 0, 1);                    
    if (rcode) {
        while(1);  //stop

/* Poll USB keyboard for new key presses, send through to host via 
 * the Keyboard HID driver in the atmega8u2
void kbd_poll(void)
    char i;
    byte rcode = 0;     //return code
    uint8_t ledReport;
    static uint8_t lastLedReport = 0;
    static uint8_t leds = 0;
    static uint8_t lastLeds = 0;

    /* poll keyboard */
    rcode = Usb.inTransfer(KBD_ADDR, KBD_EP, 8, (char *)buf);
    if (rcode != 0) {

    /* Check for change */
    for (i=0; i<8; i++) {
        if (buf[i] != old_buf[i]) {
    /* Send the new key presses to the host */
    Serial.write(buf, 8);

    /* Get led report */
    ledReport =;
#if 0
            /* Not working yet, ledReport is always 0  */
    if (ledReport != lastLedReport) {
 rcode = Usb.setReport( KBD_ADDR, 0, 1, KBD_IF, 0x02, 0, (char *)&ledReport );
 lastLedReport = ledReport;

    /* Check for status keys and adjust led status */
    for (i=2; i<8; i++) {
 if (buf[i] == 0) {
    /* 0 marks end of keys in the report */
 /* Check new keys for status change keys */
 if (key_is_new(buf[i], old_buf)) {
    switch (buf[i]) {
    case CAPSLOCK:
 capsLock =! capsLock;
 leds = capsLock ? leds |= REP_CAPSLOCK : leds &= ~REP_CAPSLOCK;
    case NUMLOCK:
 numLock =! numLock;
 leds = numLock ? leds |= REP_NUMLOCK : leds &= ~REP_NUMLOCK;
    case SCROLLLOCK:
 scrollLock =! scrollLock;
 leds = scrollLock ? leds |= REP_SCROLLLOCK : leds &= ~REP_SCROLLLOCK;

    /* Got a change in LED status? */
    if (lastLeds != leds) {
 Usb.setReport( KBD_ADDR, 0, 1, KBD_IF, 0x02, 0, (char *)&leds );
 lastLeds = leds;

    /* update the old buffer */
    for (i=0; i<8; i++) {
 old_buf[i] = buf[i];


* Function:    key_is_new(key, report)
* Description: see if key is new or is already in report
* Returns:     false if found, true if not
bool key_is_new(uint8_t key, uint8_t *report)
    uint8_t ind;
    for (ind=2; ind<8; ind++) {
 if (report[ind] == key) {
    return false;
    return true;

This code is quite old and I get lots of errors. If I copy-paste it as it is, the first error I get is about the lines #include <Spi.h> and #include <Max3421e.h>. It disappears if I write “SPI” uppercase in the first one and “Max3421e” lowercase in the second one, however it gets replaced with a new error: “Never include max3421e.h directly; include Usb.h instead”.

So I tried removing the line #include <Max3421e.h> and this causes yet a whole bunch of errors:

Arduino:1.6.8 (Mac OS X), Board:"Arduino/Genuino Uno"

kbd_usb_passthrough:48: error: 'EP_RECORD' does not name a type
 EP_RECORD ep_record[2];  //endpoint record structure for the keyboard
/Users/jaggions/Desktop/kbd_usb_passthrough/kbd_usb_passthrough.ino: In function 'void setup()':
kbd_usb_passthrough:68: error: 'MAX3421E' has no member named 'powerOn'
/Users/jaggions/Desktop/kbd_usb_passthrough/kbd_usb_passthrough.ino: In function 'void kbd_init()':
kbd_usb_passthrough:93: error: 'ep_record' was not declared in this scope
     ep_record[0] = *(Usb.getDevTableEntry(0,0));  //copy endpoint 0 parameters
kbd_usb_passthrough:93: error: 'class USB' has no member named 'getDevTableEntry'
     ep_record[0] = *(Usb.getDevTableEntry(0,0));  //copy endpoint 0 parameters
kbd_usb_passthrough:98: error: 'class USB' has no member named 'setDevTableEntry'
     Usb.setDevTableEntry(1, ep_record);              //plug kbd.endpoint parameters to devtable
exit status 1
'EP_RECORD' does not name a type

I tried to do my research but I could not fix all this stuff by myself. Do you have any suggestions for my project? The ideal would be to have a rewritten and working version of the Arduino keyboard pass-throught project. Thanks in advance.