【问题标题】:pymouse.click not interfacing with other softwarepymouse.click 不与其他软件交互
【发布时间】:2016-10-28 20:10:47
【问题描述】:

我过去曾使用 pymouse 帮助自动化重复游戏并取得了成功。

但是,当玩在BlueStacks 上下载的游戏时,pymouse 会出现移动到屏幕上的正确位置,但随后不会“注册”任何点击。

如果我将操作系统本地的其他内容放在同一位置,它将被点击。我不明白为什么在这种情况下,当我将鼠标移动到 Bluestacks 中正在玩的游戏上方的某个位置时,点击不起作用。

代码如下:

from pymouse import PyMouse
import time

m = PyMouse()

i=1
for i in range(1,1000):
        time.sleep(2)
        x, y = m.position()
        print(x, y)
        m.click(x,y,1)
        i+=1

即使鼠标从 Bluestacks 悬停在窗口上,这个(下)也会返回值。

print(m.position())

【问题讨论】:

  • 我也有同样的问题。你找到解决办法了吗?
  • 首先创建一个新进程,当对象点击事件发生时(最顶层)处于活动状态的窗口将是最后触发的应用程序。您需要在系统中进行单击处理或两次单击而不是单击一次(激活窗口>>单击操作)。

标签: python python-3.x input mouse


【解决方案1】:

有一个选项可供您选择,无需借助虚拟机或编写自定义驱动程序。如果你为鼠标命令安装了一个钩子,你就可以在将它们传递给下一个钩子之前更改该钩子中的标志。

由于 windows 如何对钩子进行排队,您需要钩子将标志更改为最后注册的钩子,因此在此示例中,您需要在安装钩子之前启动游戏。

下面是一些示例代码,我使用 pyHook 对其进行了测试以检查结果。出于您的目的,您可能希望将其包装在一个线程中,以便它在后台发生。

import atexit
import ctypes
import time
from ctypes import c_short, c_char, c_uint8, c_int32, c_int, c_uint, c_uint32, c_long, byref, Structure, CFUNCTYPE, POINTER
from ctypes.wintypes import DWORD, BOOL, HHOOK, MSG, LPWSTR, WCHAR, WPARAM, LPARAM
from collections import namedtuple
LPMSG = POINTER(MSG)

user32 = ctypes.WinDLL('user32', use_last_error = True)

class MSLLHOOKSTRUCT(Structure):
    _fields_ = [("x", c_long),
                ("y", c_long),
                ('data', c_int32),
                ("flags", DWORD),
                ("time", c_int),
                ('extrainfo', c_int32),
                ]

LowLevelMouseProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(MSLLHOOKSTRUCT))

SetWindowsHookEx = user32.SetWindowsHookExA
#SetWindowsHookEx.argtypes = [c_int, LowLevelMouseProc, c_int, c_int]
SetWindowsHookEx.restype = HHOOK

CallNextHookEx = user32.CallNextHookEx
#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(MSLLHOOKSTRUCT)]
CallNextHookEx.restype = c_int

UnhookWindowsHookEx = user32.UnhookWindowsHookEx
UnhookWindowsHookEx.argtypes = [HHOOK]
UnhookWindowsHookEx.restype = BOOL

GetMessage = user32.GetMessageW
GetMessage.argtypes = [LPMSG, c_int, c_int, c_int]
GetMessage.restype = BOOL

TranslateMessage = user32.TranslateMessage
TranslateMessage.argtypes = [LPMSG]
TranslateMessage.restype = BOOL

DispatchMessage = user32.DispatchMessageA
DispatchMessage.argtypes = [LPMSG]

