自动化测试程序之二模拟触摸屏点击事件和滑动事件(C语言)

一、测试程序编写说明

终端设备上运行的是LINUX+QT应用程序,使用触摸屏进行人机交互。经过测试人员长时间的人机交互测试,来确认系统的功能是否满足需求后。现在需要编写一个自动化的测试程序模拟触摸屏点击事件和滑动,并能够按照测试人员预设的脚本执行,比如在屏幕的某个位置需要点击某个按钮,或是屏幕或是列表需要滑动,并且这一个或几个动作需要连续执行10000次或更多。通过这样的自动测试,可以减轻测试人员的负担,还可以查看画面按钮触发N次后,画面执行N次后的系统的稳定性,如内存使用率(内存是否泄漏),cup使用率(负载是否很高)等等。

二、测试程序的结构分析

根据上述的简单要求,先分析测试程序的基本逻辑结构是程序通过读脚本中动作以及坐标来执行。

脚本文件以TXT文本形式记录,

P表示点击操作,P x y 3000:点击(x,y)点后等待3000毫秒做下一个动作

S表示滑动操作,S x1 y1 x2 y2 2000:从(x1,y1)点滑动到(x2,y2)点,等待2000毫秒做下一个动作

当前只支持垂直或是水平匀速滑动。(屏幕任意两点的滑动暂时不支持)

R表示重复,R Rounds Ln:表示以下Ln行重复Rounds次,该指令是可选的,如果不写顺序执行脚本。

脚本文本文件示例如下:

——–Sample1.txt————–

R 15000 2
P 973 545 1000 goButton
P 630 750 1000 BackButton

表示点击两个按钮,这两个点击按钮动作循环执行15000次,每次点击指定的坐标后,等待1000毫秒。

——–Sample2.txt————–

R 10000 2
S 200 300 801 300 5000 SlidingLeftToRight
S 800 100 202 100 5000 SlidingRightToLeft


表示在当前页面左右滑动,先由点(200,300)水平向右滑动到点(801,300),sleep 5秒,再由点(800,100)水平向左滑动懂点(202,100),sleep 5秒。

三、测试程序实现主要逻辑

1、定义链表结构

typedef struct List
{
    int  operIndex;
    char operation;
    int  microseconds; //微秒数
    int  i_StartX;   //点击的X坐标,或是滑动的开始点X坐标
    int  i_StartY;   //点击的Y坐标,或是滑动的开始点Y坐标
    int  i_EndX;     //滑动的结束点X坐标
    int  i_EndY;     //滑动的结束点Y坐标
    int  i_repeatCnt;//重复的次数
    int  i_repeatLine;//以下动作重复的行数
    FLAG c_flag;// HEADER or  Member
    char str_note[200]; //动作说明
    struct List *nextGp; //指针域
    struct List *repeatStart;//设定重复的头的位置

}List;
List *oprtData_Set;

2、上报输入事件(input_event)

int reportkey(int fd, uint16_t type, uint16_t code, int32_t value)
{
    struct input_event event;  

    event.type = type;
    event.code = code;
    event.value = value;  

    gettimeofday(&event.time, 0);  

    if (write(fd, &event, sizeof(struct input_event)) < 0) {
        printf("report key error!\n");
        return -1;
    }  

    return 0;
}  

3、尾插法构造动作序列的链表

