hdiraw多点分析,使用getevnt进行上报

对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_state
		if (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_point
		create_now_all_point(&now_all_point, split);
		//用now_all_point 和 pre_all_point对比,构造出event
		creat_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,上报event2
		cartoon_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_state
		if (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;
		else
			all_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 dev
	memset(&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 多指触摸 最大手指的数量我们设置5
	uinput_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 =b
	ioctl(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 3
	ioctl(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); //代表手指id
					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(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);			   //代表手指id
					device_writeEvent(EV_ABS, ABS_MT_TRACKING_ID, all_event[count].point_id + 40); //代表手指id
					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(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);		   //代表手指id
					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[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);			   //代表手指id
				device_writeEvent(EV_ABS, ABS_MT_TRACKING_ID, all_event[count].point_id + 40); //代表手指id
				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(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);		   //代表手指id
					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的坐标;
				}
				else
				{
					device_writeEvent(EV_ABS, ABS_MT_SLOT, all_event[count].point_id);		   //代表手指id
					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[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_point
		create_now_all_point(&now_all_point, split);
		//用now_all_point 和 pre_all_point对比,构造出event
		creat_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,上报event2
		start_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 0x30

static 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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值