对hidraw进行多点触摸分析

发现如果系统支持多点触摸的话,直接像内核文档这样上报是没问题的
但如果是拿了一个不支持多点的系统,还需要模拟出多点的效果

比如说上面这样,手动画一条,机器模拟一条的话,逻辑什么的都需要改改

官方文档

分析input event的数据

多点按下

多点发送是 开始先单点发送的指令 +另一个点

0003 D047 00000001  //好像代表手指1
0003 D057 00000001  //应该是对1手指的追踪
0003 D053 000020a1
0003 D054 00005a44
多点移动
/dev/input/event0: 0003 D047 00000000
/dev/input/event0: 0003 D053 0000425b
/dev/input/event0: 0003 D054 000033fa
/dev/input/event0: 0003 0000 0000425b
/dev/input/event0: 0003 0001 000033fa
/dev/input/event0: 0000 0000 00000000
多点结束
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 D057 ffffffff
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 D047 00000000
/dev/input/event0: 0003 D053 00003f3b
/dev/input/event0: 0003 D054 000026d2
/dev/input/event0: 0003 0000 00003f3b
/dev/input/event0: 0003 0001 000026d2
/dev/input/event0: 0000 0000 00000000

这些就不做什么解释了,很多地方都有,或者对应着内核文档里,命令进行查看就能知道里面的意思

不支持多点触摸的设备模拟多点信息

问题发现

如果我们用hidraw构造出数据,再用getevnt进行上报,那么会有大量重复的数据,比如下面这样
没想到hidraw的原生数据会是 hexdump的 16倍

原因1: 当x,y不变的时候,hidraw的伪造数据会持续上报,就会有这么多的重复数据
原因2: 其实如果吧上面下面三组数据一点点挑出来分析,会发现并不是像官方的文档描述的这样,啊,你用我的命令就好了啊

抓了三天头发后

如果是两根手指的触摸,应该会有下面这样的流程


我们只要把上报数据根据这样的格式进行上报

现在模仿出来的数据就很正常,接下来放一下代码

为什么点1拿了点0的数据 1有四个数据的时候,就会拿两个0的数据

代码

