Arduino keyboard emulator is adding data to stream

All,

I’m pretty new to programming an arduino, but have general experience programming.

I’m trying to pass a series of keys via the Arduino Pro Micro.

I used a usb monitoring application to see the difference between the raw data streams, since it wasn’t working with my application.

For example, when I press the scroll lock key, the Dell keyboard registers “00 00 47 00 00 00 00 00”
But when I press the scroll key on the Arduino, it registers “02 00 00 47 00 00 00 00 00”

Is there any way to remove the “02” at the beginning, or just send the raw data stream manually?

Thanks in advance.
Jeff

Sketch_v1.ino (518 Bytes)

Arduino.txt (2.68 KB)

Dell Keyboard.txt (5.63 KB)

Very Short answer: it should not matter to your HID driver and it’s going to be a challenge to modify because that’s the specification…


**Theoretical answer:**you activate your arduino through USB as a Human Interface Device (HID). HID is an abstraction layer above the USB communication protocol to send different type of structured data in a very generic and flexible way. To keep it simple, what is sent on the USB bus when an HID device wants to send information is called a Report, defined in a report descriptor (specific to your device).

if you can have different types of Reports from a single endpoint, for example your arduino can send both mouse events and keyboard events over the same USB physical connexion, the specification mentions that a Report ID item has to be added in the communication to indicate which data fields are represented in each report structure. This Report ID is a 1-byte identification prefix to each report transfer.

So what you see is the fact that your keyboard only sends keys, and does not need a Report ID whereas your Arduino posing as an HID device has more capabilities and the spec states that it needs to send a report ID before the data. So you send a Report ID of 02 before the actual keyboard report. (a mouse event would send a Report ID of 01)

You can have a look at 5.6 Reports on page 17 of the HID specification for more details.

In a nutshell if you don’t have the Report ID then the HID driver assumes that only one report structure exists and represent all of the device’s data.

On Arduino, you need this one byte and it is hardcoded as 1 for a mouse event

HID().SendReport([b][color=red]1[/color][/b],m,4);

and 2 for a keyboard event.

HID().SendReport([color=red][b]2[/b][/color],keys,sizeof(KeyReport));

Long answer:
Understanding what happens in the code is always the ultimate documentation :slight_smile:

So you are sending code 207

When you call

Keyboard.write(207);

it’s actually calling in sequence the key down and key up messages

press(207);  // Keydown
release(207); // Keyup

and if you look at the code for press(), because 207 is larger than 136, it does 207-136=71 - which is 0x47(hex) - and adds this value to the first available entry in the key of the report and then sends the report with

HID().SendReport([color=red][b]2[/b][/color],keys,sizeof(KeyReport));

Now if you look into the HID code

int HID_::SendReport(uint8_t id, const void* data, int len)
{
 auto ret = USB_Send(pluggedEndpoint, &id, 1);
 if (ret < 0) return ret;
 auto ret2 = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len);
 if (ret2 < 0) return ret2;
 return ret + ret2;
}

You can see that it indeeds starts sending through USB the Report id on 1 byte, and then the data.
Because the ID was 2, that’s why you see the 02 at the start of the frame.

Then the report is sent. An HID keyboard input report is defined in the KeyReport structure and looks like this:

//  Low level key report: up to 6 keys and shift, ctrl etc at once
typedef struct
{
  uint8_t modifiers;
  uint8_t reserved;
  uint8_t keys[6];
} KeyReport;

and that’s what will go through USB after the ID. Since you have no modifiers nor reserved data (the second byte is reserved for OEM use) , the first two bytes are 0.

Then since the keys were emptied before your sending the press, the 0x47(hex)) value that was calculated is entered in keys[nobbc][0][/nobbc] and the rest remains empty. that’s why you then see on the USB bus

[color=navy]00[/color] [color=purple]00[/color] [color=blue]47[/color] 00 00 00 00 00

In total you’ve sent

Report ID       02
modifiers       00
OEM reserved    00
keys            47 00 00 00 00 00

Now you’ve seen the full function call tree that happens to get things done, you should have enough understanding → you could modify the libraries to only support keyboard, change the descriptor and skip sending the ReportID but in theory your computer should do the right thing through the HID driver…

This is an amazing response, thank you for spending the time to answer is such detail.

I am wanting to remove the Report ID, since the device I'm connecting to isn't a computer, but a KVM switch that I'm trying to remotely control. There is a bank of them, 6 total, so I need to be able to remotely control them all. The KVM switch (IOGREAR GCS1944) accepts keyboard commands to switch between inputs, through a dedicated keyboard port. When I use the dell keyboard, it works, when I use the Arduino it doesn't. The only reason I can think of, is the additional Report ID, since it expects a keyboard.

Are you saying I'd have to alter the HID library, or the keyboard.h library?

Thanks for the help.
Jeff

I think the KVM wants a Boot protocol keyboard.
Take a look at HID-Project.
BootKeyboard example: BootKeyboard.ino

yes HoodLoader2 would probably do the job