Python自动化(2)——键盘模拟
前台键盘模拟
前台键盘模拟和后台键盘模拟的区别在于,是否绑定窗口。即前台模拟是只模拟键盘操作,例如按下按键a,如果聚焦在一个文本文档的编辑区,那么就会把这个a输入进去。但如果是聚焦到了浏览器上的百度翻译编辑区,同样会把a输入进去
下图分别是循环输入10个a的结果(浏览器下建议先将输入法改成英文,否则有可能无反应或者是触发了什么快捷键):
实现:
先上代码
import time
import win32api
import win32con
import pyautogui
import pyperclipclass FrontstageKeyBoard():def __init__(self):self.key_map = {"0": 49, "1": 50, "2": 51, "3": 52, "4": 53, "5": 54, "6": 55, "7": 56, "8": 57, "9": 58,'F1': 112, 'F2': 113, 'F3': 114, 'F4': 115, 'F5': 116, 'F6': 117, 'F7': 118, 'F8': 119,'F9': 120, 'F10': 121, 'F11': 122, 'F12': 123, 'F13': 124, 'F14': 125, 'F15': 126, 'F16': 127,"A": 65, "B": 66, "C": 67, "D": 68, "E": 69, "F": 70, "G": 71, "H": 72, "I": 73, "J": 74,"K": 75, "L": 76, "M": 77, "N": 78, "O": 79, "P": 80, "Q": 81, "R": 82, "S": 83, "T": 84,"U": 85, "V": 86, "W": 87, "X": 88, "Y": 89, "Z": 90,'BACKSPACE': 8, 'TAB': 9, 'TABLE': 9, 'CLEAR': 12,'ENTER': 13, 'SHIFT': 16, 'CTRL': 17,'CONTROL': 17, 'ALT': 18, 'ALTER': 18, 'PAUSE': 19, 'BREAK': 19, 'CAPSLK': 20, 'CAPSLOCK': 20, 'ESC': 27,'SPACE': 32, 'SPACEBAR': 32, 'PGUP': 33, 'PAGEUP': 33, 'PGDN': 34, 'PAGEDOWN': 34, 'END': 35, 'HOME': 36,'LEFT': 37, 'UP': 38, 'RIGHT': 39, 'DOWN': 40, 'SELECT': 41, 'PRTSC': 42, 'PRINTSCREEN': 42, 'SYSRQ': 42,'SYSTEMREQUEST': 42, 'EXECUTE': 43, 'SNAPSHOT': 44, 'INSERT': 45, 'DELETE': 46, 'HELP': 47, 'WIN': 91,'WINDOWS': 91, 'NMLK': 144,'NUMLK': 144, 'NUMLOCK': 144, 'SCRLK': 145,'[': 219, ']': 221, '+': 107, '-': 109}print('FrontstageKeyBoard init')# 模拟一次按键的输入,间隔值默认0.1Sdef pressKey(self, key: str, interval=0.1):self.keyDown(key)time.sleep(interval)self.keyUp(key)# 模拟一次组合键的输入,间隔值默认0.1Sdef pressKeys(self, keys, interval=0.1):for i in range (0,len(keys),1):self.keyDown(keys[i], False)time.sleep(interval)for i in range (0,len(keys),1):self.keyUp(keys[i])# 模拟一个按键的按下def keyDown(self, key: str):print('keyDown: ' + str(key))key_code = self.key_map[key.upper()]win32api.keybd_event(key_code, win32api.MapVirtualKey(key_code, 0), win32con.KEYEVENTF_EXTENDEDKEY, 0)# 模拟一个按键的弹起def keyUp(self, key: str):print('keyUp: ' + str(key))key_code = self.key_map[key.upper()]win32api.keybd_event(key_code, win32api.MapVirtualKey(key_code, 0), win32con.KEYEVENTF_KEYUP, 0)# 模拟输入一段文本,只能输入英文或字母def inputText(self, text: str, interval=0.05):print('input text: ' + text)pyautogui.typewrite(text, interval)# 模拟输入一段文本,支持中文,但是实现的方法是通过复制粘贴def inputChineseText(self, text: str):print('input text: ' + text)pyperclip.copy(text)pyautogui.hotkey('Ctrl','v')
这里使用win32api.keybd_event实现键盘模拟按下的操作,实际上前台模拟键盘操作还可以用pykeyboard库、pyautogui库、keyboard库
后台键盘模拟
与前台模拟键盘不同,后台键盘模拟是绑定窗口的,绑定的是窗口句柄,是基于win32api库实现的。后台键盘模拟能做到绑定窗口实现模拟,并且不需要聚焦窗口,简单来说就是不影响正常使用电脑。
先上代码:
import time
import win32api
import win32con
import win32guiclass BackstageKeyBoard():def __init__(self):self.key_map = {"0": 49, "1": 50, "2": 51, "3": 52, "4": 53, "5": 54, "6": 55, "7": 56, "8": 57, "9": 58,'F1': 112, 'F2': 113, 'F3': 114, 'F4': 115, 'F5': 116, 'F6': 117, 'F7': 118, 'F8': 119,'F9': 120, 'F10': 121, 'F11': 122, 'F12': 123, 'F13': 124, 'F14': 125, 'F15': 126, 'F16': 127,"A": 65, "B": 66, "C": 67, "D": 68, "E": 69, "F": 70, "G": 71, "H": 72, "I": 73, "J": 74,"K": 75, "L": 76, "M": 77, "N": 78, "O": 79, "P": 80, "Q": 81, "R": 82, "S": 83, "T": 84,"U": 85, "V": 86, "W": 87, "X": 88, "Y": 89, "Z": 90,'BACKSPACE': 8, 'TAB': 9, 'TABLE': 9, 'CLEAR': 12, 'ENTER': 13, 'SHIFT': 16, 'CTRL': 17,'CONTROL': 17, 'ALT': 18, 'ALTER': 18, 'PAUSE': 19, 'BREAK': 19, 'CAPSLK': 20, 'CAPSLOCK': 20, 'ESC': 27,'SPACE': 32, 'SPACEBAR': 32, 'PGUP': 33, 'PAGEUP': 33, 'PGDN': 34, 'PAGEDOWN': 34, 'END': 35, 'HOME': 36,'LEFT': 37, 'UP': 38, 'RIGHT': 39, 'DOWN': 40, 'SELECT': 41, 'PRTSC': 42, 'printSCREEN': 42, 'SYSRQ': 42,'SYSTEMREQUEST': 42, 'EXECUTE': 43, 'SNAPSHOT': 44, 'INSERT': 45, 'DELETE': 46, 'HELP': 47, 'WIN': 91,'WINDOWS': 91, 'NMLK': 144,'NUMLK': 144, 'NUMLOCK': 144, 'SCRLK': 145,'[': 219, ']': 221, '+': 107, '-': 109}print('BackstageKeyBoard init')def bind(self, hwnd):self.hwnd = hwnd# 后台模拟方法1——使用SendMessage(默认) ############################################# 模拟一次按键的输入,间隔值默认0.1Sdef pressKey(self, key: str, interval=0.1):self.keyDown(key)time.sleep(interval)self.keyUp(key)# 模拟一次组合键的输入,间隔值默认0.1Sdef pressKeys(self, keys, interval=0.1):for i in range (0,len(keys),1):self.keyDown(keys[i])time.sleep(interval)for i in range (0,len(keys),1):self.keyUp(keys[i])# 模拟一个按键的按下def keyDown(self, key: str):print('keyDown: ' + str(key))key_code = self.key_map[key.upper()]win32api.SendMessage(self.hwnd, win32con.WM_KEYDOWN, key_code, 0)# 模拟一个按键的弹起def keyUp(self, key: str):print('keyUp: ' + str(key))key_code = self.key_map[key.upper()]win32api.SendMessage(self.hwnd, win32con.WM_KEYUP, key_code, 0)# 模拟输入一段文本def inputText(self, text: str):print('input text: ' + text)for ch in text:win32gui.SendMessage(self.hwnd, win32con.WM_CHAR, ord(ch), 0)time.sleep(0.05)# 后台模拟方法2——使用PostMessage ############################################# 模拟一次按键的输入,间隔值默认0.1Sdef pressKey_2(self, key: str, interval=0.1):self.keyDown_2(key)time.sleep(interval)self.keyUp_2(key)# 模拟一次组合键的输入,间隔值默认0.1Sdef pressKeys_2(self, keys, interval=0.1):for i in range (0,len(keys),1):self.keyDown_2(keys[i])time.sleep(interval)for i in range (0,len(keys),1):self.keyUp_2(keys[i])# 模拟一个按键的按下def keyDown_2(self, key: str):print('keyDown_2: ' + str(key))key_code = self.key_map[key.upper()]win32api.PostMessage(self.hwnd, win32con.WM_KEYDOWN, key_code, 0)# 模拟一个按键的弹起def keyUp_2(self, key: str):print('keyUp_2: ' + str(key))key_code = self.key_map[key.upper()]win32api.PostMessage(self.hwnd, win32con.WM_KEYUP, key_code, 0)# 模拟输入一段文本def inputText_2(self, text: str):print('input_2 text: ' + text)for ch in text:win32gui.PostMessage(self.hwnd, win32con.WM_CHAR, ord(ch), 0)time.sleep(0.05)
上面的代码中,有使用SendMessage和PostMessage来实现的键盘模拟,其中,SendMessage是会等待函数执行后再返回,而PostMessage发送消息后会立即返回。一般情况下,这两种方法并无太大区别。
SendMessage方法的函数原型:
LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
返回值:返回值指定消息处理的结果,依赖于所发送的消息。
PostMessage方法的函数原型与SendMessage基本一致,不同的是PostMessage的返回值为BOOL类型。
使用后台键盘模拟,需要绑定窗口句柄,关于窗口句柄的获取,可以看看下面这篇文章:
Python自动化(1)——获取窗口句柄
完整自动化工程代码:https://gitee.com/chj-self/PythonRobotization
大佬们找到问题欢迎拍砖~