Skip to content

Contributed by bzhou830, curated by Ai-Thinker

Peripheral porting: USB keyboard + M61 board - DIY experience sharing - IoT Developer Community - Ai-Thinker Forum

1. Report Descriptor

With the USB keyboard foundation from the previous post, making a USB mouse is simple. Like the USB keyboard, the USB mouse is also an HID device, so you only need to modify the HID report descriptor to turn the USB keyboard into a USB mouse.

Change the HID report descriptor from the previous post to the following form:

cpp
static const uint8_t hid_mouse_report_desc[HID_MOUSE_REPORT_DESC_SIZE] = {
    0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
    0x09, 0x02, /* USAGE (Mouse) */
    0xA1, 0x01, /* COLLECTION (Application) */
    0x09, 0x01, /* USAGE (Pointer) */
    0xA1, 0x00, /* COLLECTION (Physical) */
    0x05, 0x09, /* USAGE_PAGE (Button) */
    0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
    0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */
    0x15, 0x00, /* LOGICAL_MINIMUM (0) */
    0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
    0x95, 0x03, /* REPORT_COUNT (3) */
    0x75, 0x01, /* REPORT_SIZE (1) */
    0x81, 0x02, /* INPUT (Data,Var,Abs) */
    0x95, 0x01, /* REPORT_COUNT (1) */
    0x75, 0x05, /* REPORT_SIZE (5) */
    0x81, 0x01, /* INPUT (Cnst,Var,Abs) */
    0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
    0x09, 0x30, /* USAGE (X) */
    0x09, 0x31, /* USAGE (Y) */
    0x09, 0x38, /* USAGE (Wheel) */
    0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
    0x25, 0x7F, /* LOGICAL_MAXIMUM (127) */
    0x75, 0x08, /* REPORT_SIZE (8) */
    0x95, 0x03, /* REPORT_COUNT (3) */
    0x81, 0x06, /* INPUT (Data,Var,Rel) */
    0xC0, 0x09, /* END_COLLECTION, USAGE */
    0x3c, 0x05, /* USAGE (Wheel), USAGE_PAGE */
    0xff, 0x09, /* USAGE_PAGE (Vendor Defined), USAGE */
    0x01, 0x15, /* USAGE (Vendor Defined 1), LOGICAL_MINIMUM */
    0x00, 0x25, /* LOGICAL_MINIMUM (0), LOGICAL_MAXIMUM */
    0x01, 0x75, /* LOGICAL_MAXIMUM (1), REPORT_SIZE */
    0x01, 0x95, /* REPORT_SIZE (1), REPORT_COUNT */
    0x02, 0xb1, /* REPORT_COUNT (2), FEATURE (Data,Var,Abs) */
    0x22, 0x75, /* FEATURE (Data,Var,Abs), REPORT_SIZE */
    0x06, 0x95, /* REPORT_SIZE (6), REPORT_COUNT */
    0x01, 0xb1, /* REPORT_COUNT (1), FEATURE (Cnst,Var,Abs) */
    0x01, 0xc0  /* FEATURE (Cnst,Var,Abs), END_COLLECTION */
};

2. Return Report

The data format of HID mouse communication differs from that of a keyboard. The data is sent as follows:

USB HID keyboard/mouse communication data format - Technical - IoT Developer Community - Ai-Thinker Forum

You can see that the 4 bytes above can be clearly represented with a struct:

cpp
struct hid_mouse {
    uint8_t buttons;
    int8_t x;
    int8_t y;
    int8_t wheel;
};

When sending data, you only need to fill in this struct:

cpp
void hid_mouse_test(void)
{
    /*!< move mouse pointer */
    mouse_cfg.x = 5;
    int ret = usbd_ep_start_write(HID_INT_EP, (uint8_t *)&mouse_cfg, 4);
    if (ret < 0)
    {
        return;
    }
}

OK, that completes the HID mouse. Isn't it simple?

Have questions?

For other questions, please visit the unified discussion area: Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23