Python自动化(3)——鼠标模拟

Python自动化(3)——鼠标模拟

前台鼠标模拟

鼠标模拟和键盘模拟类似,也是分前台和后台模拟。话不多说直接,上代码:

import time
import win32api
import win32con
import win32gui
from ctypes import *

MOUSEEVENTF_LEFTDOWN = 0x2
MOUSEEVENTF_LEFTUP = 0x4
MOUSEEVENTF_MIDDLEDOWN = 0x20
MOUSEEVENTF_MIDDLEUP = 0x40 
MOUSEEVENTF_RIGHTDOWN = 0x8
MOUSEEVENTF_RIGHTUP = 0x10 
MOUSEEVENTF_MOVE = 0x1

class FrontstageMouse():
    def __init__(self):
        print('FrontstageMouse init')

    def bind(self, hwnd):
        self.hwnd = hwnd
    
    def getRelativePosition(self, x, y):
        left, top, right, bottom = win32gui.GetWindowRect(self.hwnd)
        return [left + x, top + y]

    # 前台模拟方法1——使用win32api.mouse_event(默认)  ############################################

    # 模拟鼠标的按键按下
    def clickDown(self, x, y, button="l"):
        win32api.SetCursorPos(self.getRelativePosition(int(x), int(y)))
        button = button.lower()
        if button == "l":
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0)
        elif button == "m":
            win32api.mouse_event(win32con.MOUSEEVENTF_MIDDLEDOWN,0,0,0,0)
        elif button == "r":
            win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN,0,0,0,0)
        print('clickDown x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标的按键抬起
    def clickUp(self, x, y, button="l"):
        win32api.SetCursorPos(self.getRelativePosition(int(x), int(y)))
        button = button.lower()
        if button == "l":
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0)
        elif button == "m":
            win32api.mouse_event(win32con.MOUSEEVENTF_MIDDLEUP,0,0,0,0)
        elif button == "r":
            win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP,0,0,0,0)
        print('clickUp x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标的点击
    def click(self, x, y, button="l", interval=0.1):
        win32api.SetCursorPos(self.getRelativePosition(int(x), int(y)))
        button = button.lower()
        if button == "l":
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0)
            time.sleep(interval)
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0)
        elif button == "m":
            win32api.mouse_event(win32con.MOUSEEVENTF_MIDDLEDOWN,0,0,0,0)
            time.sleep(interval)
            win32api.mouse_event(win32con.MOUSEEVENTF_MIDDLEUP,0,0,0,0)
        elif button == "r":
            win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN,0,0,0,0)
            time.sleep(interval)
            win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP,0,0,0,0)
        print('clicked x: ' + str(x) + ', y: ' + str(y))
 
    # 模拟鼠标的左键双击
    def doubleClick(self, x, y):
        win32api.SetCursorPos(self.getRelativePosition(int(x), int(y)))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0)
        time.sleep(0.05)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0)
        print('doubleClick x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标的左键拖动(即在第一个点按下,拖动至第二个点抬起
    # 但是,不知道为啥,实际上是不准的,滑动的值会比实际的多2倍左右,因此默认除以2
    # 有时候会误触导致滑动改成点击
    def slide(self, x1, y1, x2, y2):
        # win32api.SetCursorPos(self.getRelativePosition(int(x1), int(y1)))
        time.sleep(0.1)
        offsetX = int(x2)/2 - int(x1)/2
        offsetY = int(y2)/2 - int(y1)/2
        print("offsetX: " + str(offsetX))
        print("offsetY: " + str(offsetY))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0)
        time.sleep(0.1)
        win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, int(offsetX), int(offsetY))
        time.sleep(0.1)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0)
        print('slide x1: ' + str(x1) + ', y1: ' + str(y1) + ', x2: ' + str(x2) + ', y2: ' + str(y2))

    # 前台模拟方法2——使用ctypes  ############################################

    # 模拟鼠标的按键按下
    def clickDown_2(self, x, y, button="l"):
        win32api.SetCursorPos(self.getRelativePosition(int(x), int(y)))
        button = button.lower()
        if button == "l":
            windll.user32.mouse_event(MOUSEEVENTF_LEFTDOWN)
        elif button == "m":
            windll.user32.mouse_event(MOUSEEVENTF_MIDDLEDOWN)
        elif button == "r":
            windll.user32.mouse_event(MOUSEEVENTF_RIGHTDOWN)
        print('clickDown_2 x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标的按键抬起
    def clickUp_2(self, x, y, button="l"):
        win32api.SetCursorPos(self.getRelativePosition(int(x), int(y)))
        button = button.lower()
        if button == "l":
            windll.user32.mouse_event(MOUSEEVENTF_LEFTUP)
        elif button == "m":
            windll.user32.mouse_event(MOUSEEVENTF_MIDDLEUP)
        elif button == "r":
            windll.user32.mouse_event(MOUSEEVENTF_RIGHTUP)
        print('clickUp_2 x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标左键单击
    def click_2(self, x, y, button='l', interval=0.05):
        win32api.SetCursorPos(self.getRelativePosition(int(x), int(y)))
        button = button.lower()
        if button == "l":
            windll.user32.mouse_event(MOUSEEVENTF_LEFTDOWN)
            time.sleep(interval)
            windll.user32.mouse_event(MOUSEEVENTF_LEFTUP)
        elif button == "m":
            windll.user32.mouse_event(MOUSEEVENTF_MIDDLEDOWN)
            time.sleep(interval)
            windll.user32.mouse_event(MOUSEEVENTF_MIDDLEUP)
        elif button == "r":
            windll.user32.mouse_event(MOUSEEVENTF_RIGHTDOWN)
            time.sleep(interval)
            windll.user32.mouse_event(MOUSEEVENTF_RIGHTUP)
        print('clicked_2 x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标的左键双击
    def doubleClick_2(self, x, y):
        win32api.SetCursorPos(self.getRelativePosition(int(x), int(y)))
        windll.user32.mouse_event(MOUSEEVENTF_LEFTDOWN)
        time.sleep(0.05)
        windll.user32.mouse_event(MOUSEEVENTF_LEFTUP)
        time.sleep(0.05)
        windll.user32.mouse_event(MOUSEEVENTF_LEFTDOWN)
        time.sleep(0.05)
        windll.user32.mouse_event(MOUSEEVENTF_LEFTUP)
        print('doubleClick_2 x: ' + str(x) + ', y: ' + str(y))

    def slide_2(self, x1, y1, x2, y2):
        # win32api.SetCursorPos(self.getRelativePosition(int(x1), int(y1)))
        time.sleep(0.1)
        offsetX = int(x2)/2 - int(x1)/2
        offsetY = int(y2)/2 - int(y1)/2
        print("offsetX: " + str(offsetX))
        print("offsetY: " + str(offsetY))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0)
        time.sleep(0.1)
        win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, int(offsetX), int(offsetY))
        time.sleep(0.1)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0)
        print('slide x1: ' + str(x1) + ', y1: ' + str(y1) + ', x2: ' + str(x2) + ', y2: ' + str(y2))

