I am trying to code a script that would adjust the view in a game after user clicks the mouse, and stop adjusting if mouse was released. To enable/disable my script I used a keyboard.Listener
from pynput
. To know when user clicks the mouse I tried using mouse.Listener
, but it caused me some problems, so I switched to pyWinhook.Hookmanager
and I can hook/unhook it with key bindings.
def left_down(event):
move(10, -10, 10, 0.15)
return True
hm = pyWinhook.HookManager()
hm.SubscribeMouseLeftDown(left_down)
def on_key_press(key):
if (key==keyboard.Key.f8):
try:
global hm
hm.HookMouse()
except MyException as e:
print('Exception: '.format(e.args[0]))
elif (key==keyboard.Key.f9):
hm.UnhookMouse()
elif (key==keyboard.Key.f10):
hm.UnhookMouse()
key_listener.stop()
with keyboard.Listener(on_press=on_key_press) as key_listener:
key_listener.join()
Everything worked fine, untill I tried to implement it with the code which simulates mouse movements in the game. To my understanding hook manager creates a deadlock when it calls move function which works using win32api
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
_fields_ = [("wVk", ctypes.c_ushort),
("wScan", ctypes.c_ushort),
("dwFlags", ctypes.c_ulong),
("time", ctypes.c_ulong),
("dwExtraInfo", PUL)]
class HardwareInput(ctypes.Structure):
_fields_ = [("uMsg", ctypes.c_ulong),
("wParamL", ctypes.c_short),
("wParamH", ctypes.c_ushort)]
class MouseInput(ctypes.Structure):
_fields_ = [("dx", ctypes.c_long),
("dy", ctypes.c_long),
("mouseData", ctypes.c_ulong),
("dwFlags", ctypes.c_ulong),
("time", ctypes.c_ulong),
("dwExtraInfo", PUL)]
class Input_I(ctypes.Union):
_fields_ = [("ki", KeyBdInput),
("mi", MouseInput),
("hi", HardwareInput)]
class Input(ctypes.Structure):
_fields_ = [("type", ctypes.c_ulong),
("ii", Input_I)]
def move(steps, x=None, y=None, duration=0.25, vertical=False):
x = int(x)
y = int(y)
coordinates = _interpolate_mouse_movement(
start_windows_coordinates=(0, 0),
end_windows_coordinates=(x, y)
)
for x, y in coordinates:
if (vertical):
x = 0
extra = ctypes.c_ulong(0)
ii_ = Input_I()
ii_.mi = MouseInput(x, y, 0, 0x0001, 0, ctypes.pointer(extra))
x = Input(ctypes.c_ulong(0), ii_)
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
time.sleep(duration / len(coordinates))
def _to_windows_coordinates(x=0, y=0):
display_width = win32api.GetSystemMetrics(0)
display_height = win32api.GetSystemMetrics(1)
windows_x = (x * 65535) // display_width
windows_y = (y * 65535) // display_height
return windows_x, windows_y
def _interpolate_mouse_movement(start_windows_coordinates, end_windows_coordinates, steps=10):
x_coordinates = [start_windows_coordinates[0], end_windows_coordinates[0]]
y_coordinates = [start_windows_coordinates[1], end_windows_coordinates[1]]
if x_coordinates[0] == x_coordinates[1]:
x_coordinates[1] += 1
if y_coordinates[0] == y_coordinates[1]:
y_coordinates[1] += 1
interpolation_func = scipy.interpolate.interp1d(x_coordinates, y_coordinates)
intermediate_x_coordinates = np.linspace(start_windows_coordinates[0], end_windows_coordinates[0], steps + 1)[1:]
coordinates = list(map(lambda x: (int(round(x)), int(interpolation_func(x))), intermediate_x_coordinates))
return coordinates
Another problem is that I have no idea how to create a functionality, when given series of movements are applied only while mouse is pressed and when its released, the whole cycle should reset.
Could You please help me solve these issues, or maybe offer a different way of approach based on the whole idea?