实现Python虚拟按键解决getch()的自动化测试问题

来源:互联网 发布:淘宝刷关注软件 编辑:程序博客网 时间:2024/06/05 02:29

之前由于项目组的smoke test太过频繁,而且这些工具大部分功能都是通过命令行执行的,这么便利的条件下不做一套自动测试脚本真是没有天理了!

在开发过程中发现一个问题:代码中同时使用了getchar()和getch()两个函数,从自动测试角度看,getchar()好处理,它的来源是缓冲区,利用python的管道很容易搞定,而getch()就麻烦了,它是直接来源于键盘中断,管道在这里就没用了....

这怎么办呢?思来想去只能实现一个虚拟键盘来解决这个问题了,在Windows中还好,有一个现成的python模块可以利用,直接调用Windows API调用虚拟键盘,你可以在这里找到它:http://sourceforge.net/projects/pywin32/files%2Fpywin32/。在linux里比较麻烦,好像没有现成的python模块支持,没办法只能自己写个小程序实现了,简单起见,还是用c吧,这个比较熟悉...

首先是linux下虚拟键盘的C代码实现:

#include <linux/input.h>#include <time.h>#include <fcntl.h>#include <string.h>#include <errno.h>#include <stdio.h>typedef struct Ascii2KeyCode{unsigned char ascii;int keycode_sum;unsigned int keycode[3];}Ascii2KeyCode_t;#define Backspace 14#define Shift 42 #define Control 29 #define Alt 56 #define CapsLock 58#define Esc 1 #define PageUp 104 #define PageDown 109#define End 107 #define Home 102 #define Insert 110 #define Delete 111 #define Help 138 #define NumLock 69 Ascii2KeyCode_t ascii2keycode_map[] = {{'\t', 1, {15,}},{'\n', 1, {28,}},{'\'', 1, {40,}},{'\\', 1, {43,}},{'\"', 2, {Shift,40}},{' ', 1, {57,}},{'!', 2, {Shift,2,}},{'#', 2, {Shift,4,}},{'$', 2, {Shift,5,}},{'%', 2, {Shift,6,}},{'&', 2, {Shift,8,}},{'(', 2, {Shift,10,}},{')', 2, {Shift,11,}},{'*', 2, {Shift,9,}},{'+', 2, {Shift,13,}},{',', 1, {51,}},{'-', 1, {12,}},{'.', 1, {52,}},{'/', 1, {53,}},{'0', 1, {11,}},{'1', 1, {2,}},{'2', 1, {3,}},{'3', 1, {4,}},{'4', 1, {5,}},{'5', 1, {6,}},{'6', 1, {7,}},{'7', 1, {8,}},{'8', 1, {9,}},{'9', 1, {10,}},{':', 2, {Shift,39,}},{';', 1, {39,}},{'<', 2, {Shift,51,}},{'=', 1, {13,}},{'>', 2, {Shift,52,}},{'?', 2, {Shift,53,}},{'@', 2, {Shift,3,}},{'A', 2, {Shift,30,}},{'B', 2, {Shift,48,}},{'C', 2, {Shift,46,}},{'D', 2, {Shift,32,}},{'E', 2, {Shift,18,}},{'F', 2, {Shift,33,}},{'G', 2, {Shift,34,}},{'H', 2, {Shift,35,}},{'I', 2, {Shift,23,}},{'J', 2, {Shift,36,}},{'K', 2, {Shift,37,}},{'L', 2, {Shift,38,}},{'M', 2, {Shift,50,}},{'N', 2, {Shift,49,}},{'O', 2, {Shift,24,}},{'P', 2, {Shift,25,}},{'Q', 2, {Shift,16,}},{'R', 2, {Shift,19,}},{'S', 2, {Shift,31,}},{'T', 2, {Shift,20,}},{'U', 2, {Shift,22,}},{'V', 2, {Shift,47,}},{'W', 2, {Shift,17,}},{'X', 2, {Shift,45,}},{'Y', 2, {Shift,21,}},{'Z', 2, {Shift,44,}},{'[', 1, {26,}},{']', 1, {27,}},{'^', 2, {Shift,7,}},{'_', 2, {Shift,12,}},{'`', 1, {41,}},{'a', 1, {30,}},{'b', 1, {48,}},{'c', 1, {46,}},{'d', 1, {32,}},{'e', 1, {18,}},{'f', 1, {33,}},{'g', 1, {34,}},{'h', 1, {35,}},{'i', 1, {23,}},{'j', 1, {36,}},{'k', 1, {37,}},{'l', 1, {38,}},{'m', 1, {50,}},{'n', 1, {49,}},{'o', 1, {24,}},{'p', 1, {25,}},{'q', 1, {16,}},{'r', 1, {19,}},{'s', 1, {31,}},{'t', 1, {20,}},{'u', 1, {22,}},{'v', 1, {47,}},{'w', 1, {17,}},{'x', 1, {45,}},{'y', 1, {21,}},{'z', 1, {44,}},{'{', 2, {Shift,26,}},{'|', 2, {Shift,43,}},{'}', 2, {Shift,27,}},{'~', 2, {Shift,41,}},};void simulate_key(int fd, unsigned int keycode, int keyvalue){struct input_event event,ev;event.type = EV_KEY;event.code = keycode;event.value = keyvalue;gettimeofday(&event.time, 0);memset(&ev, 0, sizeof(ev));if (write(fd, &event, sizeof(event)) < 0) {printf("simulate key error\n");write(fd, &ev, sizeof(ev));return;}write(fd, &ev, sizeof(ev));}void input_char(int fd, char ch_input){int i = 0, j = 0;Ascii2KeyCode_t keycode = {};for (i=0; i<sizeof(ascii2keycode_map)/sizeof(Ascii2KeyCode_t); i++){if (ch_input == ascii2keycode_map[i].ascii){keycode = ascii2keycode_map[i];// Key downfor (j=0; j<keycode.keycode_sum; j++){simulate_key(fd, keycode.keycode[j], 1);}// Key upfor (j=keycode.keycode_sum; j>0; j--){simulate_key(fd, keycode.keycode[j-1], 0);}break;}}}int main ( int argc, char *argv[] ){if (argc < 3){printf("Please input as this : ./virtkeyboard /dev/input/event1 \"12324\"\n");return -1;}// Open device int fd_kbd = open(argv[1], O_RDWR);if(fd_kbd <= 0) {printf("error open keyboard:%s\n", strerror(errno));return -1;}// Input chars one-by-onechar *pt = argv[2];for (pt=argv[2]; *pt!='\0'; pt++){input_char(fd_kbd, *pt);}// Close deviceclose(fd_kbd);return 0;}
用gcc编译,命名为“virtkeyboard”,然后copy到/usr/local/bin下,或者把存放路径加到PATH变量中。下面是python模块,屏蔽Windows和linux差异,实现虚拟键盘:

