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