# Beware, as of 2016-01-30 the official docs have a very incomplete list.
# This one was compiled from experience and may be incomplete.
WM_MOUSEMOVE = 0x200
WM_LBUTTONDOWN = 0x201
WM_LBUTTONUP = 0x202
WM_LBUTTONDBLCLK = 0x203
WM_RBUTTONDOWN = 0x204
WM_RBUTTONUP = 0x205
WM_RBUTTONDBLCLK = 0x206
WM_MBUTTONDOWN = 0x207
WM_MBUTTONUP = 0x208
WM_MBUTTONDBLCLK = 0x209
WM_MOUSEWHEEL = 0x20A
WM_XBUTTONDOWN = 0x20B
WM_XBUTTONUP = 0x20C
WM_XBUTTONDBLCLK = 0x20D
WM_NCXBUTTONDOWN = 0x00AB
WM_NCXBUTTONUP = 0x00AC
WM_NCXBUTTONDBLCLK = 0x00AD
WM_MOUSEHWHEEL = 0x20E
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_MOUSEMOVE = 0x0200
WM_MOUSEWHEEL = 0x020A
WM_MOUSEHWHEEL = 0x020E
WM_RBUTTONDOWN = 0x0204
WM_RBUTTONUP = 0x0205

LEFT = 'left'
RIGHT = 'right'
MIDDLE = 'middle'
X = 'x'

UP = 'up'
DOWN = 'down'
DOUBLE = 'double'

buttons_by_wm_code = {
    WM_LBUTTONDOWN: (DOWN, LEFT),
    WM_LBUTTONUP: (UP, LEFT),
    WM_LBUTTONDBLCLK: (DOUBLE, LEFT),

    WM_RBUTTONDOWN: (DOWN, RIGHT),
    WM_RBUTTONUP: (UP, RIGHT),
    WM_RBUTTONDBLCLK: (DOUBLE, RIGHT),

    WM_MBUTTONDOWN: (DOWN, MIDDLE),
    WM_MBUTTONUP: (UP, MIDDLE),
    WM_MBUTTONDBLCLK: (DOUBLE, MIDDLE),

    WM_XBUTTONDOWN: (DOWN, X),
    WM_XBUTTONUP: (UP, X),
    WM_XBUTTONDBLCLK: (DOUBLE, X),
}

NULL = c_int(0)

def translate_injected_mouse():
    def low_level_mouse_handler(nCode, wParam, lParam):
        struct = lParam.contents

        if wParam in buttons_by_wm_code:
            struct.flags &= 0x11111100 # clear the injected flags
        return CallNextHookEx(NULL, nCode, wParam, lParam)

    WH_MOUSE_LL = c_int(14)
    mouse_callback = LowLevelMouseProc(low_level_mouse_handler)
    mouse_hook = SetWindowsHookEx(WH_MOUSE_LL, mouse_callback, user32._handle, NULL)

    # Register to remove the hook when the interpreter exits. Unfortunately a
    # try/finally block doesn't seem to work here.
    atexit.register(UnhookWindowsHookEx, mouse_hook)

    msg = LPMSG()
    while not GetMessage(msg, NULL, NULL, NULL):
        TranslateMessage(msg)
        DispatchMessage(msg)

if __name__ == '__main__':
    translate_injected_mouse()

将功能包装到线程类中的精简示例:

import atexit
import ctypes
from ctypes import c_int, c_uint, c_uint32, c_long, Structure, CFUNCTYPE, POINTER
from ctypes.wintypes import DWORD, BOOL, HWND, HHOOK, MSG, WPARAM, LPARAM
import threading

LPMSG = POINTER(MSG)

user32 = ctypes.WinDLL('user32', use_last_error = True)

class MSLLHOOKSTRUCT(Structure):
    _fields_ = [("x", c_long), ("y", c_long),
                ('data', c_uint32), ("flags", DWORD),
                ("time", c_int), ('extrainfo', c_uint32), ]

LowLevelMouseProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(MSLLHOOKSTRUCT))

SetWindowsHookEx = user32.SetWindowsHookExA
#SetWindowsHookEx.argtypes = [c_int, LowLevelMouseProc, c_int, c_int]
SetWindowsHookEx.restype = HHOOK

CallNextHookEx = user32.CallNextHookEx
#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(MSLLHOOKSTRUCT)]
CallNextHookEx.restype = c_int

UnhookWindowsHookEx = user32.UnhookWindowsHookEx
UnhookWindowsHookEx.argtypes = [HHOOK]
UnhookWindowsHookEx.restype = BOOL

