327 lines
12 KiB
C
327 lines
12 KiB
C
/*
|
|
* Copyright (c) 2025, sakumisu
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
//Refer to https://github.com/espressif/esp-bsp/blob/master/components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c
|
|
|
|
#include "usbh_core.h"
|
|
#include "usbh_hid.h"
|
|
#include "usbh_hid_lvgl.h"
|
|
|
|
|
|
/* LVGL image of cursor */
|
|
LV_IMG_DECLARE(img_cursor)
|
|
|
|
struct usbh_hid_lvgl {
|
|
struct {
|
|
lv_indev_t *indev; /* LVGL mouse input device driver */
|
|
uint8_t sensitivity; /* Mouse sensitivity (cannot be zero) */
|
|
int16_t x; /* Mouse X coordinate */
|
|
int16_t y; /* Mouse Y coordinate */
|
|
bool left_button; /* Mouse left button state */
|
|
} mouse;
|
|
struct {
|
|
lv_indev_t *indev; /* LVGL keyboard input device driver */
|
|
uint32_t last_key;
|
|
bool pressed;
|
|
} kb;
|
|
};
|
|
|
|
static struct usbh_hid_lvgl g_hid_lvgl;
|
|
|
|
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t hid_mouse_buffer[64];
|
|
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t hid_keyboard_buffer[64];
|
|
|
|
static void usbh_hid_lvgl_read_mouse(lv_indev_t *indev_drv, lv_indev_data_t *data)
|
|
{
|
|
int16_t width = 0;
|
|
int16_t height = 0;
|
|
struct usbh_hid_lvgl *ctx = &g_hid_lvgl;
|
|
|
|
lv_display_t *disp = lv_indev_get_display(indev_drv);
|
|
if (lv_display_get_rotation(disp) == LV_DISPLAY_ROTATION_0 || lv_display_get_rotation(disp) == LV_DISPLAY_ROTATION_180) {
|
|
width = lv_display_get_physical_horizontal_resolution(disp);
|
|
height = lv_display_get_vertical_resolution(disp);
|
|
} else {
|
|
width = lv_display_get_vertical_resolution(disp);
|
|
height = lv_display_get_physical_horizontal_resolution(disp);
|
|
}
|
|
|
|
/* Screen borders */
|
|
if (ctx->mouse.x < 0) {
|
|
ctx->mouse.x = 0;
|
|
} else if (ctx->mouse.x > width * ctx->mouse.sensitivity) {
|
|
ctx->mouse.x = width * ctx->mouse.sensitivity;
|
|
}
|
|
if (ctx->mouse.y < 0) {
|
|
ctx->mouse.y = 0;
|
|
} else if (ctx->mouse.y > height * ctx->mouse.sensitivity) {
|
|
ctx->mouse.y = height * ctx->mouse.sensitivity;
|
|
}
|
|
|
|
/* Get coordinates by rotation with sensitivity */
|
|
switch (lv_display_get_rotation(disp)) {
|
|
case LV_DISPLAY_ROTATION_0:
|
|
data->point.x = ctx->mouse.x / ctx->mouse.sensitivity;
|
|
data->point.y = ctx->mouse.y / ctx->mouse.sensitivity;
|
|
break;
|
|
case LV_DISPLAY_ROTATION_90:
|
|
data->point.y = width - ctx->mouse.x / ctx->mouse.sensitivity;
|
|
data->point.x = ctx->mouse.y / ctx->mouse.sensitivity;
|
|
break;
|
|
case LV_DISPLAY_ROTATION_180:
|
|
data->point.x = width - ctx->mouse.x / ctx->mouse.sensitivity;
|
|
data->point.y = height - ctx->mouse.y / ctx->mouse.sensitivity;
|
|
break;
|
|
case LV_DISPLAY_ROTATION_270:
|
|
data->point.y = ctx->mouse.x / ctx->mouse.sensitivity;
|
|
data->point.x = height - ctx->mouse.y / ctx->mouse.sensitivity;
|
|
break;
|
|
}
|
|
|
|
if (ctx->mouse.left_button) {
|
|
data->state = LV_INDEV_STATE_PRESSED;
|
|
} else {
|
|
data->state = LV_INDEV_STATE_RELEASED;
|
|
}
|
|
}
|
|
|
|
static void usbh_hid_lvgl_read_keyboard(lv_indev_t *indev_drv, lv_indev_data_t *data)
|
|
{
|
|
struct usbh_hid_lvgl *ctx = &g_hid_lvgl;
|
|
|
|
data->key = ctx->kb.last_key;
|
|
if (ctx->kb.pressed) {
|
|
data->state = LV_INDEV_STATE_PRESSED;
|
|
ctx->kb.pressed = false;
|
|
} else {
|
|
data->state = LV_INDEV_STATE_RELEASED;
|
|
ctx->kb.last_key = 0;
|
|
}
|
|
}
|
|
|
|
lv_indev_t *usbh_hid_lvgl_add_mouse(uint8_t sensitivity)
|
|
{
|
|
lv_indev_t *indev;
|
|
|
|
/* Initialize USB HID */
|
|
struct usbh_hid_lvgl *hid_ctx = &g_hid_lvgl;
|
|
|
|
/* Mouse sensitivity cannot be zero */
|
|
hid_ctx->mouse.sensitivity = (sensitivity == 0 ? 1 : sensitivity);
|
|
|
|
int32_t ver_res = lv_display_get_vertical_resolution(lv_display_get_default());
|
|
int32_t hor_res = lv_display_get_physical_horizontal_resolution(lv_display_get_default());
|
|
|
|
/* Default coordinates to screen center */
|
|
hid_ctx->mouse.x = (hor_res * hid_ctx->mouse.sensitivity) / 2;
|
|
hid_ctx->mouse.y = (ver_res * hid_ctx->mouse.sensitivity) / 2;
|
|
|
|
/* Register a mouse input device */
|
|
indev = lv_indev_create();
|
|
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
|
lv_indev_set_read_cb(indev, usbh_hid_lvgl_read_mouse);
|
|
lv_indev_set_driver_data(indev, hid_ctx);
|
|
hid_ctx->mouse.indev = indev;
|
|
|
|
/* Set image of cursor */
|
|
lv_obj_t *cursor;
|
|
cursor = lv_img_create(lv_scr_act());
|
|
lv_img_set_src(cursor, &img_cursor);
|
|
lv_indev_set_cursor(indev, cursor);
|
|
|
|
return indev;
|
|
}
|
|
|
|
lv_indev_t *usbh_hid_lvgl_add_keyboard(void)
|
|
{
|
|
lv_indev_t *indev;
|
|
|
|
/* Initialize USB HID */
|
|
struct usbh_hid_lvgl *hid_ctx = &g_hid_lvgl;
|
|
|
|
/* Register a keyboard input device */
|
|
indev = lv_indev_create();
|
|
lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
|
|
lv_indev_set_read_cb(indev, usbh_hid_lvgl_read_keyboard);
|
|
lv_indev_set_driver_data(indev, hid_ctx);
|
|
hid_ctx->kb.indev = indev;
|
|
|
|
return indev;
|
|
}
|
|
|
|
void usbh_hid_mouse_callback(void *arg, int nbytes)
|
|
{
|
|
struct usbh_hid *hid_class = (struct usbh_hid *)arg;
|
|
|
|
if (nbytes > 0) {
|
|
struct usbh_hid_lvgl *hid_ctx = &g_hid_lvgl;
|
|
|
|
hid_ctx->mouse.left_button = hid_mouse_buffer[0];
|
|
hid_ctx->mouse.x += (int8_t)hid_mouse_buffer[1];
|
|
hid_ctx->mouse.y += (int8_t)hid_mouse_buffer[2];
|
|
|
|
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_mouse_buffer, hid_class->intin->wMaxPacketSize, 0,
|
|
usbh_hid_mouse_callback, hid_class);
|
|
usbh_submit_urb(&hid_class->intin_urb);
|
|
} else if (nbytes == -USB_ERR_NAK) { /* only dwc2 should do this */
|
|
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_mouse_buffer, hid_class->intin->wMaxPacketSize, 0,
|
|
usbh_hid_mouse_callback, hid_class);
|
|
usbh_submit_urb(&hid_class->intin_urb);
|
|
} else {
|
|
}
|
|
}
|
|
|
|
static char usb_hid_get_keyboard_char(uint8_t key, uint8_t shift)
|
|
{
|
|
char ret_key = 0;
|
|
|
|
const uint8_t keycode2ascii [57][2] = {
|
|
{0, 0}, /* HID_KEY_NO_PRESS */
|
|
{0, 0}, /* HID_KEY_ROLLOVER */
|
|
{0, 0}, /* HID_KEY_POST_FAIL */
|
|
{0, 0}, /* HID_KEY_ERROR_UNDEFINED */
|
|
{'a', 'A'}, /* HID_KEY_A */
|
|
{'b', 'B'}, /* HID_KEY_B */
|
|
{'c', 'C'}, /* HID_KEY_C */
|
|
{'d', 'D'}, /* HID_KEY_D */
|
|
{'e', 'E'}, /* HID_KEY_E */
|
|
{'f', 'F'}, /* HID_KEY_F */
|
|
{'g', 'G'}, /* HID_KEY_G */
|
|
{'h', 'H'}, /* HID_KEY_H */
|
|
{'i', 'I'}, /* HID_KEY_I */
|
|
{'j', 'J'}, /* HID_KEY_J */
|
|
{'k', 'K'}, /* HID_KEY_K */
|
|
{'l', 'L'}, /* HID_KEY_L */
|
|
{'m', 'M'}, /* HID_KEY_M */
|
|
{'n', 'N'}, /* HID_KEY_N */
|
|
{'o', 'O'}, /* HID_KEY_O */
|
|
{'p', 'P'}, /* HID_KEY_P */
|
|
{'q', 'Q'}, /* HID_KEY_Q */
|
|
{'r', 'R'}, /* HID_KEY_R */
|
|
{'s', 'S'}, /* HID_KEY_S */
|
|
{'t', 'T'}, /* HID_KEY_T */
|
|
{'u', 'U'}, /* HID_KEY_U */
|
|
{'v', 'V'}, /* HID_KEY_V */
|
|
{'w', 'W'}, /* HID_KEY_W */
|
|
{'x', 'X'}, /* HID_KEY_X */
|
|
{'y', 'Y'}, /* HID_KEY_Y */
|
|
{'z', 'Z'}, /* HID_KEY_Z */
|
|
{'1', '!'}, /* HID_KEY_1 */
|
|
{'2', '@'}, /* HID_KEY_2 */
|
|
{'3', '#'}, /* HID_KEY_3 */
|
|
{'4', '$'}, /* HID_KEY_4 */
|
|
{'5', '%'}, /* HID_KEY_5 */
|
|
{'6', '^'}, /* HID_KEY_6 */
|
|
{'7', '&'}, /* HID_KEY_7 */
|
|
{'8', '*'}, /* HID_KEY_8 */
|
|
{'9', '('}, /* HID_KEY_9 */
|
|
{'0', ')'}, /* HID_KEY_0 */
|
|
{'\r', '\r'}, /* HID_KEY_ENTER */
|
|
{0, 0}, /* HID_KEY_ESC */
|
|
{'\b', 0}, /* HID_KEY_DEL */
|
|
{0, 0}, /* HID_KEY_TAB */
|
|
{' ', ' '}, /* HID_KEY_SPACE */
|
|
{'-', '_'}, /* HID_KEY_MINUS */
|
|
{'=', '+'}, /* HID_KEY_EQUAL */
|
|
{'[', '{'}, /* HID_KEY_OPEN_BRACKET */
|
|
{']', '}'}, /* HID_KEY_CLOSE_BRACKET */
|
|
{'\\', '|'}, /* HID_KEY_BACK_SLASH */
|
|
{'\\', '|'}, /* HID_KEY_SHARP */ // HOTFIX: for NonUS Keyboards repeat HID_KEY_BACK_SLASH
|
|
{';', ':'}, /* HID_KEY_COLON */
|
|
{'\'', '"'}, /* HID_KEY_QUOTE */
|
|
{'`', '~'}, /* HID_KEY_TILDE */
|
|
{',', '<'}, /* HID_KEY_LESS */
|
|
{'.', '>'}, /* HID_KEY_GREATER */
|
|
{'/', '?'} /* HID_KEY_SLASH */
|
|
};
|
|
|
|
if (shift > 1) {
|
|
shift = 1;
|
|
}
|
|
|
|
if ((key >= HID_KBD_USAGE_A) && (key <= HID_KBD_USAGE_QUESTION)) {
|
|
ret_key = keycode2ascii[key][shift];
|
|
}
|
|
|
|
return ret_key;
|
|
}
|
|
|
|
void usbh_hid_keyboard_callback(void *arg, int nbytes)
|
|
{
|
|
struct usbh_hid *hid_class = (struct usbh_hid *)arg;
|
|
|
|
if (nbytes > 0) {
|
|
struct usbh_hid_lvgl *hid_ctx = &g_hid_lvgl;
|
|
struct usb_hid_kbd_report *keyboard = (struct usb_hid_kbd_report *)hid_keyboard_buffer;
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
if (keyboard->key[i] > HID_KBD_USAGE_MAX) {
|
|
char key = 0;
|
|
|
|
/* LVGL special keys */
|
|
if (keyboard->key[i] == HID_KBD_USAGE_TAB) {
|
|
if (((keyboard->modifier & HID_MODIFER_LSHIFT) || (keyboard->modifier & HID_MODIFER_RSHIFT))) {
|
|
key = LV_KEY_PREV;
|
|
} else {
|
|
key = LV_KEY_NEXT;
|
|
}
|
|
} else if (keyboard->key[i] == HID_KBD_USAGE_RIGHT) {
|
|
key = LV_KEY_RIGHT;
|
|
} else if (keyboard->key[i] == HID_KBD_USAGE_LEFT) {
|
|
key = LV_KEY_LEFT;
|
|
} else if (keyboard->key[i] == HID_KBD_USAGE_DOWN) {
|
|
key = LV_KEY_DOWN;
|
|
} else if (keyboard->key[i] == HID_KBD_USAGE_UP) {
|
|
key = LV_KEY_UP;
|
|
} else if (keyboard->key[i] == HID_KBD_USAGE_ENTER || keyboard->key[i] == HID_KBD_USAGE_KPDEMTER) {
|
|
key = LV_KEY_ENTER;
|
|
} else if (keyboard->key[i] == HID_KBD_USAGE_DELETE) {
|
|
key = LV_KEY_DEL;
|
|
} else if (keyboard->key[i] == HID_KBD_USAGE_HOME) {
|
|
key = LV_KEY_HOME;
|
|
} else if (keyboard->key[i] == HID_KBD_USAGE_END) {
|
|
key = LV_KEY_END;
|
|
} else {
|
|
/* Get ASCII char */
|
|
key = usb_hid_get_keyboard_char(keyboard->key[i], ((keyboard->modifier & HID_MODIFER_LSHIFT) || (keyboard->modifier & HID_MODIFER_RSHIFT)));
|
|
}
|
|
|
|
if (key == 0) {
|
|
USB_LOG_ERR("Not recognized key: %c (%d)\r\n", keyboard->key[i], keyboard->key[i]);
|
|
}
|
|
hid_ctx->kb.last_key = key;
|
|
hid_ctx->kb.pressed = true;
|
|
}
|
|
}
|
|
|
|
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_keyboard_buffer, hid_class->intin->wMaxPacketSize, 0,
|
|
usbh_hid_mouse_callback, hid_class);
|
|
usbh_submit_urb(&hid_class->intin_urb);
|
|
} else if (nbytes == -USB_ERR_NAK) { /* only dwc2 should do this */
|
|
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_keyboard_buffer, hid_class->intin->wMaxPacketSize, 0,
|
|
usbh_hid_mouse_callback, hid_class);
|
|
usbh_submit_urb(&hid_class->intin_urb);
|
|
} else {
|
|
}
|
|
}
|
|
|
|
void usbh_hid_run(struct usbh_hid *hid_class)
|
|
{
|
|
if (hid_class->hport->config.intf[hid_class->intf].altsetting[0].intf_desc.bInterfaceProtocol == HID_PROTOCOL_KEYBOARD) {
|
|
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_keyboard_buffer, hid_class->intin->wMaxPacketSize, 0,
|
|
usbh_hid_keyboard_callback, hid_class);
|
|
usbh_submit_urb(&hid_class->intin_urb);
|
|
} else if (hid_class->hport->config.intf[hid_class->intf].altsetting[0].intf_desc.bInterfaceProtocol == HID_PROTOCOL_MOUSE) {
|
|
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_mouse_buffer, hid_class->intin->wMaxPacketSize, 0,
|
|
usbh_hid_mouse_callback, hid_class);
|
|
usbh_submit_urb(&hid_class->intin_urb);
|
|
} else {
|
|
}
|
|
}
|
|
|
|
void usbh_hid_stop(struct usbh_hid *hid_class)
|
|
{
|
|
} |