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

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

相关推荐
测开小菜鸟15 分钟前
使用python向钉钉群聊发送消息
java·python·钉钉
萧鼎2 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸2 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农2 小时前
Python 继承、多态、封装、抽象
开发语言·python
Python大数据分析@2 小时前
python操作CSV和excel,如何来做?
开发语言·python·excel
黑叶白树2 小时前
简单的签到程序 python笔记
笔记·python
Shy9604182 小时前
Bert完形填空
python·深度学习·bert
Jason-河山2 小时前
【自动化更新,让商品信息跳舞】——利用API返回值的幽默编程之旅
运维·自动化
上海_彭彭3 小时前
【提效工具开发】Python功能模块执行和 SQL 执行 需求整理
开发语言·python·sql·测试工具·element
zhongcx013 小时前
使用Python查找大文件的实用脚本
python