Keyboard pass-through project...

I experiemented with USB keyboard pass through using a Leonardo, a USB host board, and a computer running Linux. The keypresses work including control, alt, num lock, etc. I do not have time to try with Windows or Mac.

The pass through code is short because it operates on a low level USB data structure named the USB HID keyboard report. There is no reason to decode/parse the report on the Arduino since the keys are not used on the Arduino. Keyboard.sendReport function sends the report out to the computer. The report contains all the information about modifier keys, multiple key presses, etc.

Keyboard.sendReport is not public so the Keyboard.h file must be modified to expose it. Put the modified version in the same directory as the sketch.

A similar approach should work for USB mouse and USB joystick/gamepad pass throughs.

Suppose you want to have one USB keyboard broadcast to two computers. Add a second Leonardo. Send the 8 byte USB HID report from the first Leonardo to the second Leonardo via UART Tx -> Rx. When the second Leonardo receives the report via UART Rx, it sends the report out using Keyboard.sendReport. There is no need for a USB host board on the second (or third or fourth) Leonardo.

#include <hidboot.h>
#include <usbhub.h>

// Locally modified to make SendReport public.
#include "Keyboard.h"

// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

class KbdRptParser : public KeyboardReportParser
{
  protected:
    void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};

void KbdRptParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{
  Serial.print("KbdRptParser::Parse");
  // Show USB HID keyboard report
  for (uint8_t i = 0; i < len ; i++) {
    Serial.print(' '); Serial.print(buf[i], HEX);
  }
  Serial.println();

  // On error - return
  if (buf[2] == 1)
    return;

  if (len == 8)
    Keyboard.sendReport((KeyReport *)buf);
}

USB     Usb;
//USBHub     Hub(&Usb);
HIDBoot<USB_HID_PROTOCOL_KEYBOARD>    HidKeyboard(&Usb);

KbdRptParser Prs;

void setup()
{
  Serial.begin( 115200 );
  while (!Serial) delay(1);
  // Make sure we have time to get control of the board before going into USB keyboard mode.
  Serial.println("Start in 5 seconds");
  delay(5000);
#if !defined(__MIPSEL__)
  while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
  Serial.println("Start");

  if (Usb.Init() == -1)
    Serial.println("OSC did not start.");

  delay( 200 );

  HidKeyboard.SetReportParser(0, &Prs);
  
  Keyboard.begin();
}

void loop()
{
  Usb.Task();
}

There is one odd thing. On Linux the Leonardo appears as a composite device consisting of USB CDC ACM (serial port) AND USB keyboard. The serial console works at the same time as the USB keyboard! This is quite suprising so I am not sure if this works on Windows or Mac. Windows may require an INF file. Perhaps the solution is the sketch should not use Serial.

The keyboard LEDs do not work.