USB鼠标通信协议
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));
}
}
}
项目效果
按下按键就能达到鼠标右键,左键触发效果。
右键效果
参考来源
项目地址
每个不曾起舞的日子,都是对生命的辜负。