Leonard / Pro micro keyboard report from target computer

Does anyone have any experience with making some sort of report with the keyboard libraries for the Leonardo or pro micro that tells you whether a keypress / print was received by your target computer? I'm not sure if there is some sort of handshake with the target computer that you are sending a keypress you could make a Boolean flag or something when that handshake has been completed? Have a series of pro micro boards that i'm sending keypresses to and ultimately i would like to create a report for each pro micro and possibly try to display that report on an lcd screen of which pro micro didn't send a keystroke to a machine. How feasible would this be? I'm assuming there is something that can be reported as the RX led lights up on the pro micro when a key stoke is accepted by the computer but no light if I unplug the usb from the computer i.e no light (the device is still powered and connected over serial to a leonardo so, yes its still trying to send key stoke data over the micro usb port despite being disconnected from the target machine).

How is the PC connected to the Arduino? If the protocol includes a handshake, each controller knows when a message has been received by the PC. Without such handshake the data will have been sent, unless the library is extremely buggy.

You can test every single Arduino first, to find out whether the problem exists with sending messages. If all of them pass that test, it's the PC that fails to process messages from multiple sources at the same time. Then you can control the number of (concurrent) keystrokes, sent by the controllers, to find out at which stress level the PC starts to miss something.

The pro micros are connected with USB to the targert host, so I have been trying to dig through info on how the communication happens between USB devices / computers but i'm not sure how that is handled by the pro micro. The libraries I am using are the HID-Project (GitHub - NicoHood/HID: Bring enhanced HID functions to your Arduino!) libraries as they support key presses in bios or post as I just learned the lesson that the regular keyboard.h libraries don't support USB "boot protocol".

So let me get a little more in depth for the project. Ive been building a device that will take a keypress from a keyboard and have a "master" leonardo + usb hosts shield capture the presses then pass those presses to a series of slave pro micros. Currently I have the pro micros chained together over serial but i'm looking at maybe trying to send the commands in parallel. The goal being is I work in a data center where a bunch of our guys build servers and set bios, raid, flash nic cards, ect. (I am aware there are ways to do this over the network, and we utilize many methods to do this but we are often building theses from scratch and have to set them one machine at time, times that by thousands of servers a week, its a ton of time). So i have a small version of this working that we can control 5 machines at a time and it works great with the tests so far however I want to scale this up to 40 pro micros that can control a whole rack of servers. The problem is we need to get into bios / post prompts while the machine is booting and sometimes a server in the bunch is behind booting up by a minute, for whatever reason. So this is fine with 5 machines that we can jack monitors into but if we start to scale this up we will want to know which machines in a rack are the slow pokes and the keypresses are getting out of sync from the rest. My thought was I could try to generate a report that could be sent back to the master leonardo board and connect an lcd that would display which ports are not registering presses at that current time. Then we can just unplug those ports and come back to them one at a time. Its the best solution I can think of but as you can see its not entirely flushed out. Any thoughts on how to tackle this problem would be greatly appreciated.

You get a result code if the USB message was successfully transfered but if you use the standard BootKeyboard class you don't get that result returned. But it's quite an easy change. Just set "ret" to the return value of the send() method in the press() and release() methods of DefaultKeyboard.

Apologies not sure if i'm following. So do I use BootKeyboard.press(ret) not sure where I'm using the "ret" that you mention. Arduino is pretty new to me so i've go a bit of a learning curve still. I'm pretty shocked this project has gotten as far as it has. Let me just include what is going on in the pro micro, i'm using .write not press or release:

#include <HID-Project.h>
#include <HID-Settings.h>
#include <hidboot.h>
#include <usbhub.h>

int c;
void setup(){

Serial1.begin(9600);
Serial.begin(9600);
BootKeyboard.begin();
}

