【问题标题】:python win32 simulate clickpython win32模拟点击
【发布时间】:2011-02-27 04:31:08
【问题描述】:

假设我有一个要模拟鼠标点击的窗口 在特定的 x,y 坐标处。我已经有了 hwnd 但我不确定 如何构造 lParam。我过去使用过 SendMessage 来点击 在按钮等,但我知道他们的 hwnds。 任何帮助将不胜感激。我也忍不住想知道如果 我正在以正确的方式解决这个问题。我的最终目标是点击某个 Skype 主窗口上的用户(例如)。我用 EnumChildWindows 找到所有主窗口的孩子,但找不到合适的。所以 想我会尝试使用坐标“点击”它。

【问题讨论】:

    标签: python winapi


    【解决方案1】:

    我觉得这对你有好处,你可以直接使用或者导入到你的python程序中。

    """mousemacro.py defines the following functions:
    
    click() -- calls left mouse click
    hold() -- presses and holds left mouse button
    release() -- releases left mouse button
    
    rightclick() -- calls right mouse click
    righthold() -- calls right mouse hold
    rightrelease() -- calls right mouse release
    
    middleclick() -- calls middle mouse click
    middlehold() -- calls middle mouse hold
    middlerelease() -- calls middle mouse release
    
    move(x,y) -- moves mouse to x/y coordinates (in pixels)
    getpos() -- returns mouse x/y coordinates (in pixels)
    slide(x,y) -- slides mouse to x/y coodinates (in pixels)
                  also supports optional speed='slow', speed='fast'
    """
    
    from ctypes import*
    from ctypes.wintypes import *
    from time import sleep
    import win32ui
    
    __all__ = ['click', 'hold', 'release', 'rightclick', 'righthold', 'rightrelease', 'middleclick', 'middlehold', 'middlerelease', 'move', 'slide', 'getpos']
    
    # START SENDINPUT TYPE DECLARATIONS
    PUL = POINTER(c_ulong)
    
    class KeyBdInput(Structure):
        _fields_ = [("wVk", c_ushort),
                 ("wScan", c_ushort),
                 ("dwFlags", c_ulong),
                 ("time", c_ulong),
                 ("dwExtraInfo", PUL)]
    
    class HardwareInput(Structure):
        _fields_ = [("uMsg", c_ulong),
                 ("wParamL", c_short),
                 ("wParamH", c_ushort)]
    
    class MouseInput(Structure):
        _fields_ = [("dx", c_long),
                 ("dy", c_long),
                 ("mouseData", c_ulong),
                 ("dwFlags", c_ulong),
                 ("time",c_ulong),
                 ("dwExtraInfo", PUL)]
    
    class Input_I(Union):
        _fields_ = [("ki", KeyBdInput),
                  ("mi", MouseInput),
                  ("hi", HardwareInput)]
    
    class Input(Structure):
        _fields_ = [("type", c_ulong),
                 ("ii", Input_I)]
    
    class POINT(Structure):
        _fields_ = [("x", c_ulong),
                 ("y", c_ulong)]
    # END SENDINPUT TYPE DECLARATIONS
    
      #  LEFTDOWN   = 0x00000002,
      #  LEFTUP     = 0x00000004,
      #  MIDDLEDOWN = 0x00000020,
      #  MIDDLEUP   = 0x00000040,
      #  MOVE       = 0x00000001,
      #  ABSOLUTE   = 0x00008000,
      #  RIGHTDOWN  = 0x00000008,
      #  RIGHTUP    = 0x00000010
    
    MIDDLEDOWN = 0x00000020
    MIDDLEUP   = 0x00000040
    MOVE       = 0x00000001
    ABSOLUTE   = 0x00008000
    RIGHTDOWN  = 0x00000008
    RIGHTUP    = 0x00000010
    
    
    FInputs = Input * 2
    extra = c_ulong(0)
    
    click = Input_I()
    click.mi = MouseInput(0, 0, 0, 2, 0, pointer(extra))
    release = Input_I()
    release.mi = MouseInput(0, 0, 0, 4, 0, pointer(extra))
    
    x = FInputs( (0, click), (0, release) )
    #user32.SendInput(2, pointer(x), sizeof(x[0])) CLICK & RELEASE
    
    x2 = FInputs( (0, click) )
    #user32.SendInput(2, pointer(x2), sizeof(x2[0])) CLICK & HOLD
    
    x3 = FInputs( (0, release) )
    #user32.SendInput(2, pointer(x3), sizeof(x3[0])) RELEASE HOLD
    
    
    def move(x,y):
        windll.user32.SetCursorPos(x,y)
    
    def getpos():
        global pt
        pt = POINT()
        windll.user32.GetCursorPos(byref(pt))
        return pt.x, pt.y
    
    def slide(a,b,speed=0):
        while True:
            if speed == 'slow':
                sleep(0.005)
                Tspeed = 2
            if speed == 'fast':
                sleep(0.001)
                Tspeed = 5
            if speed == 0:
                sleep(0.001)
                Tspeed = 3
    
            x = getpos()[0]
            y = getpos()[1]
            if abs(x-a) < 5:
                if abs(y-b) < 5:
                    break
    
            if a < x:
                x -= Tspeed
            if a > x:
                x += Tspeed
            if b < y:
                y -= Tspeed
            if b > y:
                y += Tspeed
            move(x,y)
    
    
    def click():
        windll.user32.SendInput(2,pointer(x),sizeof(x[0]))
    
    def hold():
        windll.user32.SendInput(2, pointer(x2), sizeof(x2[0]))
    
    def release():
        windll.user32.SendInput(2, pointer(x3), sizeof(x3[0]))
    
    
    def rightclick():
        windll.user32.mouse_event(RIGHTDOWN,0,0,0,0)
        windll.user32.mouse_event(RIGHTUP,0,0,0,0)
    
    def righthold():
        windll.user32.mouse_event(RIGHTDOWN,0,0,0,0)
    
    def rightrelease():
        windll.user32.mouse_event(RIGHTUP,0,0,0,0)
    
    
    def middleclick():
        windll.user32.mouse_event(MIDDLEDOWN,0,0,0,0)
        windll.user32.mouse_event(MIDDLEUP,0,0,0,0)
    
    def middlehold():
        windll.user32.mouse_event(MIDDLEDOWN,0,0,0,0)
    
    def middlerelease():
        windll.user32.mouse_event(MIDDLEUP,0,0,0,0)
    
    
    if __name__ == "__main__":
        speed = 10
        for i in range(1000//speed):
            move(i*speed, i*speed)
            sleep(0.01)
    

    【讨论】:

    • 这太棒了!谢谢。
    • 看起来不错,但在更改之前不要尝试代码,因为您将失去对鼠标的控制。
    • 你是上帝.. 非常感谢.. 你能帮忙扩展一下鼠标左键单击和按钮单击吗?
    【解决方案2】:

    感谢 ctypes,您可以使用低级 windows api。看下面的例子(改编自我没有测试过的东西,但应该没问题)

    import ctypes
    MOUSEEVENTF_MOVE = 0x0001 # mouse move
    MOUSEEVENTF_ABSOLUTE = 0x8000 # absolute move
    MOUSEEVENTF_MOVEABS = MOUSEEVENTF_MOVE + MOUSEEVENTF_ABSOLUTE
    
    MOUSEEVENTF_LEFTDOWN = 0x0002 # left button down 
    MOUSEEVENTF_LEFTUP = 0x0004 # left button up 
    MOUSEEVENTF_CLICK = MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP
    
    def click(x, y):
        #move first
        x = 65536L * x / ctypes.windll.user32.GetSystemMetrics(0) + 1
        y = 65536L * y / ctypes.windll.user32.GetSystemMetrics(1) + 1
        ctypes.windll.user32.mouse_event(MOUSEEVENTF_MOVEABS, x, y, 0, 0)
    
        #then click
        ctypes.windll.user32.mouse_event(MOUSEEVENTF_CLICK, 0, 0, 0, 0)
    

    更新: 我没有测试下面的代码,但我认为它应该可以帮助你写一些东西来获得孩子的位置。然后你可以尝试点击正确的位置。

    CHILD= None
    
    def the_callback(child_hwnd, regex):
        '''Pass to win32gui.EnumWindows() to check all the opened windows'''
        if re.match(regex, win32gui.GetWindowText(child_hwnd)):
            CHILD= child_hwnd
    
    win32gui.EnumChildWindows(hwnd, the_callback, regex)
    
    
    if CHILD:
        (x_tl, y_tl, x_br, y_br) = win32gui.GetWindowRect(CHILD)
    

    【讨论】:

    • 您好,感谢您的快速回复。顺便说一句,你可以说你有 hwnd 的主窗口和一堆他的孩子窗口也有他们的 hwnds ......你知道我怎么能在所有这些孩子身上寻找一些特定的文本内容吗?并确定正确的,以便我可以单击此文本(链接)? ...
    • 嗯,如果我错了,请纠正我,但 *.GetWindowText 只返回窗口的标题。这对我来说是新事物,我不知道它到底是如何工作的,但我认为无论何时打开某个复杂应用程序(例如 photoshop)的窗口,您都会得到主要的 hwnd 和一堆子窗口(它们没有标题)所以在首先,您必须找到一个特定的子窗口,例如使用一些随机生成的链接进行操作,然后您可以单击它...我不知道它是否正确,我在这里失明
    • GetWindowText 返回标题。您也可以使用 GetClassName 来查找窗口。您可能需要像 spy++ 这样的工具来找到正确的方法来定位您的窗口。
    猜你喜欢
    • 2011-04-12
    • 1970-01-01
    • 2015-06-28
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-26
    • 2012-11-06
    相关资源
    最近更新 更多