Python自动化(2)------键盘模拟
前台键盘模拟
前台键盘模拟和后台键盘模拟的区别在于,是否绑定窗口。即前台模拟是只模拟键盘操作,例如按下按键a,如果聚焦在一个文本文档的编辑区,那么就会把这个a输入进去。但如果是聚焦到了浏览器上的百度翻译编辑区,同样会把a输入进去
下图分别是循环输入10个a的结果(浏览器下建议先将输入法改成英文,否则有可能无反应或者是触发了什么快捷键):
实现:
先上代码
python
import time
import win32api
import win32con
import pyautogui
import pyperclip
class 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.1S
def pressKey(self, key: str, interval=0.1):
self.keyDown(key)
time.sleep(interval)
self.keyUp(key)
# 模拟一次组合键的输入,间隔值默认0.1S
def 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库实现的。后台键盘模拟能做到绑定窗口实现模拟,并且不需要聚焦窗口,简单来说就是不影响正常使用电脑。
先上代码:
python
import time
import win32api
import win32con
import win32gui
class 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.1S
def pressKey(self, key: str, interval=0.1):
self.keyDown(key)
time.sleep(interval)
self.keyUp(key)
# 模拟一次组合键的输入,间隔值默认0.1S
def 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.1S
def pressKey_2(self, key: str, interval=0.1):
self.keyDown_2(key)
time.sleep(interval)
self.keyUp_2(key)
# 模拟一次组合键的输入,间隔值默认0.1S
def 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
大佬们找到问题欢迎拍砖~