void loop(){
c = Serial1.read();

switch(c){
case 176: BootKeyboard.write(KEY_RETURN); break;
case 177: BootKeyboard.write(KEY_ESC); break;
case 178: BootKeyboard.write(KEY_BACKSPACE); break;
case 179: BootKeyboard.write(KEY_TAB); break;
case 194: BootKeyboard.write(KEY_F1); break;
case 195: BootKeyboard.write(KEY_F2); break;
case 196: BootKeyboard.write(KEY_F3); break;
case 197: BootKeyboard.write(KEY_F4); break;
case 198: BootKeyboard.write(KEY_F5); break;
case 199: BootKeyboard.write(KEY_F6); break;
case 200: BootKeyboard.write(KEY_F7); break;
case 201: BootKeyboard.write(KEY_F8); break;
case 202: BootKeyboard.write(KEY_F9); break;
case 203: BootKeyboard.write(KEY_F10); break;
case 204: BootKeyboard.write(KEY_F11); break;
case 205: BootKeyboard.write(KEY_F12); break;
case 210: BootKeyboard.write(KEY_HOME); break;
case 211: BootKeyboard.write(KEY_PAGE_UP); break;
case 212: BootKeyboard.write(KEY_DELETE); break;
case 213: BootKeyboard.write(KEY_END); break;
case 214: BootKeyboard.write(KEY_PAGE_DOWN); break;
case 215: BootKeyboard.write(KEY_RIGHT_ARROW); break;
case 216: BootKeyboard.write(KEY_LEFT_ARROW); break;
case 217: BootKeyboard.write(KEY_DOWN_ARROW); break;
case 218: BootKeyboard.write(KEY_UP_ARROW); break;
default: {
//Serial.print(" N/A ");
BootKeyboard.write(c);

}
}
}

Apologies not sure if i'm following. So do I use BootKeyboard.press(ret) not sure where I'm using the "ret" that you mention.

No, you have to patch the library, in the current version it does not support what you're looking for. You have to change the press() and release() (and probably write()) methods of DefaultKeyboard.cpp in that library and then check the return code you get from a write to the BootKeyboard object. It should be positive, zero or negative means your key code wasn't transfered properly.

Please use code tags for posting code!

Thank you very much for the suggestion. Im not really sure where to begin with this, is there a good resource I could read on what I need to edit in the libraries?

Edit: So i think i see the file in the library you are directing me to DefaultKeyboard.hpp? i don't have a .cpp file that I can find on my machine. Seems some of these already are set to ret am i correct?

size_t DefaultKeyboardAPI::write(ConsumerKeycode k)
{
	// Press and release key (if press was successfull)
	auto ret = press(k);
	if(ret){
		release(k);
	}
	return ret;
}


size_t DefaultKeyboardAPI::press(ConsumerKeycode k)
{
	// Press key and send report to host
	auto ret = add(k);
	if(ret){
		send();
	}
	return ret;
}


size_t DefaultKeyboardAPI::release(ConsumerKeycode k) 
{
	// Release key and send report to host
	auto ret = remove(k);
	if(ret){
		send();
	}
	return ret;
}

That code already seems to return the required information. Now update your code, to get and use the ret code, like this:

while (BootKeyboard.write(whatever) <= 0) ; //send until success, assuming success > 0
break;

Cool now this is sort of making more sense to me. This is like using while (serial.available() <= 0); correct? Just with the BootKeyboard libraries?

That code already seems to return the required information. Now update your code, to get and use the ret code, like this:

No, it doesn't. It returns the result of the insertion into the local buffer but not the result of the actual transmit.

I would change DefaultKeyboard.hpp (sorry for the wrong extension) to something like this:

size_t DefaultKeyboardAPI::press(ConsumerKeycode k)
{
	// Press key and send report to host
	auto ret = add(k);
	if(ret){
		ret = send();
	}
	return ret;
}


size_t DefaultKeyboardAPI::release(ConsumerKeycode k) 
{
	// Release key and send report to host
	auto ret = remove(k);
	if(ret){
		ret = send();
	}
	return ret;
}

You might modify the write method similarly if you are interested in the result of the release command.