安卓实现按键录制回放

2 篇文章 0 订阅

       最近玩pokemongo需要将扔excellent球的操作录下来,这样子下次直接就可以不用自己手扔了。通过adb进入shell后getevent命令可以打印实时触摸的操作信息,sendevent能够写入操作到触摸屏,实现模拟滑动和点击和其他操作,但是将getevent的16进制转为10进制后给sendevent后批量执行操作,会发现回放得很慢,这是因为不到100行的sendevent.c源码,仅仅是打开触摸设备,然后写入操作,然后关闭设备,所以批量执行sendevent肯定慢,因此我们采用安卓NDK重新修改编译getevent和setevent代码。

      getevent代码需要修改是因为getevent /dev/input/event5 > a.txt后没办法停止,我们内部加一个停止功能,用select判断输入缓冲区有没有数据,有的话就退出录制。只需要加一点代码如下:

while(1) {
        pollres = poll(ufds, nfds, -1);
        //printf("poll %d, returned %d\n", nfds, pollres);
        if(ufds[0].revents & POLLIN) {
            read_notify(device_path, ufds[0].fd, print_flags);
        }

        //添加这些代码
		FD_ZERO(&fSet);
		FD_SET(0,&fSet);
		tv.tv_sec = 0; tv.tv_usec=0;
		{
			int ret=select(1,&fSet,NULL,NULL,&tv);
			if(ret>0) return 0;
		}
        //添加结束

这样子在不想要录制屏幕操作的时候虽然输入一些东西回车后,在碰下屏幕就停止录制了。其他的添加需要的头文件,以及修改时间打印格式

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>

printf("%8ld %06ld ", event.time.tv_sec, event.time.tv_usec);

一共是需要getevent.c和getevent.h两个文件。

sendevent只需要一个sendevent.c文件,修改为如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>

fd_set fSet;
struct timeval tv;
void delay(__time_t tv_sec,__suseconds_t tv_usec)
{
  tv.tv_sec = tv_sec;
  tv.tv_usec = tv_usec;
  select(0,NULL,NULL,NULL,&tv);
}
int convert (char * str) {
    return (int) strtol(str, NULL, 16);
}
int main(int argc, char *argv[])
{
    int fdout;
	FILE * fd_in;
	//打开录制的数据文件
	fd_in = fopen(argv[1], "r");
    if (fd_in == NULL) {
        fprintf(stderr, "Can't open input file: %s\n", argv[1]);
        return 1;
    }
	//打开触摸屏设备
	fdout = open(argv[2],O_RDWR);
	if(fdout<0){
		perror("open device:");
	   return -1;	
	}
	struct input_event event;
    char type[32];
    char code[32];
    char value[32];
	unsigned int tsec,tusec,initsec,initusec,dtsec,dtusec;
	int ret;
	int first = 0;
	//逐行扫描写入
	while (fscanf(fd_in, "%u %u %s %s %s", &tsec,&tusec,type, code, value) != EOF) {
        memset(&event, 0, sizeof(event));
        event.type = convert(type);
        event.code = convert(code);
        event.value = convert(value);
        memset(type, 0, sizeof(type));
        memset(code, 0, sizeof(code));
        memset(value, 0, sizeof(value));
        ret = write(fdout, &event, sizeof(event));
        if(ret < sizeof(event)) {
            fprintf(stderr, "write event failed, %s\n", strerror(errno));
            return -1;
        }
		if(first==0){//初值
		   first=1;	
		   initsec = tsec;
		   initusec = tusec;
		}else{
			//计算两个操作间的延时
		   dtsec = tsec - initsec;
		   if(dtsec==0){
			  dtusec = tusec - initusec;   
		   }else{
			  if(tusec<initusec){
				 dtusec = 1000000-initusec + tusec;
				 dtsec-=1;
			  }else{
				 dtusec = tusec-initusec;
			  }
		   }
		   //printf("time diff sec=%u,usec=%u\n",dtsec,dtusec);
		   initsec = tsec;
		   initusec = tusec;
		}
		
		delay(dtsec,dtusec);
	}
	fclose(fd_in);
	close(fdout);
	return 0;
}

通过ndk-build编译后就可以测试了,测试命令如下

cd /data/local/tmp
dir=/storage/emulated/0
cp $dir/mygetevent .
cp $dir/mysendevent .
chmod 755 mygetevent
chmod 755 mysendevent
//查看触摸屏设备事件号码,为event5
cat /proc/bus/input/devices或者getevent
//录制
./mygetevent -t /dev/input/event5 > record.txt
录制完成后随便输入一些东西回车,摸屏幕退出mygetevent程序
//回放操作
./mysendevent record.txt /dev/input/event5

​

在HWP10上测试成功,但是不知道怎么在app中调用这些,只能靠adb shell调用,所以还不是很满意,但是我玩pgo是开飞机的,所以够用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值