void TailCreatList(List *L,char * fname)  //尾插法建立链表
{
    List *tmpData;
    List *tail ;
    List *pRepeatHeader;
    int i_repeatCnt = 0;
    int i_repeatLines = 0;
    char c_repeatID;
    REPEAT flag = NoRepeatPos; //
    char buffer[512];
    char c_Oper_temp;
    FILE *infile;
    infile=fopen(fname,"r");
    int index=0;

    tail=L;  //NULL
    pRepeatHeader=tail->nextGp;//NULL

    if(infile==NULL)
    {
        printf("\nFailed to open the file : %s \n",fname);
        exit(0);
    }
    else
    {
        printf("open success! \n");
    }

    memset(buffer,0,sizeof(buffer));

    while ( fgets(buffer, sizeof(buffer), infile))
    {

            tmpData=(struct List*)malloc(sizeof(struct List));
            if(!tmpData)
            {
                printf("malloc() [email protected] \n");
                exit(0);
            }
            memset(tmpData,0,sizeof(struct List));

            tmpData->nextGp=NULL;
            tmpData->repeatStart=NULL;

            sscanf(buffer,"%c",&c_Oper_temp);

            if(c_Oper_temp == ‘p‘ || c_Oper_temp == ‘P‘ ) // 点击事件
            {
                index++;
                sscanf( buffer,"%c %d %d %d %s",&(tmpData->operation),&(tmpData->i_StartX),&(tmpData->i_StartY),&(tmpData->microseconds),&(tmpData->str_note));
                tmpData->operIndex=index;
                tmpData->nextGp=NULL;
                tmpData->repeatStart=NULL; //初始化结构体

                if(flag == RepeatPos ) //设定头指针
                {
                    tmpData->i_repeatCnt=i_repeatCnt;
                    tmpData->i_repeatLine=i_repeatLines; //处于循环位置的第一个节点,设置循环次数和循环的行数
                    pRepeatHeader = tmpData;
                    tmpData->repeatStart = pRepeatHeader;
                    flag = NoRepeatPos;
                    i_repeatLines--;
     //行数减一

                    tail->nextGp=tmpData; //移动指针 未插入链表
                    tail=tmpData; 

                    memset(buffer,0,sizeof(buffer));

                    continue;  //继续循环
                }

                if(pRepeatHeader!=NULL && i_repeatLines>0)  //未循环完了,并且存在头直指
                {
                    i_repeatLines--;

                    tmpData->repeatStart = pRepeatHeader;
                    tail->repeatStart = NULL;
                    tail->nextGp=tmpData; //移动指针 尾部插入链表
                    tail=tmpData; 

                    memset(buffer,0,sizeof(buffer));

                    continue;  //继续循环
                }

                if(i_repeatLines = 0) //循环完了 (循环完了 或是根本没有循环)
                {
                    pRepeatHeader =NULL; //复位循环头的指针,使之为空。
                    flag = NoRepeatPos;//标志位复位
                }               

                tail->nextGp=tmpData; //移动指针 尾部插入链表
                tail=tmpData; 

            }
            else if (c_Oper_temp == ‘s‘ || c_Oper_temp == ‘S‘ ) //滑动事件
            {

                index++;

            //构造滑动动作
                sscanf( buffer,"%c %d %d %d %d %d %s",&(tmpData->operation),
                                                   &(tmpData->i_StartX),&(tmpData->i_StartY),
                                                   &(tmpData->i_EndX),&(tmpData->i_EndY),
                                                   &(tmpData->microseconds),
                                                   &(tmpData->str_note));
                tmpData->operIndex=index;
                tmpData->nextGp=NULL;
                tmpData->repeatStart=NULL; //初始化结构体

                if(flag == RepeatPos ) //设定头指针
                {
                    tmpData->i_repeatCnt=i_repeatCnt;
                    tmpData->i_repeatLine=i_repeatLines; //处于循环位置的第一个节点,设置循环次数和循环的行数
                    pRepeatHeader = tmpData;
                    tmpData->repeatStart = pRepeatHeader;
                    flag = NoRepeatPos;
                    i_repeatLines--;
    //行数减一

                    tail->nextGp=tmpData; //移动指针 未插入链表
                    tail=tmpData; 

                    memset(buffer,0,sizeof(buffer));

                    continue;  //继续循环
                }

                if(pRepeatHeader!=NULL && i_repeatLines>0)  //未循环完了,并且存在头直指
                {
                    i_repeatLines--;

                    tmpData->repeatStart = pRepeatHeader;
                    tail->repeatStart = NULL;
                    tail->nextGp=tmpData; //移动指针 尾部插入链表
                    tail=tmpData; 

                    memset(buffer,0,sizeof(buffer));

                    continue;  //继续循环
                }

                if(i_repeatLines = 0) //循环完了 (循环完了 或是根本没有循环)
                {
                    pRepeatHeader =NULL; //复位循环头的指针,使之为空。
                    flag = NoRepeatPos;//标志位复位
                }               

                tail->nextGp=tmpData; //移动指针 尾部插入链表
                tail=tmpData; 

            }
            else if (c_Oper_temp == ‘R‘ || c_Oper_temp == ‘r‘ ) //滑动事件
            {
                sscanf( buffer,"%c %d %d",&c_repeatID,&i_repeatCnt,&i_repeatLines );
                printf( "Repeat = %c , i_repeatCnt = %d,RepeatLines = %d \n",c_repeatID,i_repeatCnt,i_repeatLines );
                memset(buffer,0,sizeof(buffer));
                flag = RepeatPos;
            }

        memset(buffer,0,sizeof(buffer));
    }
    tail->nextGp=NULL; 

    fclose(infile);

    return ;

}

