USB鼠标通信协议

发布时间 2023-07-26 16:24:43作者: JaydenHuan

USBS鼠标通信协议

用手中的STM32开发板实现一个USB鼠标的点击过程。
模拟鼠标左右键按键的操作过程,大致开发思路是按键读取数据,数据触发指定的鼠标上报事件,完成鼠标的左右
键操作。
鼠标发送给PC的数据每次4个字节

BYTE1 BYTE2 BYTE3 BYTE4
每个字节都有八位数据表示一个事件
定义分别是:
bit0: 1 表示左键按下,
bit1: 1 表示右键按下,
bit2: 1 表示中键按下,
bit3: 1 恒为1
bit4: x 坐标变化的符号位,1表示负数,鼠标左移动
bit5: y 坐标变化的符号位,1表示负数,鼠标向下移动
bit6: 1 表示x 坐标的变化量超出 -256 ~ 255 的范围,0表示没有溢出
bit7: 1 表示y坐标的变化量超出 -256 ~ 255 的范围,0表示没有溢出

如何定位对应的事件?

通过HID设备报告的描述符决定的,市面上的鼠标报告描述符基本都一样。具体的在usbd_hid.c的文件夹下有个数组
static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE],就是报告描述符。这个数组告诉PC机
去解析HID设备上报的数据。整个描述符内容就是描述了类似下面的一个结构体。

typedef struct
{
    char mouse_abs_left : 1;    //鼠标左键
    char mouse_abs_right : 1;   //鼠标右键
    char mouse_abs_wheel : 1;   //鼠标中键
    char reserve : 5;   //常量0
    char mouse_rel_x;    //鼠标x轴移动值
    char mouse_rel_y;    //鼠标y轴移动值
    char mouse_rel_wheel;  //鼠标滚轮移动值
}tMouse_buff;

USB鼠标报告描述符,描述了4个字节,第一个字节表示按键,第二个字节表示x轴(既鼠标左右移动,0表示不动,正值表示往右边移动
,负值表示往左边移动) ,第三个字节表示y轴,第四个表示鼠标滚轮。

//
    // Dummy mouse collection starts here
    //
    0x05, 0x01,                         // USAGE_PAGE (Generic Desktop)     0
    0x09, 0x02,                         // USAGE (Mouse)                    2
    0xa1, 0x01,                         // COLLECTION (Application)         4
    0x85, REPORTID_MOUSE,               //   REPORT_ID (Mouse)              6
    0x09, 0x01,                         //   USAGE (Pointer)                8
    0xa1, 0x00,                         //   COLLECTION (Physical)          10
    0x05, 0x09,                         //     USAGE_PAGE (Button)          12
    0x19, 0x01,                         //     USAGE_MINIMUM (Button 1)     14
    0x29, 0x02,                         //     USAGE_MAXIMUM (Button 2)     16
    0x15, 0x00,                         //     LOGICAL_MINIMUM (0)          18
    0x25, 0x01,                         //     LOGICAL_MAXIMUM (1)          20
    0x75, 0x01,                         //     REPORT_SIZE (1)              22
    0x95, 0x02,                         //     REPORT_COUNT (2)             24
    0x81, 0x02,                         //     INPUT (Data,Var,Abs)         26
    0x95, 0x06,                         //     REPORT_COUNT (6)             28
    0x81, 0x03,                         //     INPUT (Cnst,Var,Abs)         30
    0x05, 0x01,                         //     USAGE_PAGE (Generic Desktop) 32
    0x09, 0x30,                         //     USAGE (X)                    34
    0x09, 0x31,                         //     USAGE (Y)                    36
    0x15, 0x81,                         //     LOGICAL_MINIMUM (-127)       38
    0x25, 0x7f,                         //     LOGICAL_MAXIMUM (127)        40
    0x75, 0x08,                         //     REPORT_SIZE (8)              42
    0x95, 0x02,                         //     REPORT_COUNT (2)             44
    0x81, 0x06,                         //     INPUT (Data,Var,Rel)         46
    0xc0,                               //   END_COLLECTION                 48
    0xc0                                // END_COLLECTION                   49/50


通过对上面的集合报告,如果鼠标左键按下就是0x01,如果是右键按下就是0x02。
因此可以可以设定一个数组,然后根据事件上报,来调用就行了。


uint8_t MouseData1[4] = {0,0,0,0};

//然后在主函数中使用按键读取信息,在触发鼠标上报事件,从而
//达到模拟鼠标左右键按下的过程

//读取Key的按键值
unsigned char Get_key_num(void)
{
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0)
	{
		HAL_Delay(20); //按键消抖操作
		while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0);
		HAL_Delay(20);
		keyNum = 1;
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11)==0)
	{
		HAL_Delay(20);
		while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11)==0);
		HAL_Delay(20);
		keyNum = 2;
	}

	return keyNum;
}

int main(void)
{
  
  //unsigned char keyNumLast;
  //int cnt;
  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  keyNum = Get_key_num();
    if(keyNum == 1)
	{
		MouseData1[0] = 0x02; //鼠标右键按下
		USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&MouseData1,sizeof(MouseData1));
	}
    if(keyNum == 2)
	{
		MouseData1[0]=0x01; //鼠标左键按下
	   USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&MouseData1,sizeof(MouseData1));
	}
  }
  
}


项目效果

按下按键就能达到鼠标右键,左键触发效果。

右键效果

参考来源

微软硬件参考文档

项目地址

Usb_key项目demo