通过蓝牙HID上传鼠标,键盘,按键的事件基本已经比较成熟。并且功能比较好实现,基本参照网络上的配置都可以弄出来。但多点触摸功能却怎么弄都没有满意的结果。搜罗了网上的很多报告描述符的描写,试验了一段时间,竟然没有一个可以使用,高度怀疑自己是哪个地方出现了问题。那就只有深挖下去,看看到底卡在哪个地方。
内核的drivers\hid\hid-core.c代码中,有一个
hid_scan_main --> hid_scan_input_usage,该函数对如何识别一个多点触控设备做了判断:
static void hid_scan_input_usage(struct hid_parser *parser, u32 usage)
{
struct hid_device *hid = parser->device;
if (usage == HID_DG_CONTACTID)
hid->group = HID_GROUP_MULTITOUCH;
}
从中可以看出,如果report中有usage为HID_DG_CONTACTID,即判断为多点触摸的设备,会加载多点触摸的hid相关驱动,也就是linux内核中drivers\hid\hid-multitouch.c代码,该代码对HID的多点触摸设备进行了相关的转换,以适应android系统上报正确的多点触摸input事件。
通过宏定义#define HID_DG_CONTACTID 0x000d0051 可以看见,这个usage的Usage ID是0x51,而多点触摸属于一个Digitizers Page范畴的设备。所以可以查看HID Usage Tables FOR Universal Serial Bus (USB)文档(可访问USB官网下载HID Usage Tables 1.4 | USB-IF)。
也就是report中一定要包含该usage(0x09, 0x51),才能被识别为一个多点触摸的设备。
但是即使把这个usage包含进去了,也做好了各种准备,结果却仍然无法查看到上传的多点触摸结果。(通过getevent无法查看到正确的多点触摸信息。)
连接蓝牙,android设备进入adb之后,
查看/sys/bus/hid/devices,发现里面有注册好并且可以使用的HID设备,比如0005:05AC:022C.0001,,进入/sys/bus/hid/devices/0005:05AC:022C.0001/driver,执行ls -la,
可以发现该设备是通过uhid虚拟出来的一个hid设备。并且用到了hid_apple的驱动。如下图所示:
查看/sys/bus/hid/drivers,可以发现里面有一些hid的驱动。
cd apple可看见0005:05AC:022C.0002(最后一个0002只是表示连接次数,中途断了一下,重连,就变为0002,可以忽略。)说明用到了apple的驱动。
翻开内核代码,进入drivers\hid\hid-apple.c,会发现
static const struct hid_device_id apple_devices[]中有很多供应商和设备ID,
通过查看,
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c
说明0005:05AC:022C.0002,这个设备确实是用到了hid-apple的驱动。查看该驱动,发现都是一些按键和鼠标的定义,并未找到多点触摸的相关处理过程。
也就是HID用什么设备,都是通过05AC:022C这些厂商ID和设备ID定义好的。如果想即连即用,不想自己写驱动。需要选择好这两个ID。
查看drivers\hid\hid-multitouch.c,该驱动才是多点触摸蓝牙或者USBHID设备需要匹配的驱动。
在其代码中,也可以找到static const struct hid_device_id mt_devices[]结构体数组,里面定义了支持该驱动的设备ID和厂商ID。也就是说只有厂商ID和设备ID都在这个数组里面的设备,才能支持多点触摸的功能。那么怎么找到这两个ID呢?
在android上面安装一个nRF.Connect.apk,连接上蓝牙,在设备信息中查看,如下图:
滑到最下面,有一个PnP ID,点击向下的箭头,读取一下。
厂商ID和设备ID就在这里,556写成16进制就是0x22c。
也就是PnP ID是确定HID设备使用什么驱动的识别信息。
那么就需要去更改蓝牙芯片的代码,找到这个东西,修改为能够使用多点触摸驱动的PnP ID。
比如杰理的芯片,在apps\hid\modules\bt\ble_hogp.c中,可以发现有如下的信息:
把PNP_VID,PNP_PIN修改一下即可。其他的芯片也应该可以找到对应的地方做修改。
比如hid-multitouch.c中,用通用的设备ID看看效果如何,当然其他的ID也是可以的。这里仅做一下展示。
/* Generic MT device */
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
HID_BUS_ANY是0xffff,HID_ANY_ID只要非0即可。
修改完之后,再打开蓝牙,这时通过nRF.Connect.apk,发现PnP ID已经改变了。
adb查看/sys/bus/hid/devices
查看/sys/bus/hid/drivers/hid-multitouch
说明是已经用到了hid-multitouch的驱动。
adb 通过getevent -lt,然后蓝牙上传一个滑动的数据包,可以看见:
也就是滑动的事件已经通过input子系统上传到了应用层,并滑动的屏幕。这里只展示了1个点的滑动,多点也是可以实现的。不再展开。