4、构造点击事件

注意 上报的顺序不要写错,一个事件的结束标志是上报一个EV_SYN事件

void LCD_Touch_Pressed(int posx,int posy,int sec)
{

    printf("emit Point:(%d,%d),sleep %.2f secs\n",posx,posy,(float)sec/1000.0);

    reportkey(TOUCH_FD,EV_ABS,ABS_X,posx);
    reportkey(TOUCH_FD,EV_ABS,ABS_Y,posy); //report position x,y

    reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,200); //report preeusre 200
    reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,1); //report touch preesed event

    reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!

    reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,0);  //report preeusre 0
    reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,0);    //report touch release event

    reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN);   //report syn signal , finish the curent event!

}

5、构造滑动事件

void LCD_Press_Silding(int sx,int sy,int ex,int ey ,int sec)
{

    int nextPosX,nextPosY;
    printf("Siding from Point(%d,%d) to Point(%d,%d),sleep %.2f secs\n",sx,sy, ex, ey , (float)sec/1000.0);

    if(ex == sx && ey==sy) // the same two points
    {
        LCD_Touch_Pressed(sx,sy,sec);
        return ;
    }

    //*report First point */
//  printf("(%d,%d) ",sx,sy);

/**Report pressed-down event START----*/

    reportkey(TOUCH_FD,EV_ABS,ABS_X,sx);
    reportkey(TOUCH_FD,EV_ABS,ABS_Y,sy); //report position x,y

    reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,200); //report preeusre 200
    reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,1); //report touch preesed event

    reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!

    usleep(SILDING_DELAY);
/**Report pressed-down event END----*/  

    nextPosX = sx;
    nextPosY = sy;
    if(ex == sx) // vertical Line
    {
        nextPosY = ey > sy ? (nextPosY + SILDING_STEP) : (nextPosY - SILDING_STEP);
        while (abs(nextPosY-sy)< abs(ey-sy))
        {
    //      printf("(%d,%d), ",ex,nextPosY);

            reportkey(TOUCH_FD,EV_ABS,ABS_X,ex);

            reportkey(TOUCH_FD,EV_ABS,ABS_Y,nextPosY); //report position x,y

            reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
            usleep(SILDING_DELAY);
            nextPosY = ey > sy ? (nextPosY + SILDING_STEP) : (nextPosY - SILDING_STEP);
        }
    //  printf("(%d,%d) \n",ex,ey); //report this last Point

        reportkey(TOUCH_FD,EV_ABS,ABS_X,ex);

        reportkey(TOUCH_FD,EV_ABS,ABS_Y,ey); //report position x,y          

        reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!

        reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,0);  //report preeusre 0
        reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,0);    //report touch release event
        reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN);   //report syn signal , finish the curent event!

        return;
    }

    if(ey == sy) //     horizontal Line
    {
        nextPosX = ex > sx ? (nextPosX + SILDING_STEP) : (nextPosX - SILDING_STEP);
        while (abs(nextPosX-sx)< abs(ex-sx))
        {
        //  printf("(%d,%d), ",nextPosX,ey);
            reportkey(TOUCH_FD,EV_ABS,ABS_X,nextPosX);

            reportkey(TOUCH_FD,EV_ABS,ABS_Y,ey); //report position x,y          

            reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
            usleep(SILDING_DELAY);
            nextPosX = ex > sx ? (nextPosX + SILDING_STEP) : (nextPosX - SILDING_STEP);
        }
    //  printf("(%d,%d) \n",ex,ey); //report this last Point
        reportkey(TOUCH_FD,EV_ABS,ABS_X,ex);

        reportkey(TOUCH_FD,EV_ABS,ABS_Y,ey); //report position x,y          

        reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!

        reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,0);  //report preeusre 0
        reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,0);    //report touch release event
        reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN);   //report syn signal , finish the curent event!
        return;
    }

    printf("Siding from Point(%d,%d) to Point(%d,%d),sleep %d secs, this is A Oblique Line.\n",sx,sy, ex, ey , sec);