/********************************************************************************* @file    analyze_data.c* @author  duck* @version V1.6.0* @date    13-08-2021* @brief   该文件用于分析hidraw触摸点的down/up数据,以及能统计丢up率******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,能进行5点及五点以下的统计,测试中功能* 优异,随便舞动手指也不会出错*******************************************************************************/#include "analyze_data.h"/** @fun_name     : -my_split* @description  : 把原始数据存入数组里* @param - filp    : 获取的hidraw原生数据(字符串指针)* @return            : 返回分割好的数据放入一个数组里*/
unsigned int *analyze_split(char *str_data ,unsigned int * split_analyze_data) //把原始数据存入数组里
{char *split = " ";char *p;p = strtok(str_data, split);split_analyze_data[0] = (unsigned int)(atoi(p));int split_i = 1;for (split_i = 1; split_i < 40; split_i++){p = strtok(NULL, split);split_analyze_data[split_i] = (unsigned int)(atoi(p));}return split_analyze_data;
}/** @fun_name     : create_now_analyze_point* @description   : 构造出5个触摸点,并且进行赋值* @param - filp   : 获取的hidraw原生数据(hidraw分割好的数组)* @return             : NULL*/
void create_now_analyze_point(unsigned int *split ,struct analyze_all_point* p_now_analyze_point)
{int count;for (count = 0; count < 5; count++){p_now_analyze_point->touch[split[4 + 6 * count]].x_location = split[5 + 6 * count] + split[6 + 6 * count] * 256;p_now_analyze_point->touch[split[4 + 6 * count]].y_location = split[7 + 6 * count] + split[8 + 6 * count] * 256;p_now_analyze_point->touch[split[4 + 6 * count]].point_id = split[4 + 6 * count];p_now_analyze_point->touch[split[4 + 6 * count]].touch_info = split[3 + 6 * count];}p_now_analyze_point->sec = split[0];p_now_analyze_point->usec = split[1];p_now_analyze_point->point_count = split[39];
}/** @fun_name                         : creat_report* @description                       : 根据触摸点构造出触摸事件* @param - all_point now_analyze_point   : 当前触摸点数据* @param - all_point pre_analyze_point    : 之前触摸点数据(进行对比)* @param - report_event all_event[]     : 构造的5个触摸事件* @return                               : NULL*/
void creat_report(struct analyze_all_point now_analyze_point, struct analyze_all_point pre_analyze_point)
{int i;for (i = 0; i < 5; i++){//判断point_stateif (pre_analyze_point.touch[i].touch_info == 0 && now_analyze_point.touch[i].touch_info == 4)record_data[i * 2] += 1; //表示按下if (pre_analyze_point.touch[i].touch_info == 7 && now_analyze_point.touch[i].touch_info == 4)record_data[i * 2 + 1] += 1; //表示抬起if (pre_analyze_point.touch[i].touch_info == 4 && now_analyze_point.touch[i].touch_info == 4)record_data[i * 2] += 1; //表示按下}
}/** @fun_name                         : analyze_report* @description                         : 分析上报数据,对已知的down/up进行统计* @param                               : NULL  * @return                              : NULL*/
void analyze_report()
{int the_num_of_up = 0;int the_num_of_down = 0;int i;for (i = 0; i < 5; i++){printf("the point %d down %d up %d\n", i, record_data[i * 2], record_data[i * 2 + 1]);the_num_of_down += record_data[i * 2];the_num_of_up += record_data[i * 2 + 1];}float loss_rate = (float)(the_num_of_up * 100 / the_num_of_down) / 100;int count = loss_rate * 100;printf("the sucess rate  is %d%\n", count);
}/** @fun_name                         : init_all_point* @description                         : 对原始点触摸数据进行初始化赋值,好产生对照组* @param - pre_analyze_point               : 当前触摸点数据* @return                                 : NULL*/void init_all_point(struct analyze_all_point* p_pre_analyze_point)
{p_pre_analyze_point->sec = 0;p_pre_analyze_point->usec = 0;int i;for (i = 0; i < 5; i++){p_pre_analyze_point->touch[i].touch_info = 0;p_pre_analyze_point->touch[i].x_location = 0;p_pre_analyze_point->touch[i].y_location = 0;p_pre_analyze_point->touch[i].point_id = 0;}
}/** @fun_name                         : analyze_data* @description                       : 分析上报数据,对原生hidraw数据进行清洗,重新分析统计* @param                                : NULL* @return                                : NULL*/
int analyze_data()
{FILE *fp;char str[N + 1];unsigned int *split;unsigned int split_analyze_data[50]={0};struct analyze_all_point now_analyze_point;struct analyze_all_point pre_analyze_point;printf("i am running\n");if ((fp = fopen("./1.txt", "rt")) == NULL){puts("Fail to open file!");exit(0);}// 开始拿数据init_all_point(&pre_analyze_point);while (fgets(str, N, fp) != NULL){split = analyze_split(str,split_analyze_data);create_now_analyze_point(split ,&now_analyze_point);creat_report(now_analyze_point, pre_analyze_point);pre_analyze_point = now_analyze_point;}analyze_report();fclose(fp);sleep(5);return 0;
}
/******************************************************************************** @file    cartoon.c* @author  duck* @version V1.7.0* @date    16-08-2021* @brief   由于在树莓派的系统实现不了多点触摸,但为了证明作者逻辑还算正确,所以作者用*          控制台的形式,来进行多点触摸的划线           ******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,现在能进行两点触摸的复现,对于两点以上* 还有一丝逻辑没有理清, 复现的不准确来自于和input子系统判断的时间戳不同*****/#include "cartoon.h"/** @fun_name          : -change_buffer* @description         : 更新我们的buff,构造最先的点阵* @param -x_location    : 更新点的x坐标* @param -y_location  : 更新点多y坐标* @return                 : 返回0成功*/
void change_buffer(int x_location, int y_location)
{cartoon_buffer[y_location][x_location] = 1;
}/** @fun_name         : -cartoon_report* @description        : 判断这次上报的方式,决定如何打点* @param -all_event  : 全部的触发事件* @param -point_count : 全部的手指头* @return              : 返回0成功*/
void cartoon_report(struct report_event all_event[5], int point_count)
{int count;int count_effective = 5;for (count = 0; count < 5; count++){if (all_event[count].effective == -1){count_effective--;if (all_event[count].point_state == 1 || all_event[count].point_state == 0)count_effective++;}}if (count_effective == 1){for (count = 0; count < 5; count++){if (all_event[count].point_state == -1)continue;if (all_event[count].effective == -1 && all_event[count].point_state != 1 && all_event[count].point_state != 0)continue;//如果是抬起if (all_event[count].point_state == 1){if (point_count == 1) //唯一的手指抬起{                   //通过真实存在判断只有一个点continue;}else //一个手指不动,另一个抬起{continue;}}//刚刚按下if (all_event[count].point_state == 0){if (point_count == 1) //唯一的手指按下{change_buffer(all_event[count].x_location / 24, all_event[count].y_location / 24);}else //一个手指不动,另一个按下{change_buffer(all_event[count].x_location / 24, all_event[count].y_location / 24); //同步一下事件}}//保持按下if (all_event[count].point_state == 2){if (point_count == 1) //唯一的手指滑动{change_buffer(all_event[count].x_location / 24, all_event[count].y_location / 24);}else //一个手指不动,另一个滑动{change_buffer(all_event[count].x_location / 24, all_event[count].y_location / 24);}}}}if (count_effective > 1){ //这时候就是多点按下了for (count = 0; count < 5; count++){if (all_event[count].point_state == -1)continue;if (all_event[count].effective == -1 && all_event[count].point_state != 1 && all_event[count].point_state != 0)continue;//如果是抬起if (all_event[count].point_state == 1){continue;}//多点按下if (all_event[count].point_state == 0){change_buffer(all_event[count].x_location / 24, all_event[count].y_location / 24);}//多点滑动if (all_event[count].point_state == 2){if (count == 0) //构造出touch1的多点触摸上报事件{change_buffer(all_event[count].x_location / 24, all_event[count].y_location / 24);}else{change_buffer(all_event[count].x_location / 24, all_event[count].y_location / 24); //同步一下事件}}}}
}/** @fun_name         : -frame_buffer* @description      : 根据buff进行画点* @return              : 返回0成功*/
int frame_buffer()
{int x, y;for (y = 0; y < LINE; y++){for (x = 0; x < ROW; x++){if (cartoon_buffer[y][x] == 0){printf("**");}else{printf("  ");}}putchar('\n');}return 0;
}/** @fun_name         : -show_cartoon* @description      : 根据buff进行画点* @return              : 返回0成功*/
int show_cartoon()
{int ts;int us;FILE *fp_data;int start = 0; //开始运行定义char str[N + 1];unsigned int *split;unsigned int split_data[50] = {0}; //单次获取数据数组struct report_event all_event[5];struct all_point now_all_point; //本次数据的整理struct all_point pre_all_point; //上次数据的整理if ((fp_data = fopen("./1.txt", "rt")) == NULL){puts("Fail to open file!");exit(0);}// 构建虚拟设备int ret = 0;ret = creat_user_uinput();if (ret < 0){printf("%s:%d\n", __func__, __LINE__);return -1; //error process.}sleep(5); // help you to 'hexdump -C /dev/input/event[X]' for test.//开始复现pre_all_point.sec = 0;pre_all_point.touch[0].touch_info = 0;while (fgets(str, N, fp_data) != NULL){split = my_split(str, split_data);//取出split的数据,构造出now_all_pointcreate_now_all_point(&now_all_point, split);//用now_all_point 和 pre_all_point对比,构造出eventcreat_report_event(now_all_point, pre_all_point, all_event);//获取延时时间ts = now_all_point.sec - pre_all_point.sec;us = now_all_point.usec - pre_all_point.usec;if (us < 0){us = (1000000 - pre_all_point.usec) + now_all_point.usec;ts -= 1;}if (ts < 0)ts = (1000000 - pre_all_point.sec) + now_all_point.sec;if (start == 0){ts = 0;us = 0;}start = 1;usleep(us);sleep(ts);//上报event1,上报event2cartoon_report(all_event, now_all_point.point_count);pre_all_point = now_all_point;frame_buffer();}//关闭文件fclose(fp_data);sleep(5);close(uinput_fd);return 0;
}
/********************************************************************************* @file    hidraw.c* @author  duck* @version V1.5.0* @date    12-08-2021* @brief   文件用来保存hidraw原生数据,在此基础上增加了时间戳,对数据保存在1.txt上*           为将来的复现数据基础做好准备******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,现在能进行两点触摸的复现,对于两点以上* 还有一丝逻辑没有理清, 复现的不准确来自于和input子系统判断的时间戳不同*******************************************************************************/#include "hid_raw.h"
#include "search_touch.h"/** @fun_name           : -hidraw_write* @description      : 把原始数据存1.txt里* @param - the_str   : 获取的hidraw原生数据(字符串指针)* @return                : 返回0成功*/
int hidraw_write(char * the_str)
{FILE* p = (fopen("./1.txt","a"));if(p ==NULL){printf("open error!\n");return -1;}fputs(the_str,p);free(the_str);fclose(p);return 0;
}/** @fun_name         : -hidraw_start* @description      : 把原始数据存1.txt里,并且在此基础上增加了时间戳* @param               : NULL* @return                : 返回0成功*/
int hidraw_start()
{struct hidraw_devinfo info;char *path_name = scan_devices();int fd = open(path_name, O_RDONLY);if (fd == -1){printf("touch device open fail\n");return -1;}printf("open the device is %s \n",path_name);free(path_name);int rc = ioctl(fd, HIDIOCGRAWINFO, &info);if (rc < 0){printf("readerror!\n");return 1;}printf("HID device info %04x:%04x:%04x is\n", info.bustype,info.vendor, info.product);unsigned char buff[96];printf("open successful\n");while (1){int i =0;int size = read(fd, buffer, 64);gettimeofday(&now_time, NULL);                  //获取当前时间char * save_time = (char *)malloc(200);        //保存时间数据sprintf(save_time,"%d %d ",now_time.tv_sec,now_time.tv_usec);hidraw_write(save_time);for (i = 0; i < size; ++i){char * save_data = (char *)malloc(200); //保存触摸数据sprintf(save_data,"%d ",buffer[i]);hidraw_write(save_data);}for (i = 0; i < size; ++i){printf("%d ", buffer[i]);}printf("\n");     char * save_data = (char *)malloc(200);        //保存触摸数据sprintf(save_data,"\n");hidraw_write(save_data);}return 0;
}
/******************************************************************************** @file    search_touch.h* @author  duck* @version V1.8.0* @date    18-08-2021* @brief   增加了自动识别触摸设备的功能,无论在哪个hidraw都能识别出来           ******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,现在能进行两点触摸的复现,对于两点以上* 还有一丝逻辑没有理清, 复现的不准确来自于和input子系统判断的时间戳不同*******************************************************************************/#include "search_touch.h"static int is_event_device(const struct dirent *dir)
{return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
}char *scan_devices(void)
{struct dirent **namelist;int i, ndev;char *filename = NULL;long propbit[BITS_TO_LONGS(INPUT_PROP_MAX)] = {0};ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, alphasort);if (ndev <= 0)return NULL;for (i = 0; i < ndev; i++) {char fname[512];int fd = -1;snprintf(fname, sizeof(fname),"%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);fd = open(fname, O_RDONLY);if (fd < 0)continue;if ((ioctl(fd, EVIOCGPROP(sizeof(propbit)), propbit) < 0) ||!(propbit[BIT_WORD(INPUT_PROP_DIRECT)] &BIT_MASK(INPUT_PROP_DIRECT))) {close(fd);continue;} else {close(fd);filename = malloc(strlen(DEV_INPUT_EVENT) +strlen(EVENT_DEV_NAME) +12);if (!filename)break;sprintf(filename, "%s%d","/dev/hidraw", i);break;}}for (i = 0; i < ndev; ++i)free(namelist[i]);free(namelist);return filename;
}
/********************************************************************************* @file    readraw.c* @author  duck* @version V1.5.0* @date    12-08-2021* @brief   文件提供了构造虚拟设备和复现数据的所有函数 ******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,现在能进行两点触摸的复现,对于两点以上* 还有一丝逻辑没有理清, 复现的不准确来自于和input子系统判断的时间戳不同*******************************************************************************/
#include "readraw.h"/** @fun_name        : -my_split* @description  : 把原始数据存入数组里* @param - filp    : 获取的hidraw原生数据(字符串指针)* @return            : 返回分割好的数据放入一个数组里*/
unsigned int *my_split(char *str_data ,unsigned int * split_data )
{char *split = " ";char *p;p = strtok(str_data, split);split_data[0] = (unsigned int)(atoi(p));int split_i = 1;for (split_i = 1; split_i < 40; split_i++){p = strtok(NULL, split);split_data[split_i] = (unsigned int)(atoi(p));}return split_data;
}/** @fun_name     : create_now_all_point* @description   : 构造出5个触摸点,并且进行赋值* @param - filp   : 获取的hidraw原生数据(hidraw分割好的数组)* @return             : NULL*/
void create_now_all_point(struct all_point *p_now_all_point, unsigned int *split)
{int count;for (count = 0; count < 5; count++){p_now_all_point->touch[split[4 + 6 * count]].x_location = split[5 + 6 * count] + split[6 + 6 * count] * 256;p_now_all_point->touch[split[4 + 6 * count]].y_location = split[7 + 6 * count] + split[8 + 6 * count] * 256;p_now_all_point->touch[split[4 + 6 * count]].point_id = split[4 + 6 * count];p_now_all_point->touch[split[4 + 6 * count]].touch_info = split[3 + 6 * count];}p_now_all_point->sec = split[0];p_now_all_point->usec = split[1];p_now_all_point->point_count = split[39];
}/** @fun_name                         : creat_report_event* @description                         : 根据触摸点构造出触摸事件* @param - all_point now_all_point   : 当前触摸点数据* @param - all_point pre_all_point    : 之前触摸点数据(进行对比)* @param - report_event all_event[]     : 构造的5个触摸事件* @return                               : NULL*/
void creat_report_event(struct all_point now_all_point, struct all_point pre_all_point, struct report_event all_event[5])
{//只有按下的时候才需要上报id,所以touch分配到哪一个event都没问题int i;for (i = 0; i < 5; i++){//判断point_stateif (pre_all_point.touch[i].touch_info == 0 && now_all_point.touch[i].touch_info == 4)all_event[i].point_state = 0; //表示按下if (pre_all_point.touch[i].touch_info == 4 && now_all_point.touch[i].touch_info == 4)all_event[i].point_state = 0; //表示按下if (pre_all_point.touch[i].touch_info == 7 && now_all_point.touch[i].touch_info == 4)all_event[i].point_state = 1; //表示抬起if (pre_all_point.touch[i].touch_info == 4 && now_all_point.touch[i].touch_info == 7)all_event[i].point_state = 2; //接着滑动if (pre_all_point.touch[i].touch_info == 7 && now_all_point.touch[i].touch_info == 7)all_event[i].point_state = 2; //按着滑动if (pre_all_point.touch[i].touch_info == 0 && now_all_point.touch[i].touch_info == 0)all_event[i].point_state = -1; //该触摸点没有启用if (pre_all_point.touch[i].touch_info == 4 && now_all_point.touch[i].touch_info == 0)all_event[i].point_state = -1; //该触摸点没有启用//分析x,y的位置all_event[i].x_location = now_all_point.touch[i].x_location * 1824 / 32767;all_event[i].y_location = now_all_point.touch[i].y_location * 984 / 32767;//判断这个点是否有效if (pre_all_point.touch[i].x_location == now_all_point.touch[i].x_location && pre_all_point.touch[i].y_location == now_all_point.touch[i].y_location)all_event[i].effective = -1;elseall_event[i].effective = 1;all_event[i].point_id = now_all_point.touch[i].point_id;}
}/** @fun_name                         : creat_user_uinput* @description                      : 对虚拟设备uinput创建成为触摸屏* @return                              : 成功返回0*/
int creat_user_uinput(void)
{int i;int ret = 0;uinput_fd = open("/dev/uinput", O_RDWR | O_NDELAY);if (uinput_fd < 0){printf("%s:%d\n", __func__, __LINE__);return -1; //error process.}//to set uinput devmemset(&uinput_dev, 0, sizeof(struct uinput_user_dev));snprintf(uinput_dev.name, UINPUT_MAX_NAME_SIZE, "uinput-custom-dev");uinput_dev.id.version = 1;uinput_dev.id.bustype = BUS_VIRTUAL;uinput_dev.id.bustype = BUS_USB;uinput_dev.absmin[ABS_MT_SLOT] = 0;uinput_dev.absmax[ABS_MT_SLOT] = 5; // MT代表multi touch 多指触摸 最大手指的数量我们设置5uinput_dev.absmin[ABS_MT_TOUCH_MAJOR] = 0;uinput_dev.absmax[ABS_MT_TOUCH_MAJOR] = 15;uinput_dev.absmin[ABS_MT_POSITION_X] = 0;      // 屏幕最小的X尺寸uinput_dev.absmax[ABS_MT_POSITION_X] = 32767; // 屏幕最大的X尺寸uinput_dev.absmin[ABS_MT_POSITION_Y] = 0;     // 屏幕最小的Y尺寸uinput_dev.absmax[ABS_MT_POSITION_Y] = 32767; //屏幕最大的Y尺寸uinput_dev.absmin[ABS_MT_TRACKING_ID] = 0;uinput_dev.absmin[ABS_MT_PRESSURE] = 0;uinput_dev.absmax[ABS_MT_PRESSURE] = 255; //屏幕按下的压力值// Touch   让ev =bioctl(uinput_fd, UI_SET_EVBIT, EV_ABS); //支持触摸ioctl(uinput_fd, UI_SET_EVBIT, EV_SYN);ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY);//调整ABS 为2608000 3ioctl(uinput_fd, UI_SET_ABSBIT, ABS_X);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_Y);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_MT_SLOT);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_MT_WIDTH_MAJOR);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_MT_POSITION_X);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);ioctl(uinput_fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_TOUCH);for (i = 0; i < 256; i++){ioctl(uinput_fd, UI_SET_KEYBIT, i);}ioctl(uinput_fd, UI_SET_MSCBIT, KEY_CUSTOM_UP);ioctl(uinput_fd, UI_SET_MSCBIT, KEY_CUSTOM_DOWN);ret = write(uinput_fd, &uinput_dev, sizeof(struct uinput_user_dev));if (ret < 0){printf("%s:%d\n", __func__, __LINE__);return ret; //error process.}ret = ioctl(uinput_fd, UI_DEV_CREATE);if (ret < 0){printf("%s:%d\n", __func__, __LINE__);close(uinput_fd);return ret; //error process.}return ret;
}/** @fun_name     : report_key* @description     : 上报一个触摸事件* @param - type  : 事件种类* @param - keycode : 该种的key* @param - value     : 对应上面key的value* @return           : 成功返回0*/
int report_key(unsigned int type, unsigned int keycode, unsigned int value)
{struct input_event key_event;int ret;memset(&key_event, 0, sizeof(struct input_event));gettimeofday(&key_event.time, NULL);key_event.type = type;key_event.code = keycode;key_event.value = value;ret = write(uinput_fd, &key_event, sizeof(struct input_event));if (ret < 0){printf("%s:%d\n", __func__, __LINE__);return ret; //error process.}return 0;
}/** @fun_name     : device_writeEvent* @description  : 上报一个触摸事件* @param - type  : 事件种类* @param - keycode : 该种的key* @param - value     : 对应上面key的value* @return           : 成功返回0*/
static int device_writeEvent(unsigned int type, unsigned int keycode, unsigned int value)
{struct input_event ev;// 保存log数据char *save_log_data = (char *)malloc(200);sprintf(save_log_data, "%04x %04x %08x \n", type, keycode, value);free(save_log_data);memset(&ev, 0, sizeof(struct input_event));ev.type = type;ev.code = keycode;ev.value = value;if (write(uinput_fd, &ev, sizeof(struct input_event)) < 0){char *mesg = strerror(0);printf("nibiru uinput errormag info :%s\n", mesg);return 0;}return 1;
}/** @fun_name         : start_report* @description       : 对全部的event进行上报* @param - all_event    : 全部的事件结构体数组* @param - point_count : 此时有多少事件是能够被input识别的* @return                 : NULL*/
void start_report(struct report_event all_event[5], int point_count)
{int count;int count_effective = 5;for (count = 0; count < 5; count++){if (all_event[count].effective == -1){count_effective--;if (all_event[count].point_state == 1 || all_event[count].point_state == 0)count_effective++;}}if (count_effective == 1){for (count = 0; count < 5; count++){if (all_event[count].point_state == -1)continue;if (all_event[count].effective == -1 && all_event[count].point_state != 1 && all_event[count].point_state != 0)continue;//如果是抬起if (all_event[count].point_state == 1){if (point_count == 1) //唯一的手指抬起{                   //通过真实存在判断只有一个点//device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[count].point_id); //其实不用加的,但是这个不太听话,乱搞,以至于不上报device_writeEvent(EV_ABS, ABS_MT_TRACKING_ID, -1); //代表手指消失device_writeEvent(1, 330, 0);                      // 表示抬起指令device_writeEvent(0, 0, 0);                        //同步一下事件}else //一个手指不动,另一个抬起{device_writeEvent(EV_ABS, ABS_MT_TRACKING_ID, -1); //代表手指消失device_writeEvent(0, 0, 0);                         //同步一下事件device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[0].point_id);}}//刚刚按下if (all_event[count].point_state == 0){if (point_count == 1) //唯一的手指按下{device_writeEvent(EV_ABS, ABS_MT_TRACKING_ID, all_event[count].point_id + 40); //代表手指iddevice_writeEvent(EV_ABS, ABS_MT_POSITION_X, all_event[count].x_location);     //多点下x坐标device_writeEvent(EV_ABS, ABS_MT_POSITION_Y, all_event[count].y_location);      //多点下y的坐标device_writeEvent(1, 330, 1);                                                  //表示按下指令device_writeEvent(EV_ABS, ABS_X, all_event[count].x_location);                  //单点下 x坐标device_writeEvent(EV_ABS, ABS_Y, all_event[count].y_location);                 //单点下 y坐标device_writeEvent(0, 0, 0);                                                    //同步一下事件}else //一个手指不动,另一个按下{device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[count].point_id);             //代表手指iddevice_writeEvent(EV_ABS, ABS_MT_TRACKING_ID, all_event[count].point_id + 40); //代表手指iddevice_writeEvent(EV_ABS, ABS_MT_POSITION_X, all_event[count].x_location);      //多点下x坐标device_writeEvent(EV_ABS, ABS_MT_POSITION_Y, all_event[count].y_location);      //多点下y的坐标device_writeEvent(0, 0, 0);                                                    //同步一下事件}}//保持按下if (all_event[count].point_state == 2){if (point_count == 1) //唯一的手指滑动{device_writeEvent(EV_ABS, ABS_MT_POSITION_X, all_event[count].x_location); //多点下x坐标device_writeEvent(EV_ABS, ABS_MT_POSITION_Y, all_event[count].y_location); //多点下y的坐标device_writeEvent(EV_ABS, ABS_X, all_event[count].x_location);            //单点下 x坐标device_writeEvent(EV_ABS, ABS_Y, all_event[count].y_location);             //单点下 y坐标device_writeEvent(0, 0, 0);                                                //同步一下事件}else //一个手指不动,另一个滑动{device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[count].point_id);         //代表手指iddevice_writeEvent(EV_ABS, ABS_MT_POSITION_X, all_event[count].x_location); //多点下x坐标device_writeEvent(EV_ABS, ABS_MT_POSITION_Y, all_event[count].y_location); //多点下y的坐标device_writeEvent(EV_ABS, ABS_X, all_event[0].x_location);                   //单点下 x坐标device_writeEvent(EV_ABS, ABS_Y, all_event[0].y_location);                 //单点下 y坐标device_writeEvent(0, 0, 0);                                                //同步一下事件}}}}if (count_effective > 1){ //这时候就是多点按下了for (count = 0; count < 5; count++){if (all_event[count].point_state == -1)continue;if (all_event[count].effective == -1 && all_event[count].point_state != 1 && all_event[count].point_state != 0)continue;//如果是抬起if (all_event[count].point_state == 1){device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[count].point_id);device_writeEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);           //代表手指消失device_writeEvent(EV_ABS, ABS_X, all_event[0].x_location); //多点下x坐标device_writeEvent(EV_ABS, ABS_Y, all_event[0].y_location); //多点下y的坐标device_writeEvent(0, 0, 0);                                  //同步一下事件device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[0].point_id);}//多点按下if (all_event[count].point_state == 0){device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[count].point_id);            //代表手指iddevice_writeEvent(EV_ABS, ABS_MT_TRACKING_ID, all_event[count].point_id + 40); //代表手指iddevice_writeEvent(EV_ABS, ABS_MT_POSITION_X, all_event[count].x_location);      //多点下x坐标device_writeEvent(EV_ABS, ABS_MT_POSITION_Y, all_event[count].y_location);      //多点下y的坐标device_writeEvent(0, 0, 0);                                                    //同步一下事件}//多点滑动if (all_event[count].point_state == 2){if (count == 0) //构造出touch1的多点触摸上报事件{device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[count].point_id);           //代表手指iddevice_writeEvent(EV_ABS, ABS_MT_POSITION_X, all_event[count].x_location); //多点下x坐标device_writeEvent(EV_ABS, ABS_MT_POSITION_Y, all_event[count].y_location); //多点下y的坐标;}else{device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[count].point_id);        //代表手指iddevice_writeEvent(EV_ABS, ABS_MT_POSITION_X, all_event[count].x_location); //多点下x坐标device_writeEvent(EV_ABS, ABS_MT_POSITION_Y, all_event[count].y_location); //多点下y的坐标device_writeEvent(EV_ABS, ABS_X, all_event[0].x_location);                   //单点下 x坐标device_writeEvent(EV_ABS, ABS_Y, all_event[0].y_location);                 //单点下 y坐标device_writeEvent(0, 0, 0);                                                //同步一下事件}}}}
}/** @fun_name         : read_raw* @description       : 读取原生数据,调用虚拟设备,并且进行复现* @return                : 返回0表示成功*/
int read_raw()
{int ts;int us;FILE *fp_data;int start = 0; //开始运行定义char str[N + 1];unsigned int *split;unsigned int split_data[50] = {0}; //单次获取数据数组struct report_event all_event[5];struct all_point now_all_point; //本次数据的整理struct all_point pre_all_point; //上次数据的整理if ((fp_data = fopen("./1.txt", "rt")) == NULL){puts("Fail to open file!");exit(0);}// 构建虚拟设备int ret = 0;ret = creat_user_uinput();if (ret < 0){printf("%s:%d\n", __func__, __LINE__);return -1; //error process.}sleep(5); // help you to 'hexdump -C /dev/input/event[X]' for test.//开始复现pre_all_point.sec = 0;pre_all_point.touch[0].touch_info = 0;while (fgets(str, N, fp_data) != NULL){printf("starting   %s\n", str);split = my_split(str,split_data);//取出split的数据,构造出now_all_pointcreate_now_all_point(&now_all_point, split);//用now_all_point 和 pre_all_point对比,构造出eventcreat_report_event(now_all_point, pre_all_point, all_event);//获取延时时间ts = now_all_point.sec - pre_all_point.sec;us = now_all_point.usec - pre_all_point.usec;if (us < 0){us = (1000000 - pre_all_point.usec) + now_all_point.usec;ts -= 1;}if (ts < 0)ts = (1000000 - pre_all_point.sec) + now_all_point.sec;if (start == 0){ts = 0;us = 0;}start = 1;usleep(us);sleep(ts);//上报event1,上报event2start_report(all_event, now_all_point.point_count);pre_all_point = now_all_point;}//关闭文件fclose(fp_data);sleep(5);close(uinput_fd);return 0;
}
/********************************************************************************* @file    analyze_data.h* @author  duck* @version V1.6.0* @date    13-08-2021* @brief   该文件用于分析hidraw触摸点的down/up数据,以及能统计丢up率******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,能进行5点及五点以下的统计,测试中功能* 优异,随便舞动手指也不会出错*******************************************************************************/#ifndef _ANALYZE_DATA_H
#define _ANALYZE_DATA_H#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <linux/uinput.h>
#include <linux/input.h>//我的变量
#define N 150
static int record_data[16] = {0};/**** 单触摸点定义  ****/
struct analyze_touch_point{int point_id;int x_location;int y_location;int touch_info;
};/**** 所有触摸点数据定义  ****/
struct analyze_all_point{int sec;int usec;int point_count;struct analyze_touch_point touch[5];};unsigned int *analyze_split(char *str_data ,unsigned int * split_analyze_data);
void create_now_analyze_point(unsigned int *split ,struct analyze_all_point* p_now_analyze_point);
void creat_report(struct analyze_all_point now_all_point ,struct analyze_all_point pre_all_point );
void analyze_report();#endif
/******************************************************************************** @file    cartoon.h* @author  duck* @version V1.7.0* @date    16-08-2021* @brief   由于在树莓派的系统实现不了多点触摸,但为了证明作者逻辑还算正确,所以作者用*          控制台的形式,来进行多点触摸的划线           ******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,现在能进行两点触摸的复现,对于两点以上* 还有一丝逻辑没有理清, 复现的不准确来自于和input子系统判断的时间戳不同*******************************************************************************/
#ifndef _CARTOON_H
#define _CARTOON_H
#include "readraw.h"#define LINE 41   //给控制台行
#define ROW 76    //给控制台列
static int cartoon_buffer[LINE][ROW] = {0};int show_cartoon();
#endif
/********************************************************************************* @file    hidraw.h* @author  duck* @version V1.5.0* @date    12-08-2021* @brief   文件用来保存hidraw原生数据,在此基础上增加了时间戳,对数据保存在1.txt上*           为将来的复现数据基础做好准备******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,现在能进行两点触摸的复现,对于两点以上* 还有一丝逻辑没有理清, 复现的不准确来自于和input子系统判断的时间戳不同*******************************************************************************/
#ifndef _HID_RAW_H
#define _HID_RAW_H#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/hidraw.h>#define MOUSE_DEV_PATH    "/dev/hidraw0"unsigned char buffer[1000];//存放一次的hidraw数据
struct timeval now_time;   //增加时间节点int hidraw_start();
int hidraw_write(char * the_str);#endif
/********************************************************************************* @file    read_raw.h* @author  duck* @version V1.5.0* @date    12-08-2021* @brief   文件构造了虚拟设备并且对多指触摸进行复现 ******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,现在能进行两点触摸的复现,对于两点以上* 还有一丝逻辑没有理清, 复现的不准确来自于和input子系统判断的时间戳不同*******************************************************************************/#ifndef _READRAW_H
#define _READRAW_H#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <linux/uinput.h>
#include <linux/input.h>#define N 150 //单次获取数据大小
#define KEY_CUSTOM_UP 0x20
#define KEY_CUSTOM_DOWN 0x30static int uinput_fd;                     //虚拟文件指针
static struct uinput_user_dev uinput_dev; //虚拟设备节点/**** 单触摸点定义  ****/
struct touch_point
{int point_id;int x_location;int y_location;int touch_info;
};/**** 所有触摸点数据定义  ****/
struct all_point
{int sec;int usec;int point_count;struct touch_point touch[5];
};/**** 所有上报事件定义  ****/
struct report_event
{int point_state; //判断抬起和按下或者保持下按(0,1,2)int point_id;int x_location;int y_location;int effective;
};unsigned int *my_split(char *str_data ,unsigned int * split_data );
void create_now_all_point(struct all_point *p_now_all_point, unsigned int *split);
void creat_report_event(struct all_point now_all_point, struct all_point pre_all_point, struct report_event all_event[5]);
int creat_user_uinput(void);
int report_key(unsigned int type, unsigned int keycode, unsigned int value);
static int device_writeEvent(unsigned int type, unsigned int keycode, unsigned int value);
void start_report(struct report_event all_event[5], int point_count);
int read_raw();#endif
/******************************************************************************** @file    search_touch.h* @author  duck* @version V1.8.0* @date    18-08-2021* @brief   增加了自动识别触摸设备的功能,无论在哪个hidraw都能识别出来           ******************************************************************************* @attention* 目前的固件仅供指导,目的是为完成demo,现在能进行两点触摸的复现,对于两点以上* 还有一丝逻辑没有理清, 复现的不准确来自于和input子系统判断的时间戳不同*******************************************************************************/#ifndef _SEARCH_TOUCH_H
#define _SEARCH_TOUCH_H#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>#ifndef INPUT_PROP_MAX
# define INPUT_PROP_MAX         0x1f
#endif
#ifndef INPUT_PROP_DIRECT
# define INPUT_PROP_DIRECT      0x01
#endif#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BIT(nr)                 (1UL << (nr))
#define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr)            ((nr) / BITS_PER_LONG)
#define BITS_PER_BYTE           8
#define BITS_PER_LONG           (sizeof(long) * BITS_PER_BYTE)
#define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))#define DEV_INPUT_EVENT "/dev/input"
#define EVENT_DEV_NAME "event"char *scan_devices(void);
#endif

hdiraw多点分析,使用getevnt进行上报相关推荐

  1. android 电容屏多点触控协议

    多点触控协议 为了发挥新近的多点触摸和多用户设备的强大功能,为多点触摸定义一种上报详细数据的方法(比如有多个物体直接接触到设备的表面),是非常有必要的.多点触摸协议(multi-touch,MT),是 ...

  2. IMX6q ft5x0x_ts触摸芯片分析

    Imx6使用的触摸屏控制芯片是ft5x06系列的,对应的文件为:ft5x06_ts.c. Ft5x06_ts驱动涉及的内容如下: 1.  I2C驱动框架. 2.  中断子系统,中断分层思想. 3.  ...

  3. 数据上报痛点解决方案

    作者:donnyhuang,腾讯微信支付运营支持研发团队 数据驱动是近年来很火的概念,可以优化产品体验.可以用于运营增长.可以发现质量问题,看起来无所不能,时尚先进.但是,你得先有"数据上报 ...

  4. android 触摸屏(TP)问题现象分析和解决方法

    1 现象描述:进入浏览器,网页放大和缩小效果差 原因分析:由于TP抖动导致该问题. 解决方法:有抖动导致放大缩小不稳定,需要开启防抖功能,在最后主动丢掉2~3个点.开启防抖会降低报点率,需要结合用户效 ...

  5. 《手Q Android线程死锁监控与自动化分析实践》

    一.问题背景 手Q每个版本上线以后研发同学都会收到各种问题反馈.在跟进手Q内部用户反馈的问题时,发现多例问题,其表象和原因如下: 1.问题表象:"未读不消失"."图片不展 ...

  6. 关于微信小程序进行数据统计以及分析问题

    一款项目的发布和使用,开发者均希望能够得知自己开发的项目人群反响如何.一般的项目都会通过自己定义的方式与数据库连接进行记录与统计.如今微信小程序的流行,小程序的使用情况的反馈也是必不可少的.故而,微信 ...

  7. TP问题现象分析和解决方法汇总

    No.1 现象描述:进入浏览器,网页放大和缩小效果差 原因分析:由于TP抖动导致该问题. 解决方法:有抖动导致放大缩小不稳定,需要开启防抖功能,在最后主动丢掉2~3个点. 开启防抖会降低报点率,需要结 ...

  8. 重理工疫情期间自动打卡JS实现(每日上报+体温上报)

    文章目录 疫情打卡背景 打卡界面 网站分析 登陆网站 每日上报 每日体温上报 部署代码 结果展示 整体代码 疫情打卡背景 众所周知,机器的出现就是为了将人从大量重复的劳动中解救出来,再加上我一般都是在 ...

  9. Android 触摸屏(TP)问题现象分析和解决方法汇总

    转载自http://blog.csdn.net/wlwl0071986/article/details/8302135 No.1 现象描述:进入浏览器,网页放大和缩小效果差 原因分析:由于TP抖动导致 ...

最新文章

  1. Spark2.x写入Elasticsearch的性能测试
  2. python编程入门电子书下载-最经典的25本Python编程开发电子书(附下载地址)!...
  3. 11gR2 RAC启用iptables导致节点宕机问题处理
  4. 惠普服务器bios查看硬件属性,查看硬件信息
  5. 3d vision可以卸载吗_金属粉末可以用于3D打印,但这些知识你了解吗?
  6. python的基础_毫无基础的人如何入门 Python ?
  7. html怎么设置动画保持,html – 如何使用CSS3为td列可见性设置动画
  8. 自带CA ,sha256 哈希签名,2048 位加密 脚本,通用
  9. 2016年中国OTT盒子行业市场现状及发展前景分析
  10. 网站采集工具免费采集发布网站后台
  11. JavaScript/JS闭包理解
  12. 线性动力学问题(二)
  13. MacBook上有哪些实用必备软件(2020年集合篇)
  14. GUI图形用户接口编写QQ登录界面
  15. [转]我的FLASH情结2010——浅谈FLASH WEB GAME与创业(下)
  16. 滴滴开源 LogicFlow:专注流程可视化的前端框架
  17. Python 获取当前系统时间
  18. TCP/IP网络编程(一)
  19. 欧盟 GDPR 通用数据保护条例正式生效后,各行业影响分析
  20. JavaScript对数组操作。添加/删除/截取/排序/倒序

热门文章

  1. ACM学习:例题完成总结与期中心得
  2. iOS:quartz2D绘图(绘制渐变图形)
  3. 09-mumu模拟器调键盘,回车键
  4. excel怎么设置自动计算_超全8套工程测量计算Excel自动算量表,输入参数即可得出精准结果...
  5. 好嗨呦是谁_好嗨哟谁唱火的 毛毛姐录好嗨哦原创视频吸粉无数
  6. phpfpm怎么连接mysql_配置nginx、mysql、php-fpm的方法
  7. Big Faceless Java PDF Library[bfopdf]
  8. 塑料壳上下扣合的卡扣设计_一种组合玩具的塑料卡扣的制作方法
  9. python查阅文献
  10. 小姐姐教你用代码画画,真大佬!