zoukankan      html  css  js  c++  java
  • android 按键精灵。C++编写。

    可以记录屏幕键盘等传感器对系统的输入。

    上一篇文章做的那个稍微有点复杂了,还需要把板子的输出拿回电脑处理再倒回去。这个就简单多了用法如下

    usage:
    event record /path/file1
    event replay /path/file1

    给我女友写的程序直接搬过来了,所以注释有些冗余。

    "stdafx.h"

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdint.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <errno.h>
    #include <asm/types.h>
    #include <unistd.h>
    #include <iostream>
    #include <vector>
    struct input_event {
        timeval time;
        __u16 type;
        __u16 code;
        __s32 value;
    };
    struct myinputevent:public input_event
    //继承了16字节的数据结构,添加了一个deviceID
    {
        int deviceID;
    
    };

    main.cpp

    #include "stdafx.h"
    
    void record(char* filename);
    void replay(char* filename);
    int main(int argc, char *argv[])
    {
        if(argc!=3 || (strcmp(argv[1],"record") & strcmp(argv[1],"replay")))
        {
            std::cout<<
    
                    "usage:"<<std::endl<<
                    "event record /path/file1"<<std::endl<<
                    "event replay /path/file1"<<std::endl;
            return 0;
        }
        if(!strcmp(argv[1],"record"))
            record(argv[2]);
        else
            replay(argv[2]);
        return 0;
    }

    replay.cpp

    #include "stdafx.h"
    //#define DEBUG
    int timedif(timeval& a,timeval& b)
    //这是个计算时间差的函数,对于一个timeval的数据结构,前面4字节秒,后面4字节微秒
    //这个函数接受两个这样的结构,返回一个微秒单位的时间差
    {
        return (b.tv_sec-a.tv_sec)*1000000+(b.tv_usec-a.tv_usec);
    }
    
    
    void replay(char* filename)
    {
    
        int fi = open(filename,O_RDONLY);
        if(fi==-1)
        {
            std::cout<<filename<<" cannot be opened"<<std::endl;
            exit(0);
        }
    
    
        char dev[40]="/dev/input/eventX";
    
    
        int DeviceFile[10];
        for(char i='0';i<='9';++i)
        {
            dev[16]=i;
            int f=open(dev,O_RDWR);
            //把所有的event都打开准备写入
            DeviceFile[i-'0']=f;
            //把句柄保存下来,如果打不开的话f值是-1
    #ifdef DEBUG
            if(f!=-1)
                std::cout<<"Device opened:"<<i<<std::endl;
    #endif
    
        }
        myinputevent event0,event1;
        read(fi,&event0,sizeof(myinputevent));
        //先读取第一个event到event0中
        timeval timetemp=event0.time;
        //临时存储event中的时间,因为往设备写的时候,时间要清空
        memset(&event0.time, 0, sizeof(struct timeval));
        //清空时间
        write(DeviceFile[event0.deviceID], &event0.time, sizeof(input_event));
        //写回设备
        event0.time=timetemp;
        //把刚刚保存的时间拿回来
        while(read(fi,&event1,sizeof(myinputevent)))
        //只要文件还能读,就读取下一个event到event1中
        {
    
            int sleeptime=timedif(event0.time,event1.time);
            //计算event0和event1的时间差
    #ifdef DEBUG
            std::cout<<"sleep"<<sleeptime<<std::endl;
    #endif
            usleep(sleeptime);
            //进行时间间隔
            event0.time=event1.time;
            //把event1的时间赋值给event0,这样下次循环的时候继续对比下一个时间差
            memset(&event1.time, 0, sizeof(struct timeval));
            //清空event1的时间
            write(DeviceFile[event1.deviceID], &event1.time, sizeof(input_event));
            //把event1写回设备
        }
        for(int i=0;i<=9;++i)
        {
            if(DeviceFile[i]!=-1)
                close(DeviceFile[i]);
            //关闭所有设备
    
        }
        std::cout<<"Replay completed"<<std::endl;
    }

    record.cpp

    #include "stdafx.h"
    
    #define DEBUG
    inline bool eventcmp(const myinputevent& a,const myinputevent& b)
    //这个比较函数为了之后排序用,因为两个自定义的数据结构,你用标准排序函数,排序肯定不知道你这俩结构应该怎么比大小
    //定义了我的数据结构之间如果做小于比较时,时间小就算小。
    //这样就可以采用标准排序函数对事件进行排序了。
    {
        if(a.time.tv_sec<b.time.tv_sec)
            return 1;
        if(a.time.tv_sec>b.time.tv_sec)
            return 0;
        if(a.time.tv_usec<b.time.tv_usec)
            return 1;
        else
            return 0;
    }
    
    
    
    std::vector<myinputevent> AllRecordedEvent;
    //这里有个数组,用来添加所有录制到的event
    char fn[200];
    void afterstop(int x)
    //按下ctrl+c和回车之后,录制停止,做数据整理和保存工作
    //主要是按时间顺序对事件排序,然后保存
    {
    #ifdef DEBUG
        std::cout<<"Recorded events:"<<AllRecordedEvent.size()<<std::endl;
    #endif
        std::cout<<"Sorting & saving..."<<std::endl;
        std::stable_sort(AllRecordedEvent.begin(),AllRecordedEvent.end(),eventcmp);
        std::cout<<"Sort completed"<<std::endl;
        //这是排序语句,对所有的录制的event排序,排序时大小比较用eventcmp函数,也就是根据时间先后排序啦
        //因为有的时候,设备的输出并不按照时间顺序,比如你按开机键,它涉及的不止一个event,有时会有微微的时间上的错序
        //任何错序都会严重影响replay,所以这里必须排序啦,这里一定要stable_sort,也就是排序必须是稳定的
        //对于不稳定的排序,有时两个事件的时间完全相等,可能会使原来在后面的跑前面去
        int f=open(fn,O_WRONLY | O_CREAT | O_TRUNC);
        if(f==-1)
        {
            std::cout<<fn<<" cannot be opened!";
            exit(0);
        }
        //打开一开始event record file中那个file文件进行写入
        for(unsigned int i=0;i<AllRecordedEvent.size();++i)
        {
            write(f,&AllRecordedEvent[i],sizeof(myinputevent));
        }
        close(f);
        std::cout<<"Record completed. Filename:"<<fn<<std::endl;
        exit(0);
    }
    void record(char* filename)
    {
        std::cout<<"If using windows adb, you have to \"busybox stty intr ^X\" to change the INTR from Ctrl-C to Ctrl-X"<<std::endl;
        std::cout<<"And the stop recording command will be ctrl-X."<<std::endl
                <<"If using linux adb, you are fine."<<std::endl;
        //注意如果用windows中的adb,按下ctrl+c之后windows的shell也会收到命令从而终止adb shell,这样达不到终止录制的功能
        //所以如果非要在windows中使用adb,就需要用这个命令busybox stty intr ^X,把板子的终止组合键注册到ctrl-X上去
        //这样按ctrl-X再回车,就可以终止录制
        strcpy(fn,filename);
        int f=open(fn,O_WRONLY | O_CREAT);
        //先尝试打开一下参数中的文件,若失败就不继续了
        if(f==-1)
        {
            std::cout<<fn<<" cannot be opened!";
            exit(0);
        }
        close(f);
        struct sigaction act;
        act.sa_handler=afterstop;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGINT,&act, NULL);
        //这里注册了ctrl+c事件,这样录制过程中按下ctrl+c然后回车,可以执行afterstop函数。
    
        char dev[40]="/dev/input/eventX";
    
        int DeviceFile[10];
        for(char i='0';i<='9';++i)
        {
            dev[16]=i;
            int f=open(dev,O_RDONLY | O_NONBLOCK);
            //把所有的event都打开,这样保证能包括键盘和屏幕
            //这里O_RDONLY是只读,O_NONBLOCK是非阻塞。非阻塞的意思就是读取的时候,如果设备里没有,就返回-1。
            //如果是阻塞的话,设备里没有,read函数是不返回的,要等到有了才返回。
            //所以阻塞肯定不行,因为我有一堆设备要循环读取的,如果第一个设备没数据就会卡住,后面的设备都读不到。
            DeviceFile[i-'0']=f;
            //把句柄保存下来,如果打不开的话f值是-1
    #ifdef DEBUG
            if(f!=-1)
                std::cout<<"Device opened:"<<i<<std::endl;
    #endif
    
        }
        char buffer[2048];
    
    
        std::cout<<"Recording started, press Ctrl+C then press ENTER to stop recording"<<std::endl;
    
        while(1)
        {
            for(int i=0;i<10;++i)
            {
                if(DeviceFile[i]==-1)
                    continue;
                int ReadSize=read(DeviceFile[i],buffer,2048);
                //不断的循环,把打开了的文件反复读取,这里缓存区必须是16的倍数,因为生成的数据是16字节的数据结构,这个基本结构不能破坏了
                //16字节的数据结构中,前4字节是秒,然后4字节微秒,最后8字节是实际的设备发送的信息
                //这里read会返回读取到的字节数量,如果啥也没读到会返回-1
                if(ReadSize!=-1)
                {
    #ifdef DEBUG
                    std::cout<<"device"<<i<<"read"<<ReadSize<<std::endl;
    #endif
                    for(input_event *p=(input_event*)buffer;(char*)p<buffer+ReadSize;++p)
                    {
                        myinputevent my;
    
                        my.code=p->code;
                        my.type=p->type;
                        my.value=p->value;
                        my.time=p->time;
                        my.deviceID=i;
                        AllRecordedEvent.push_back(my);
                        //这里可能难理解,buffer里存储了大量16字节的event,所以让指针p是数据结构指针,然后16字节16字节的挪动
                        //我有一个自己的数据结构叫myinputevent,比这个16字节来说,尾部添加了一个4字节的int,存储设备的event号
                        //你可以在stdafx.h中看到这些数据结构
                        //把那16字节的原封不动的放到我的数据结构中,再把我自己的设备号赋值,就完成了这一个事件的录制。
                        //然后就存储到AllRecordedEvent里面去。
                    }
                }
            }
        }
    
    }
  • 相关阅读:
    django media配置
    django model项目外操作
    django 快捷代码提示
    django静态文件路径配置
    selenium爬取网易云
    selenium
    pyquery
    beautifulsoup
    Kafka与.net core(三)kafka操作
    Oracle 日期类型timestamp(时间戳)和date类型使用
  • 原文地址:https://www.cnblogs.com/zhangzheng/p/3261224.html
Copyright © 2011-2022 走看看