/*
 斜线的情况
    //NOT TO Do
*/

}

6、按照链表中的数据逐条发送触摸事件

void Touch_Event_Test(List *L)
{
    List *p=L->nextGp;
    printf("-------Touch_Event_Test-------\n");

    int loop=0;
    CYCLE_MODE mode_flag = FirstCycle;
    int step=0;
    int round=0;

    while(p!=NULL)
    {
        if(p->operation == ‘p‘ || p->operation == ‘P‘ ) // 点击事件
        {
            printf("[%d:%d]",round,p->operIndex);
            // printf("[%c,%d,%d   %d]  \n", p->operation,p->i_StartX,p->i_StartY,p->microseconds);
            LCD_Touch_Pressed(p->i_StartX,p->i_StartY,p->microseconds);
            usleep(p->microseconds * MSECONDS);
        }
        else if (p->operation == ‘s‘ || p->operation == ‘S‘ ) //滑动事件
        {
            printf("[%d:%d]",round,p->operIndex);
            //printf("[%c,%d,%d ; %d,%d   %d]  \n", p->operation,p->i_StartX,p->i_StartY,p->i_EndX,p->i_EndY,p->microseconds);
            LCD_Press_Silding(p->i_StartX,p->i_StartY,p->i_EndX,p->i_EndY,p->microseconds);
            usleep(p->microseconds * MSECONDS);
        }

        if(!p->repeatStart) //当前没有前向循环节点,
        {
            p = p->nextGp;

            if(loop==0) //没有循环
                round = 0;
            else
                round=round;//存在循环,round不变
        }
        else
        {

if(mode_flag == FirstCycle &&  p->repeatStart->i_repeatCnt >0)
             {
                    loop = p->repeatStart->i_repeatCnt;
                    mode_flag = OtherCycle;
                    p = p->repeatStart;
                    loop--;
                    round ++;
                    continue;
            }

            if( loop > 0 && mode_flag == OtherCycle )//未重复完
            {
                    p = p->repeatStart;
                    loop--;
                    round ++;

                    continue;

            }

            mode_flag = FirstCycle;//循环完了, 恢复默认值,

            round = 0;
            p = p->nextGp;
            printf("\n\n");
        }

    }

}

四、参考源码程序

http://download.csdn.net/detail/flyeagle022/8800319

时间: 2024-10-21 09:43:07

自动化测试程序之二模拟触摸屏点击事件和滑动事件(C语言)的相关文章

AndroidのListView之滑动列表项(点击事件和滑动事件共存) - bvin

返回脚本百事通 这里正好在项目有这么一个bt的需求,如下图ListView的item可以响应点击事件也可以响应item的左右滑动事件,两个事件可以相互独立互不影响. 听说iphone的list选项就有这样bt的功能,安卓版的手机QQ和微信和QQ通讯录也有类似的效果,在网上各种寻早方案都试过,要不只能滑动不能点击要么就只能点击不能滑动,而且操作很不灵敏,网上的代码都是在itemView的onTouch方法里处理,判断down和up的像素差.其实这样操作相当不便,down-up这样的其实只能算拖动事

使用powershell/vbs自动化模拟鼠标点击操作

