案例链接:https://pan.baidu.com/s/1VkIOEwwE6XS_zM-YsoTYKw?pwd=s5of
提取码:s5of
通信逻辑:当你插上游戏手柄的时候,它就会一包一包数据往电脑上发,只是我们没有合适的接收处理,所以看不出来,它类似与UDP的报文,只管发,它一包的数据长度是固定的,逻辑类似每个按键控制数据包中的一个位置的值的变化,我们用的就是通过判断按键对应的那个位置的值的变化来处理按键的功能
难点一:要明白:作为一个新手没处理过这种HID数据处理的开发者来说,首先要做的就是先连通能收到数据再说,至于硬件啊,协议啊什么的,完全不需要去关心
难点二:从网上找资料,下载C语言的实现的接口文件,但是下载绑定能恶心死人
难点三:文件找到了,怎么用,怎么个包含关系,网上的demo代码没注释,看的是一脸懵逼说不准抄的什么地方出了问题就崩了
解决办法:
第一步:将下载下来的头文件/源文件跟自己的代码放到一个文件夹里,就当它是自己写的一个类;可以直接扫码从我的网盘中下载接口文件
第二步:进行具体的代码书写,内容以及解释看以下代码块:
//需要包含的头文件
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include "hidapi.h"
//包含库
#ifdef _WIN32
#pragma comment (lib,"setupapi.lib")
#endif
//需要用到sleep,根据Windows和linux系统包含不同的头文件
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
int main(int argc, char *argv[])
{
//定义容器,用来存放各种数据(例如:从usb发到本机的数据)
unsigned char buf[256];
memset(buf,0x00,sizeof(buf));
//HID设备的句柄
hid_device *handle;
//循环查找本地的设备数,以及每个设备的信息
//后续开发需要用到设备的VID,PID,作为识别设备的参数
//devInfo备用指针用来遍历查找本地的设备
//注:VID,PID,可以通过查看本地信息直接输入具体值,也可以代码查找,找到了,进行赋值
//建议代码扫设备(遇到过一包数据数据是27个字节来代表不同的按键,插拔了一次变成了9个字节代表按键,本地VID,PID信息的值也变了)
struct hid_device_info *devInfo;
//设备容器,存放找到的设备信息
struct hid_device_info* devArray[10];
memset(devArray,0,10);
//用来表示设备容器devArray[10]的下标
int devArrayIndex=0;
//指针初始化,初始化成功代表存在
devInfo = hid_enumerate(0x0, 0x0);
while (devInfo) {
devArray[devArrayIndex++]=devInfo;//将找到的设备交给容器记录
printf("Device Found:\n");
printf("VID:%04hx\n",devInfo->vendor_id);//
printf("PID:%04hx\n",devInfo->product_id);
printf("\n");
//通过next来寻找是否存在下一个设备
//注:只有一个设备的时候,可以注掉这句代码
// 如果有多个设备,记得定义多个指针来接收设备信息
devInfo = devInfo->next;
}
hid_free_enumeration(devInfo);//删除最后一个没找到设备的指针
//调试信息:循环遍历显示所有找到的设备信息(开发只用VID,PID信息,因此只显示这俩值)
int index=0;
while (devArray[index]) {
printf("dev%d:VID:%04hx\n",index,devArray[index]->vendor_id);
printf("dev%d:PID:%04hx\n",index,devArray[index]->product_id);
index++;
}
//打开USB句柄
handle = hid_open(devArray[0]->vendor_id,devArray[0]->product_id , NULL);
if (!handle) { //判断是否连接(打开)成功
printf("unable to open device\n");
}
//开始接收数据
printf("Start Data read:\n");
while (true) {
//res是实际收到的字节数,65是预留的长度
//如果知道会收到一包数据的固定长度,65可以预设
//hid_read是读取数据,存放到buf中,无限时的等待,直到收到数据为止
//hid_read_timeout()中的第四个参数可以设置超时,不管有没有收到数据,都退出
int res=hid_read_timeout(handle, buf, 65,100);//100是超时设置,毫秒
//调试信息:输出显示收到的数据
for (i = 0; i < res; i++)
printf("%03d ", buf[i]);
printf("\n");
//休眠时间可以根据具体情况设,但是不能没有,没有sleep容易导致主线程来不及处理导致界面卡死
Sleep(100);
}
//资源回收(指针回收)
hid_close(handle);
hid_exit();
index=0;
while (devArray[index]) {
hid_free_enumeration(devArray[index]);
index++;
}
return 0;
}
第三步:使用过程中应该是线程里接收数据进行处理,然后将数据交给主线程使用;因此,等知道代码的每一步的意思后就得靠自己进行具体的代码结构设计和开发了;
注:测试过程中遇到过同一个手柄,同一个主机,在一次插拔后,设备的VID,PID的值变了,收的包的数据长度变了,好在我使用的数据的位置没变,没造成大的影响,但是不知道发生的原因(如果有知道的请留言告知,感激不尽);
因此,再次建议开发时尽量通过代码来扫描查找设备PID,VID等参数值,后期能省事很多;