GetMessage = user32.GetMessageW
GetMessage.argtypes = [LPMSG, c_int, c_int, c_int]
GetMessage.restype = BOOL

TranslateMessage = user32.TranslateMessage
TranslateMessage.argtypes = [LPMSG]
TranslateMessage.restype = BOOL

DispatchMessage = user32.DispatchMessageA
DispatchMessage.argtypes = [LPMSG]

NULL = c_int(0)

class TranslateInjectedMouse(threading.Thread):
    daemon=True
    def run(self):
        def low_level_mouse_handler(nCode, wParam, lParam):
            print("handler")
            lParam.contents.flags &= 0x11111100
            return CallNextHookEx(NULL, nCode, wParam, lParam)

        WH_MOUSE_LL = c_int(14)
        mouse_callback = LowLevelMouseProc(low_level_mouse_handler)
        self.mouse_hook = SetWindowsHookEx(WH_MOUSE_LL, mouse_callback, user32._handle, NULL)

        # Register to remove the hook when the interpreter exits. Unfortunately a
        # try/finally block doesn't seem to work here.
        atexit.register(UnhookWindowsHookEx, self.mouse_hook)

        msg = LPMSG()
        while not GetMessage(msg, NULL, NULL, NULL):
            TranslateMessage(msg)
            DispatchMessage(msg)

    def stop(self):
        UnhookWindowsHookEx(self.mouse_hook)

if __name__ == '__main__':
    # this is all you need to translate in background
    t = TranslateInjectedMouse()
    t.start()

    # below this is test code to create clicks
    import time
    mouse_event = user32.mouse_event
    MOUSEEVENTF_LEFTDOWN = 0x0002
    MOUSEEVENTF_LEFTUP = 0x0004

    while True:
        try:
            time.sleep(1)
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)

            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
        except KeyboardInterrupt:
            if t.is_alive():
                t.stop()
            else:
                break

请注意,目前我找不到在命令中杀死该线程的方法。 GetMessage处的线程执行块等待消息处理,例如WM_QUIT,因为这发生在C而不是python中,在线程中引发异常不会导致它退出,我尝试了大量的组合,例如SendMessage、PostMessage 和 PostThreadMessage 尝试发送 WM_QUIT 消息但没有成功。而是设置了守护进程标志,当主线程退出时强制它退出。

【讨论】:

    【解决方案2】:

    它使用mouse_event,它在内部调用了SendInput。

    SendInput 函数会将输入事件插入到与硬件设备相同的队列中,但这些事件标有 LLMHF_INJECTED 标志,可以通过挂钩检测到。为避免此标志,您可能必须编写自定义驱动程序。

    对于您的特殊情况,我认为您可以使用SetWindowsHookEx 清除标志。 但为了方便使用,只需使用 VMware。请参阅此post

    【讨论】:

      【解决方案3】:

      试试这个,它对我有用。

      # -*- 编码:UTF-8 -*- 将 pyautogui 导入为 gui 从时间导入睡眠 从线程导入线程 从 pymouse 导入 PyMouse __author__ = 'lpe234' 默认点击(x,y): 打印(x,y) gui.click(x, y) 定义主(): # 确保窗口处于活动状态。 pyautogui.click 无法激活窗口,不知道为什么 PyMouse().click(489, 316) t = 线程(目标 = 点击,参数 = [400, 500]) t.daemon = 真 t.start() 睡觉(5) 如果 __name__ == '__main__': 主要的()

      【讨论】:

        【解决方案4】:

        如果你使用 pywin32 库, 在执行点击之前,您可以轻松地将应用程序窗口置于顶部

        import win32gui
        
        
        
        bluestacks_hwnd=win32gui.FindWindow(None,"bluestacks")
        win32gui.BringWindowToTop(bluestacks_hwnd)
        ...
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-01-23
          • 1970-01-01
          • 1970-01-01
          • 2012-11-25
          • 2012-12-26
          • 1970-01-01
          • 2014-02-18
          相关资源
          最近更新 更多