今天想做windows上的自动化,所以才有了模拟鼠标点击的需求,先考虑用powershell实现: 首先先安装一个名为“WASP”免费可用的Powershell扩展程序,下载地址:http://wasp.codeplex.com/ 下载解压之后放到C:\Windows\System32\WindowsPowerShell\v1.0\Modules\下,如图: 之后,在开始->运行处输入powershell,以管理员方式运行, 执行Import-Module WASP,则引入了扩展程序, 假如有个

Android模拟屏幕点击input tap替代解决方案

动机解释 本来直接使用 adb shell -> input 即可模拟 键盘事件,触屏事件keyevent ,text,tap 但是手上的这台目标Android机4.0.3系统的input只支持text和keyevent,不支持tap,无法模拟触屏点击事件. usage: input [text|keyevent] input text <string> input keyevent <event_code> 于是开始寻找模拟触屏的替代解决方案. 最新的Android API

CSS伪类选择器active模拟JavaScript点击事件

一.说明 设置元素在被用户激活(在鼠标点击与释放之间发生的事件)时的样式. IE7及更早浏览器只支持a元素的:active,从IE8开始支持其它元素的:active. 另:如果需要给超链接定义:访问前,鼠标悬停,当前被点击,已访问这4种伪类效果,而又没有按照一致的书写顺序,不同的浏览器可能会有不同的表现.超链接的4种状态,需要有特定的书写顺序才能生效.注意,a:hover必须位于a:link和a:visited之后,a:active必须位于a:hover之后.可靠的顺序是:l(link)ov(v

求助:程序如何模拟鼠标点击一个TreeView节点?

void CreateTreeViewControl(HWND hMainWnd) { g_hTreeView = CreateWindow(WC_TREEVIEW, _T("Tree View"), WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES | TVS_LINESATROOT, 5, 5, 320, 480, hMainWnd, NULL, hInst, NULL); TVINSERTSTRUCT tvInsertStruct

css3模拟jq点击事件

还是这个梗,收好冷.今天是一个css3模拟jq点击事件,因为我发现,css3中没有类似于,js的点击事件,那么,可不可以仿照 jq的效果,类似的做一个呢?主要用到,input里面的radio 单选按钮,然后后面跟一个a标签,让radio覆盖在a上,那为什么不直接 把 a放在radio上面呢?因为选择器 + 好选择嘛,用radio的功能,a来修饰按钮样式,再把radio 隐藏,这里要用opacity(透明度) 这就是,主要原理! 上视图吧 <!DOCTYPE html> <html>

WEBBROWSER中模拟鼠标点击(SendMessage/PostMessage)

好久没有写文章,发一篇顶顶博客访问量.别人建议转一些比较好的代码也贴过来,但是我打算这里主要发自己原创的代码,所以么..流量该多少就多少吧... 回到主题,在webbrowser中点击某链接网上几乎都是用document对象模拟点击,这个方法基本能应对一般的情况,但是例如广告联盟的点击XXX就有检测机制(不多解释,你们懂的).所以完全模拟鼠标的点击事件就比较完美.于是我用了最常见的SendMessage. 接下来就要解决一个问题,webbrowser的句柄问题.从控件本身得到的句柄不是真正的浏览

sendmessage()模拟鼠标点击

{鼠标软模拟:好处就是不会真的移动鼠标 开始按钮 坐标 x=386y=387 }sendmessage(hookHwnd,messages.WM_LBUTTONDOWN ,0,$0180017A); {按下鼠标左键}sendmessage(hookHwnd,messages.WM_LBUTTONUP ,0, $0180017A); {抬起鼠标左键}{硬件模拟:会真的移动鼠标}mouse_event(MOUSEEVENTF_LEFTDOWN,X ,Y ,0,0);mouse_event(MOUSE

android 代码实现模拟用户点击、滑动等操作

/** * 模拟用户点击 * * @param view 要触发操作的view * @param x 相对于要操作view的左上角x轴偏移量 * @param y 相对于要操作view的左上角y轴偏移量 */private static void analogUserClick(View view, float x, float y) { if (view == null) { return; } LogUtil.e(TAG_POINT, "正在模拟点击操作:p->" + x +