这里使用了两个不同的库分别实现,分别是win32api和ctypes库。win32库实际上也是实现鼠标后台模拟的关键,也可以实现前台模拟,使用mouse_event方法。
其中,win32api中mouse_event的函数原型:
VOID mouse_event(DWORD dwFlags,DWORD dx,DWORD dwFlags,OWORD dx,DWORD dy, DWORD dwData, DWORD dwExtralnfo);
dwFlags:标志位集,指定点击按钮和鼠标动作的多种情况。此参数里的各位可以是下列值的任何合理组合:
MOOSE_EVENTF_ABSOLOTE:表明参数dX,dy含有规范化的绝对坐标。如果不设置此位,参数含有相对数据:相对于上次位置的改动位置。此标志可被设置,也可不设置,不管鼠标的类型或与系统相连的类似于鼠标的设备的类型如何。要得到关于相对鼠标动作的信息,参见下面备注部分。
MOOSEEVENTFMOVE:表明发生移动。
M00SEEVENTF_LEFTDOWN:表明接按下鼠标左键。
M00SEEVENTF_LEFTUP:表明松开鼠标左键。
MOOSEEVENTF_RIGHTDOWN:表明按下鼠标右键。
MOOSEEVENTF_RIGHTUP:表明松开鼠标右键。
MOOSEEVENTF_MIDDLEDOWN:表明按下鼠标中键。
MOOSEEVENTF_MIDDLEUP:表明松开鼠标中键。
MOOSEEVENTF_WHEEL:在Windows NT中如果鼠标有一个轮,表明鼠标轮被移动。移动的数量由dwData给出。
dx:指定鼠标沿x轴的绝对位置或者从上次鼠标事件产生以来移动的数量,依赖于MOOSEEVENTF_ABSOLOTE的设置。给出的绝对数据作为鼠标的实际X坐标;给出的相对数据作为移动的mickeys数。一个mickey表示鼠标移动的数量,表明鼠标已经移动。
dy:指定鼠标沿y轴的绝对位置或者从上次鼠标事件产生以来移动的数量,依赖于MOOSEEVENTF_ABSOLVTE的设置。给出的绝对数据作为鼠标的实际y坐标,给出的相对数据作为移动的mickeys数。
dwData:如果dwFlags为MOOSEEVENTF_WHEEL,则dwData指定鼠标轮移动的数量。正值表明鼠标轮向前转动,即远离用户的方向;负值表明鼠标轮向后转动,即朝向用户。一个轮击定义为WHEEL_DELTA,即120。
如果dwFlagsS不是MOOSEEVENTF_WHEEL,则dWData应为零。
dwExtralnfo:指定与鼠标事件相关的附加32位值。应用程序调用函数GetMessgeExtrajnfo来获得此附加信息。
返回值:无。

