Skip to content

Mouse Compatible Mode

Barryblueice edited this page Mar 9, 2026 · 5 revisions

In elan_i2c.c I programed a ptp mode activate function according to Sniffer Example:

esp_err_t elan_activate_ptp() {
    uint8_t payload[] = {
        0x05, 0x00,             // Command Register
        0x33, 0x03,             // SET_REPORT Feature ID 03 (PTP)
        0x06, 0x00,
        0x05, 0x00,             // Usage Page: Digitizer
        0x03, 0x03, 0x00        // Value: Enable PTP Mode
    };
    return i2c_master_transmit(dev_handle, payload, sizeof(payload), 200);
}

By following the example, we can obtain the activation function of Mouse Mode:

esp_err_t elan_activate_mouse() {
    uint8_t payload[] = {
        0x05, 0x00,
        0x33, 0x01,             // SET_REPORT Feature ID 01 (Mouse)
        0x06, 0x00,
        0x05, 0x00,
        0x01, 0x00, 0x00        // Value: Enable Mouse Mode
    };

    return i2c_master_transmit(dev_handle, payload, sizeof(payload), 200);
}

Default mode is also Mouse Mode, but we can switch between 2 different mode by these 2 functions, in order to adapt different host support.


During the development process, if the USB Description of Mouse Mode and PTP Mode is combined together, it will cause abnormal XY parsing, manifested as the system side parsing the 8-bit data sent by Mouse Mode in 16-bit mode (the PTP Descriptor contaminates the Mouse Descriptor).

Therefore, in the project, a scheme of separating PTP Descriptor from Mouse Descriptor was adopted.

Caution

This way of development is relatively simple, but the cost is that it may not support old systems well. In actual tests, Windows7 can recognize it normally, while WindowsXP reports error code 10.

#define EPNUM_TP_IN    0x81
#define EPNUM_MOUSE_IN 0x82

#define CONFIG_TOTAL_LEN  (TUD_CONFIG_DESC_LEN + 2 * TUD_HID_DESC_LEN)

const uint8_t mouse_hid_report_descriptor[] = {
    // MOUSE TLC
}

const uint8_t ptp_hid_report_descriptor[] = {
    // TOUCHPAD TLC
    //CONFIG TLC
}

uint8_t const desc_configuration[] = {
    TUD_CONFIG_DESCRIPTOR(1, 2, 0, CONFIG_TOTAL_LEN, 0x00, 100),
    TUD_HID_DESCRIPTOR(0, 0, HID_ITF_PROTOCOL_NONE, sizeof(ptp_hid_report_descriptor), EPNUM_TP_IN, 64, 10),
    TUD_HID_DESCRIPTOR(1, 0, HID_ITF_PROTOCOL_MOUSE, sizeof(mouse_hid_report_descriptor), EPNUM_MOUSE_IN, 8, 10)
};

We also need to set right HID Device Count in sdkconfig:

CONFIG_TINYUSB_HID_COUNT=2

Finally is processing the Mouse Mode data. Mouse Mode is relatively simple, so no algorithm optimization was carried out in the project.

mouse_current_state.x = (int8_t)data[4];
mouse_current_state.y = (int8_t)data[5];
mouse_current_state.buttons = data[3];

xQueueOverwrite(mouse_queue, &mouse_current_state);

Because the XY displacement value of the touchpad is relatively small, an amplification factor can be defined in advance in practical applications for convenient use.

Finally, just send the XY values and the left and right keys directly.

In Mouse Mode, the clicked status is mainly handled by the touchpad, and there is no need to rely on the X-coordinate for judgment as in PTP Mode.

const float SENSITIVITY = 3.0f;

typedef struct __attribute__((packed)) {
    uint8_t buttons;
    int8_t  x;
    int8_t  y;
} mouse_hid_report_t;

if (xQueueReceive(mouse_queue, &mouse_msg, portMAX_DELAY)) {
    mouse_hid_report_t report = {0};

    int move_x = (int)(mouse_msg.x * SENSITIVITY);
    int move_y = (int)(mouse_msg.y * SENSITIVITY);

    if (move_x > 127)  move_x = 127;
    if (move_x < -127) move_x = -127;

    if (move_y > 127)  move_y = 127;
    if (move_y < -127) move_y = -127;

    report.x = (int8_t)move_x;
    report.y = (int8_t)move_y;

    report.buttons = mouse_msg.buttons & 0x07;

    // ESP_LOGI(TAG, "X: %d, y:%d", report.x, report.y);

    if (tud_hid_n_ready(1)) {
        tud_hid_n_report(1, REPORTID_MOUSE, &report, sizeof(report));
    }
}

Clone this wiki locally