Python自动化(2)——键盘模拟

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

大佬们找到问题欢迎拍砖~

相关推荐
ROBOT玲玉14 分钟前
Milvus 中,FieldSchema 的 dim 参数和索引参数中的 “nlist“ 的区别
python·机器学习·numpy
Kai HVZ1 小时前
python爬虫----爬取视频实战
爬虫·python·音视频
古希腊掌管学习的神1 小时前
[LeetCode-Python版]相向双指针——611. 有效三角形的个数
开发语言·python·leetcode
m0_748244831 小时前
StarRocks 排查单副本表
大数据·数据库·python
B站计算机毕业设计超人1 小时前
计算机毕业设计PySpark+Hadoop中国城市交通分析与预测 Python交通预测 Python交通可视化 客流量预测 交通大数据 机器学习 深度学习
大数据·人工智能·爬虫·python·机器学习·课程设计·数据可视化
路人甲ing..1 小时前
jupyter切换内核方法配置问题总结
chrome·python·jupyter
沛沛老爹1 小时前
什么是 DevOps 自动化?
大数据·ci/cd·自动化·自动化运维·devops
游客5202 小时前
opencv中的常用的100个API
图像处理·人工智能·python·opencv·计算机视觉
永恒,怎么可能2 小时前
关于博客系统的自动化功能测试报告
自动化·测试
每天都要学信号2 小时前
Python(第一天)
开发语言·python