pymouse.click没有与其他软件连接

时间:2016-10-28 20:10:47

标签: python python-3.x input mouse

我过去曾使用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())

4 个答案:

答案 0 :(得分:2)

它使用内部调用SendInput的mouse_event

  

SendInput函数将输入事件插入与硬件设备相同的队列中,但事件标记为可由挂钩检测到的LLMHF_INJECTED标志。要避免这个标志,你可能需要编写一个自定义驱动程序。

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

答案 1 :(得分:2)

在没有使用虚拟机或编写自定义驱动程序的情况下,您可以选择一个选项。如果您为鼠标命令安装了一个钩子,那么您可以在将它们传递给下一个钩子之前更改该钩子中的标志。

由于windows如何对钩子进行排队,你需要将挂钩改变标志作为最后一个挂钩,所以在这个例子中你需要在安装钩子之前启动你的游戏。

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

nat_rec

剥离了将功能包装到线程类中的示例:

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 等待消息处理如WM_QUIT,因为这发生在C而不是python中,在线程中引发异常并不会导致它退出,我尝试了大量的组合例如SendMessage,PostMessage和PostThreadMessage尝试发送WM_QUIT消息但没有成功。而是设置守护进程标志,当主线程退出时强制它退出。

答案 2 :(得分:0)

尝试一下,它对我有用。


# -*- coding: UTF-8 -*-

import pyautogui as gui
from time import sleep
from threading import Thread

from pymouse import PyMouse


__author__ = 'lpe234'


def click(x, y):
    print(x, y)
    gui.click(x, y)


def main():
    # make sure the window is active. pyautogui.click can't active the window, don't know why
    PyMouse().click(489, 316)

    t = Thread(target=click, args=[400, 500])
    t.daemon = True
    t.start()
    sleep(5)


if __name__ == '__main__':
    main()


答案 3 :(得分:-1)

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

import win32gui



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