import platformimport timeimport subprocessif (platform.system().lower().find("windows") != -1):    Backspace = 8     Shift  = 16     Control = 17     Alt = 18     CapsLock = 20    Esc = 27     PageUp = 33     PageDown = 34    End = 35     Home = 36     Insert = 45     Delete = 46     Help = 47     NumLock = 144     Ascii2KeyCode = {\            b'\t':[9,],        \            b'\n':[13,],       \            b'\'':[222,],     \            b'\\':[220,],     \            b'\"':[Shift,222,],\            b' ':[32,],        \            b'!':[Shift,49,], \            b'#':[Shift,51,], \            b'$':[Shift,52,], \            b'%':[Shift,53,], \            b'&':[Shift,55,], \            b'(':[Shift,57,], \            b')':[Shift,48,], \            b'*':[Shift,56,], \            b'+':[Shift,187,],\            b',':[188,],      \            b'-':[189,],      \            b'.':[190,],      \            b'/':[191,],      \            b'0':[48,],       \            b'1':[49,],       \            b'2':[50,],       \            b'3':[51,],       \            b'4':[52,],       \            b'5':[53,],       \            b'6':[54,],       \            b'7':[55,],       \            b'8':[56,],       \            b'9':[57,],       \            b':':[Shift,186,],\            b';':[186,],      \            b'<':[Shift,188,],\            b'=':[187,],      \            b'>':[Shift,190,],\            b'?':[Shift,191,],\            b'@':[Shift,50,], \            b'A':[Shift,65,], \            b'B':[Shift,66,], \            b'C':[Shift,67,], \            b'D':[Shift,68,], \            b'E':[Shift,69,], \            b'F':[Shift,70,], \            b'G':[Shift,71,], \            b'H':[Shift,72,], \            b'I':[Shift,73,], \            b'J':[Shift,74,], \            b'K':[Shift,75,], \            b'L':[Shift,76,], \            b'M':[Shift,77,], \            b'N':[Shift,78,], \            b'O':[Shift,79,], \            b'P':[Shift,80,], \            b'Q':[Shift,81,], \            b'R':[Shift,82,], \            b'S':[Shift,83,], \            b'T':[Shift,84,], \            b'U':[Shift,85,], \            b'V':[Shift,86,], \            b'W':[Shift,87,], \            b'X':[Shift,88,], \            b'Y':[Shift,89,], \            b'Z':[Shift,90,], \            b'[':[219,],      \            b']':[221,],      \            b'^':[Shift,54,], \            b'_':[Shift,189,],\            b'`':[192,],      \            b'a':[65,],       \            b'b':[66,],       \            b'c':[67,],       \            b'd':[68,],       \            b'e':[69,],       \            b'f':[70,],       \            b'g':[71,],       \            b'h':[72,],       \            b'i':[73,],       \            b'j':[74,],       \            b'k':[75,],       \            b'l':[76,],       \            b'm':[77,],       \            b'n':[78,],       \            b'o':[79,],       \            b'p':[80,],       \            b'q':[81,],       \            b'r':[82,],       \            b's':[83,],       \            b't':[84,],       \            b'u':[85,],       \            b'v':[86,],       \            b'w':[87,],       \            b'x':[88,],       \            b'y':[89,],       \            b'z':[90,],       \            b'{':[Shift,219,],\            b'|':[Shift,220,],\            b'}':[Shift,221,],\            b'~':[Shift,192,],\    }if (platform.system().lower().find("windows") != -1):    import win32api    import win32con      def KeyDown(keyCode):    if (platform.system().lower().find("windows") != -1):        win32api.keybd_event(keyCode,0,0,0)def KeyUp(keyCode):    if (platform.system().lower().find("windows") != -1):        win32api.keybd_event(keyCode,0,win32con.KEYEVENTF_KEYUP,0)def InputChar(char=b''):    if (len(char) < 1):        return None    keyCodeList = Ascii2KeyCode.get(char)    if (keyCodeList == None):        print('Can not found char\'s key code : ' + char)        return None    for keyCode in keyCodeList:        KeyDown(keyCode)    for keyCode in keyCodeList[::-1]:        KeyUp(keyCode)    return char    def FindKeyDevice():    if (platform.system().lower().find("linux") != -1):        commandLine = ['cat', '/proc/bus/input/devices']        proc = subprocess.Popen(commandLine,  shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE,  stderr=subprocess.PIPE)        out, err = proc.communicate()        devInfoLines = out.decode().splitlines()        index = 0        while (index < len(devInfoLines)):            lineStr = devInfoLines[index].strip()            if (len(lineStr) < 1):                index += 1                continue            splitArry = lineStr.split(':')            if (len(splitArry) < 2):                index += 1                continue            if (splitArry[0].strip() == 'N'):                nameSplitArry = splitArry[1].split('=', 1)                if (len(nameSplitArry) < 2) or (nameSplitArry[0].strip() != 'Name'):                    index += 1                    continue                if (nameSplitArry[1].lower().find('keyboard') != -1) and (nameSplitArry[1].lower().find('virtual') == -1):                    index += 4                    if (index >= len(devInfoLines)):                        print('Can not found keyboard device !')                        return None                    lineStr = devInfoLines[index].strip()                    splitArry = lineStr.split(':')                    if (len(splitArry) < 2):                        index += 1                        continue                    if (splitArry[0].strip() == 'H'):                        handlSplitArry = splitArry[1].split('=', 1)                        if (len(handlSplitArry) < 2) or (handlSplitArry[0].strip() != 'Handlers') or (handlSplitArry[1].lower().find('event') == -1):                            index += 1                            continue                        devSplitArry = handlSplitArry[1].split(' ')                        for devStr in devSplitArry:                            if (devStr.lower().find('event') != -1):                                return devStr            index += 1        return None    def InputString(inputStr=b''):    if (platform.system().lower().find("windows") != -1):        for char in inputStr:            keyCode = ord(char)            InputChar(char)        return inputStr    elif (platform.system().lower().find("linux") != -1):        keyDev = FindKeyDevice()        if (keyDev == None):            print('Can not found key device !')            return None        keyDev = '/dev/input/' + keyDev        keyInputStr = '' + inputStr        commandLine = ['virtkeyboard', keyDev, keyInputStr]        proc = subprocess.Popen(commandLine,  shell=False)        proc.wait()    else:        return None    if __name__ == '__main__':    InputString('auto_test\"sdfsdgsdggasd')

Windows下要先安装pywin32,然后就可以随心所欲发你想要的字符了!不过这里有个问题,由于是键盘中断,linux中每个终端貌似都能收到键盘输入事件,windows好像只有当前有效窗口能收到,以后再考虑吧,至少已经满足当前需求了。

1 0