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

之前由于项目组的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 down
			for (j=0; j<keycode.keycode_sum; j++){
				simulate_key(fd, keycode.keycode[j], 1);
			}
			// Key up
			for (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-one
	char *pt = argv[2];
	for (pt=argv[2]; *pt!='\0'; pt++){
		input_char(fd_kbd, *pt);
	}
	
	// Close device
	close(fd_kbd);
	
	return 0;
}
用gcc编译,命名为“virtkeyboard”,然后copy到/usr/local/bin下,或者把存放路径加到PATH变量中。下面是python模块,屏蔽Windows和linux差异,实现虚拟键盘:

import platform
import time
import subprocess

if (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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值