后台鼠标模拟

import time
import win32api
import win32con
import win32com
import win32gui
import pythoncom
import math

class BackstageMouse():
    def __init__(self):
        print('BackstageMouse init')

    def bind(self, hwnd):
        self.hwnd = hwnd

    # 聚焦句柄对应的窗口
    def focusHwnd(self):
        pythoncom.CoInitialize()
        shell = win32com.client.Dispatch("WScript.Shell")
        shell.SendKeys('%')
        win32gui.SetForegroundWindow(self.hwnd)

    # 后台模拟方法1——使用SendMessage(默认)  ############################################

    # 模拟鼠标的移动
    def move(self, x, y):
        point = win32api.MAKELONG(int(x), int(y))
        win32api.SendMessage(self.hwnd, win32con.WM_MOUSEMOVE, win32con.MK_LBUTTON, point)

    # 模拟鼠标的按键按下
    def clickDown(self, x, y, button="l"):
        point = win32api.MAKELONG(int(x), int(y))
        button = button.lower()
        if button == "l":
            win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, point)
        elif button == "m":
            win32api.SendMessage(self.hwnd, win32con.WM_MBUTTONDOWN, win32con.MK_MBUTTON, point)
        elif button == "r":
            win32api.SendMessage(self.hwnd, win32con.WM_RBUTTONDOWN, win32con.MK_RBUTTON, point)
        print('clickDown x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标的按键抬起
    def clickUp(self, x, y, button="l"):
        point = win32api.MAKELONG(int(x), int(y))
        button = button.lower()
        if button == "l":
            win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, point)
        elif button == "m":
            win32api.SendMessage(self.hwnd, win32con.WM_MBUTTONUP, win32con.MK_MBUTTON, point)
        elif button == "r":
            win32api.SendMessage(self.hwnd, win32con.WM_RBUTTONUP, win32con.MK_RBUTTON, point)
        print('clickUp x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标的点击
    def click(self, x, y, button="l", interval=0.1):
        point = win32api.MAKELONG(int(x), int(y))
        button = button.lower()
        if button == "l":
            win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, point)
            time.sleep(interval)
            win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, point)
        elif button == "m":
            win32api.SendMessage(self.hwnd, win32con.WM_MBUTTONDOWN, win32con.MK_MBUTTON, point)
            time.sleep(interval)
            win32api.SendMessage(self.hwnd, win32con.WM_MBUTTONUP, win32con.MK_MBUTTON, point)
        elif button == "r":
            win32api.SendMessage(self.hwnd, win32con.WM_RBUTTONDOWN, win32con.MK_RBUTTON, point)
            time.sleep(interval)
            win32api.SendMessage(self.hwnd, win32con.WM_RBUTTONUP, win32con.MK_RBUTTON, point)
        print('clicked x: ' + str(x) + ', y: ' + str(y))
 
    # 模拟鼠标的左键双击
    def doubleClick(self, x, y):
        point = win32api.MAKELONG(int(x), int(y))
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONDBLCLK, win32con.MK_LBUTTON, point)
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, point)
        print('doubleClick x: ' + str(x) + ', y: ' + str(y))
 
    # 模拟鼠标移动到坐标,并进行左键单击
    def moveToPosClick(self, x, y):
        point = win32api.MAKELONG(int(x), int(y))
        win32api.SendMessage(self.hwnd, win32con.WM_MOUSEMOVE, win32con.MK_LBUTTON, point)
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, point)
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, point)
        print('moveToPosClick x: ' + str(x) + ', y: ' + str(y))
 
    # 模拟鼠标移动到坐标,并进行左键双击
    def moveToPosDoubleClick(self, x, y):
        point = win32api.MAKELONG(int(x), int(y))
        win32api.SendMessage(self.hwnd, win32con.WM_MOUSEMOVE, win32con.MK_LBUTTON, point)
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONDBLCLK, win32con.MK_LBUTTON, point)
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, point)
        print('moveToPosDoubleClick x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标使用滚轮向上滚动
    # 需要聚焦到窗口
    def wheelUp(self, x, y):
        self.focusHwnd()
        point = win32api.MAKELONG(int(x), int(y))
        win32api.SendMessage(self.hwnd, win32con.WM_MOUSEWHEEL, win32con.WHEEL_DELTA * 5, point)
        print('wheelDown x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标使用滚轮向下滚动
    # 需要聚焦到窗口
    def wheelDown(self, x, y):
        self.focusHwnd()
        point = win32api.MAKELONG(int(x), int(y))
        win32api.SendMessage(self.hwnd, win32con.WM_MOUSEWHEEL, win32con.MK_LBUTTON, point)
        print('wheelDown x: ' + str(x) + ', y: ' + str(y))

    # 模拟鼠标的左键拖动(即在第一个点按下,拖动至第二个点抬起)
    # @step 步长,模拟拖动会将一个操作分开多次来模拟,次数=拖动的长度/步长
    # @delay 拖动时间,默认0.5秒
    # @isNeedBtnUp 是否需要弹起鼠标,默认是,若不弹起可通过多次调用实现轨迹拖动
    def slide(self, x1, y1, x2, y2, isNeedBtnUp=True, step=20, delay=0.5):
        offsetX = x2-x1
        offsetY = y2-y1
        count = int(math.sqrt(offsetX*offsetX + offsetY*offsetY) / step)
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, win32api.MAKELONG(int(x1), int(y1)))
        for i in range(count):
            point2 = win32api.MAKELONG(int(x1+offsetX/count*(i+1)), int(y1+offsetY/count*(i+1)))
            win32api.SendMessage(self.hwnd, win32con.WM_MOUSEMOVE, win32con.MK_LBUTTON, point2)
            time.sleep(delay/count)
        if isNeedBtnUp:
            win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, 0, point2)
        print('slide x1: ' + str(x1) + ', y1: ' + str(y1) + ', x2: ' + str(x2) + ', y2: ' + str(y2))

这里同样使用win32api的SendMessage方法来实现鼠标的后台模拟,此方法的原型在键盘模拟中提过了,这里不再复述。

使用后台键盘模拟,需要绑定窗口句柄,关于窗口句柄的获取,可以看看下面这篇文章:Python自动化(1)——获取窗口句柄

完整自动化工程代码:https://gitee.com/chj-self/PythonRobotization

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

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值