Recently I've been trying to figure out how to simulate a key being held down via Rockbox's USB HID feature.
In firmware/usbstack/usb_hid.c where the function usb_hid_send() is defined, there's this piece of code:
logf("Sending cmd 0x%x", id);
length = report->buf_set(&buf[1], id) + 1;
logf("length %u", length);
if (!length)
return;
/* Key pressed */
buf_dump(buf, length, "key press");
usb_hid_queue(buf, length);
if (report->is_key_released)
{
/* Key released */
memset(&buf[1], 0, length-1);
buf_dump(buf, length, "key release");
usb_hid_queue(buf, length);
}
Looking at that, it seems that the last if block is what sends the 'key up' event to the host.
My reasoning was that by removing this, you could simulate a key being held down.
Building on this, idea, I wrote a function identical to usb_hid_send(), but with that if statement removed:
void usb_hid_send_keydown(usage_page_t usage_page, int id)
{
uint8_t length;
static unsigned char buf[HID_BUF_SIZE_CMD] USB_DEVBSS_ATTR
__attribute__((aligned(32)));
usb_hid_report_t *report = NULL;
for (uint8_t report_id = 1; report_id < REPORT_ID_COUNT; report_id++)
if (usb_hid_reports[report_id].usage_page == usage_page)
{
report = &usb_hid_reports[report_id];
buf[0] = report_id;
break;
}
if (!report)
{
logf("Unsupported usage_page");
return;
}
logf("Sending cmd 0x%x", id);
length = report->buf_set(&buf[1], id) + 1;
logf("length %u", length);
if (!length)
return;
usb_hid_try_send_drv();
}
However, it doesn't work.
My question is this: what should I do to simulate a key being held down?
EDIT:As it turns, out, I was Doing It Wrong (TM). The HID driver's keyboard component can take up to 4 key codes at once, packed into a 4-byte int.