I'm just trying to learn the "Listener" function. But I couldn't manage to break any loop with mouse clicking. Here is an example:
from pynput.mouse import Listener
import time
def on_click(x, y, button, pressed):
counter = 0
while True:
print(counter)
counter += 1
time.sleep(1)
if pressed:
break
with Listener(on_click = on_click) as listener:
listener.join()
When I'm running this code, my PC is getting very slow. I'm a beginner. I need to use listener with normal codes.
Thanks
Keep in mind that on_click function is called twice. Once when you press the mouse button down, and again when the button is released. Since the function will be called twice, we cannot break the loop that the first function call creates by calling it again with a different value for the state of the mouse button.
I am assuming your intention was to print counter every second the mouse button is held down. I have a snippet below for you that uses threading to accomplish this, and each call to the on_click function can read the state of the mouse as well as the state of the thread used for printing.
While using time.sleep() within a function it causes the thread it was called in to sleep. When you only have one thread running it causes the entire program to sleep every second. I believe that your computer was not lagging, however the mouse would appear to lag because your input is being interrupted by the call to sleep every second.
from pynput import mouse
import time
from threading import Thread
def on_click(x, y, button, pressed):
thread = Thread(target = threaded_function)
if pressed and thread.is_alive() == False:
thread.start()
if not pressed:
if thread.is_alive():
thread.join()
return False
def threaded_function():
count = 0
while True:
count+=1
print(count)
time.sleep(1)
with mouse.Listener(on_click = on_click) as listener:
listener.join()
Related
I want to have a shared bool between threads that is write-accessed in two threads (but since its just a byte should be thread-safe) and then read in the main thread. The execution of the main thread depends on wheter the bool is true or false. I currently have a pynput mouse listener thread listed below:
listener = mouse.Listener(on_click=on_click)
listener.start()
def on_click(x, y, button, pressed):
global Xcord, Ycord, mousePressed
if pressed:
mousePressed = True
Xcord = x
Ycord = y
and a thread plotting_thread that resets the bool mousePressed exactly after 10 seconds if it changes to true:
x = threading.Thread(target=plotting_thread, args=())
x.start()
def plotting_thread():
while not shutdown:
global mousePressed
if mousePressed:
time.sleep(10)
mousePressed = False
I then read the bool mousePressed in the main thread and plot something according to if mousePressed is set.
My problem is the following: The computer and mouse start to lag quite badly exactly 10 seconds after I press the mouse (without pressing it again). This can be replicated every time. So upon startup it works fine for 10 seconds, then it starts lagging. I click the mouse once, it works fine for 10 seconds and then starts lagging again, etc...
My best guess is a constant overwrite which keeps the program busy but I don't see where it could happen since on_click() is only called upon a mouse click.
I've tried to use python events via .set() and .is_set(), but that resulted in the exact same behavior. If I remove the assignment mousePressed = false in the plotting_thread(), it works fine so it definetly is some constant overwrite or something similar. But I do not see why it would happen and how to fix it so that it just works without lagging.
Thank you
I made an autoclicker and i can stop it by pressing b but only at the right timing. I didn't find anything that would allow me to stop the program by pressing a button at any time without accessing the console
Here's the program:
from time import sleep
import keyboard
import mouse
state=True
while state:
if keyboard.is_pressed("b"):
state=False
else:
mouse.click()
sleep(1)
I already answered at Using a key listener to stop a loop
You can simply use the add_hotkey method.
Example:
import keyboard
state = True
def stop():
state = False # The function you want to execute to stop the loop
keyboard.add_hotkey("b", stop) # add the hotkey
I've got a small and simple piece of code which is supposed to make it so you are unable to click and hold. It works fine, however it has a large amount of latency and when I click it takes about half a second or more for it to interact with anything on my screen.
I've also noticed that sometimes it will do something to my cursor which makes my cursor move at about 5 fps with extremely high resistance and momentum (by momentum I mean it keeps moving even when I stop moving the mouse).
I'm wondering if I'm doing something wrong or maybe there's some other module which is better for the job?
This is my code:
import pyautogui
from pynput import mouse, keyboard
def on_click(x, y, button, pressed):
if button == mouse.Button.left:
if pressed:
pyautogui.mouseUp()
return True
while True:
listener = mouse.Listener(on_click=on_click)
listener.start()
listener.join()
I don't have the same issues you have on your machine. But it could be that inside your loop you are continually starting the listener? Try putting the listener outside the loop and just have a pass inside the loop:
import pyautogui
from pynput import mouse, keyboard
def on_click(x, y, button, pressed):
if button == mouse.Button.left:
if pressed:
print('doogie')
pyautogui.mouseUp()
return True
listener = mouse.Listener(on_click=on_click)
listener.start()
listener.join()
while True:
pass
I was trying to emulate "double-clicking" often used in gaming mouses as a python programme but after making a short programme and reading the docs, I realized I caused an infinite loop of clicking!
Now, I would like to continue but I don't know what the best way out of the infinite loop.
My Code:
import pyautogui
import random
from pynput import mouse
def on_click(x, y, button, pressed):
pyautogui.click()
x = random.randint(1, 2)
if x == 2:
pyautogui.click()
# Collect events until released
with mouse.Listener(
on_click=on_click) as listener:
listener.join()
Thanks!
I have this relatively simple program that listens for mouse clicks and when the mouse button is held down prints "1"s. Unfortunately when I let go of the mouse it just keeps printing "1"s, even though there is an if statement which checks if the mouse is clicked and should stop the loop if it is not. I am using the pynput.mouse module for the mouse interaction.
Here is my code:
import time
from pynput.mouse import Listener
def clicked(x, y, button, pressed):
if pressed == True:
while button == button.left:
print("1")
time.sleep(1)
if pressed == False:
break
with Listener(on_click=clicked) as listener:
listener.join()
My theory is that once the loops starts it stops listening for mouse clicks, so it can never stop the loop. Would it be necessary to create a new thread for the loop? If yes, how would I do that?
Thanks!
Your current logic makes it impossible to get out of the loop, since pressed doesn't change within the loop. There is not a statement that checks if the mouse is clicked: your only if statements check whether the mouse was clicked when you entered the function. pressed doesn't change within the function.
Look at the critical logiic:
if pressed == True:
while ...
...
if pressed == False:
break
There is nothing in here to change the value of pressed; the first if guarantees that it's True anywhere within the loop.
Yes, you need to set up another listener that operates within the loop. You already know the building blocks: create a new one within the function and bind it to another operation that breaks the loop. For instance, you might "cheat" and have it reset pressed as a global variable.
You could also research how to do this in other answers, if you want an overall handler solution. keypress and keyrelease have been done often enough.
import pyautogui, random, time
import pynput
keys = ['w', 's', 'a', 'd']
def on_press(key):
p = True
if key == pynput.keyboard.Key.esc:
return False
else:
while p == True:
press = keys[random.randint(0,3)]
pyautogui.keyDown(press)
pyautogui.keyUp(press)
p = False
with pynput.keyboard.Listener(on_press=on_press) as L:
L.join()
a code like this will work instead of what you did.
BTW, that is just an example; feel free to visit my GitHub page: github.com/ironnicko