Пытаетесь создать диктофон мыши, но он продолжает бесконечно зацикливаться? - PullRequest
3 голосов
/ 02 июня 2019

Я пробую свои силы в Pynput, и я начинаю с создания простой программы, которая записывает движения мыши, а затем воспроизводит эти движения после нажатия кнопки.

Однако каждый раз, когда я щелкаю мышью, она просто начинает волноваться и бесконечно зацикливаться. Я думаю, что он проходит через движения на супер высокой скорости, но мне в конечном итоге придется Alt-F4 снаряд, чтобы остановить его.

Любая помощь будет оценена.

import pynput

arr = []

from pynput import mouse

mou = pynput.mouse.Controller()

def on_move(x,y):
    Pos = mou.position
    arr.append(Pos)

def on_click(x, y, button, pressed):
    listener.stop()
    for i in arr:
        mou.position = i
    print("Done")

listener = mouse.Listener(on_move = on_move, on_click=on_click)
listener.start()

Ответы [ 2 ]

1 голос
/ 03 июня 2019

Вы должны быть осторожны при использовании нескольких потоков (в данном случае, поскольку mouse.Listener работает в своем собственном потоке).Очевидно, что пока вы находитесь в функции обратного вызова, все события все еще обрабатываются, даже после того, как вы вызвали listener.stop().Таким образом, при воспроизведении для каждой установленной позиции мыши вызывается функция обратного вызова on_move, поэтому позиция мыши снова добавляется в ваш список, что вызывает бесконечный цикл.

В общем, это плохая практикареализовать слишком много функций (в данном случае «воспроизведение») в функции обратного вызова.Лучшим решением было бы использовать событие, чтобы сообщить другому потоку, что кнопка мыши нажата.Смотрите следующий пример кода.Несколько замечаний:

  • Я добавил несколько операторов печати, чтобы увидеть, что происходит.
  • Я добавил небольшую задержку между позициями мыши, чтобы действительно увидеть воспроизведение.(NB: Это также может облегчить выход из приложения в случае зависания!)
  • Я изменил несколько имен переменных, чтобы сделать их более понятными.Называть массив "arr" не очень хорошая идея.Попробуйте использовать имена, которые действительно описывают переменную.В данном случае это список позиций, поэтому я решил назвать его positions.
  • Я использую return False, чтобы остановить контроллер мыши.Документация гласит: «Позвоните pynput.mouse.Listener.stop откуда угодно, поднимите StopException или верните False из обратного вызова, чтобы остановить слушателя», но лично я считаю, что возвращение False - самое чистое и безопасное решение.
import threading
import time

import pynput

positions = []
clicked = threading.Event()
controller = pynput.mouse.Controller()


def on_move(x, y):
    print(f'on_move({x}, {y})')
    positions.append((x, y))


def on_click(x, y, button, pressed):
    print(f'on_move({x}, {y}, {button}, {pressed})')
    # Tell the main thread that the mouse is clicked
    clicked.set()
    return False


listener = pynput.mouse.Listener(on_move=on_move, on_click=on_click)
listener.start()
try:
    listener.wait()
    # Wait for the signal from the listener thread
    clicked.wait()
finally:
    listener.stop()


print('*REPLAYING*')
for position in positions:
    controller.position = position
    time.sleep(0.01)

Обратите внимание, что при запуске этого в командной строке Windows приложение может зависнуть, потому что вы нажали кнопку мыши, а затем начинаете отправлять позиции мыши.Это вызывает движение «перетаскивания», которое останавливает терминал.Если это произойдет, вы можете просто нажать Escape, и программа продолжит работу.

1 голос
/ 02 июня 2019

У тебя есть бесконечный цикл. Я думаю, что слушатель, на который вы ссылались в методе on_click, может быть нулевым или неопределенным. Также согласно некоторой документации, которую я нашел, вам нужно вернуть false, чтобы метод on_click прекратил прослушивание

Вот на что я смотрел:

https://pythonhosted.org/pynput/mouse.html

...