Convert Hold Left Click to Multiple Left Clicks - python

I am trying to write a python program that would convert left click being held down to multiple left clicks. Essentially it just spams left click when left click is pressed down. I have written code that does this except that it gets stuck in a loop of because it triggers itself with the left clicks it sends. Here is my code:
from pynput.mouse import Listener
from threading import Thread
import pyautogui
import time
flag = False
def clicking():
while flag:
time.sleep(0.5)
pyautogui.click(button='left')
print("Clicking...")
def clicked(x, y, button, pressed):
global flag
if pressed == True:
if button == button.left:
print("Left Click")
flag = True
thread = Thread(target=clicking)
thread.start()
else:
flag = False
with Listener(on_click=clicked) as listener:
listener.join()
How would I modify this code to stop if from triggering itself and getting stuck in a loop. Thanks!

I use this code as an autoclicker you may be able to do some adjustments to set a listener to a left click.
import time
import threading
from pynput.mouse import Button, Controller
from pynput.keyboard import Listener, KeyCode, Key
def on_press(key):
if key == start_stop_key:
if click_thread.running:
click_thread.stop_clicking()
else:
click_thread.start_clicking()
elif key == exit_key:
click_thread.exit()
listener.stop()
class ClickMouse(threading.Thread):
def __init__(self, delay, button):
super(ClickMouse, self).__init__()
self.delay = delay
self.button = button
self.running = False
self.program_running = True
def start_clicking(self):
self.running = True
def stop_clicking(self):
self.running = False
def exit(self):
self.stop_clicking()
self.program_running = False
def run(self):
while self.program_running:
while self.running:
mouse.click(self.button)
time.sleep(self.delay)
time.sleep(0.1)
start_stop_key = KeyCode(char='+')
#key to start
exit_key = KeyCode(char='ยก')
#key to stop the iteration
button = Button.left
#Either Button.left or Button.right
delay = 0.1
#Time between clicks
click_thread = ClickMouse(delay, button)
mouse = Controller()
click_thread.start()
with Listener(on_press = on_press) as listener:
listener.join()
Good luck

Related

How to pause a pynput event listener

I am trying to make a program that will read the user's inputs and if it detects a certain key combination, it will type a special character. Currently I am testing and I want the script to just output a '+' after each character that the user types. I am using the pynput event listener to determine if a key was pressed and using a 'Pause' variable so that the output of the '+' doesn't cause the event listener to make an infinite loop. The problem is that the event listener is going into an infinite loop anyway and I am not sure why.
Current typed output after each key press: +++++++++++++++++++...
Desired typed output after each key press: +
Current console output after each key press:
pause is False
getting pressed
getting released
['f']
paused
send outputs
unpaused
pause is False
getting pressed
getting released
['+']
paused
send outputs
unpaused
pause is False
getting pressed
getting released
['+']
paused
send outputs
unpaused
pause is False
getting pressed
getting released
...
Desired console output after each key press:
pause is False
getting pressed
getting released
['f']
paused
send outputs
pause is True
unpaused
import pynput
import time
from pynput.keyboard import Key, Listener, Controller
keyboardOut = Controller()
PressedKeys = []
ReleasedKeys = []
Pause = False
def on_press(key):
global PressedKeys, ReleasedKeys, Pause
print("pause is "+str(Pause))
if Pause == False:
print("getting pressed")
PressedKeys.append(key)
else:
return
def on_release(key):
global PressedKeys, ReleasedKeys, Pause
if Pause == False and len(PressedKeys) > 0:
print("getting released")
ReleasedKeys.append(key)
test_frame()
else:
return
def test_frame():
global Pause
print(PressedKeys)
Pause = True
print("paused")
print("send outputs")
keyboardOut.press('+')
keyboardOut.release('+')
PressedKeys.clear()
ReleasedKeys.clear()
Pause = False
print("unpaused")
time.sleep(1)
# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
How can I fix my code to *actually* pause the event listener. I am new to python, so I might just not understand how to update global variables correctly.
You have to stop the listener before using the keyboard controller.
I hope this code helps out, I tried to get as close to what I thought you were looking for.
code:
from pynput import keyboard
from time import sleep
KeyboardOut = keyboard.Controller()
pressed_keys = []
released_keys = []
def on_press(key):
try:
pressed_keys.append(format(key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
if len(pressed_keys) > 0:
released_keys.append(format(key))
test_frame()
return False
if key == keyboard.Key.esc:
# Stop listener
return False
def test_frame():
print('\n\n'+str(pressed_keys))
print('paused')
print('send outputs')
KeyboardOut.press('+')
KeyboardOut.release('+')
pressed_keys.clear()
released_keys.clear()
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.run()
print('unpaused')
sleep(1)
return True
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.run()

stop a pynput listener python

I know there may be an answer already out there, but from what I've looked up for python, I really can't find a very straightforward answer on how to stop a pynput Listener.
from pynput.keyboard import Key, Listener
from threading import Thread
stopThreads = True
def on_press(key):
if keyboard.is_pressed("a"):
print("pressed a")
def starting():
global stopThreads
while True:
if stopThreads == True:
with Listener(on_press=on_press) as listener:
if listener.is_alive():
pass
else:
listener.join()
elif stopThreads == False:
listener.stop()
t = Thread(target=starting)
t.start()
time.sleep(5)
print("stop")
stopThreads = False
Im not sure what this looks to you guys, but for this would look like it works perfectly but in reality it doesnt even register if i pressed "a" so im a bit confused on how the pynput listener can be stopped if a variable is False and how to keep it a thread in the background
Nvm, Im just very blinded right now, because i didnt even need to use a listener, i could just say
stopThreads = True
def detectPress():
global stopThreads
while True:
time.sleep(0.05)
if stopThreads == False:
print("stopping")
break
else:
if keyboard.is_pressed("a"):
print("a")
t = Thread(target=detectPress)
t.start()
time.sleep(5)
stopThreads = False

Scrolling is not detected - Pynput

from pynput.mouse import Listener
from pynput.keyboard import Key, Listener
xy = []
sizes = []
isCtrl = False
size = 11
def on_scroll(x, y, dx, dy):
global size, sizes
global isCtrl
print(isCtrl)
if isCtrl:
size += dy
sizes.append(size)
print(sizes[-1])
def on_press(key):
global isCtrl
if key == Key.ctrl:
isCtrl = True
print(isCtrl)
def on_release(key):
global isCtrl
if key == Key.ctrl:
isCtrl = False
print(isCtrl)
# Collect events until released
with Listener(on_scroll=on_scroll,
on_press=on_press,
on_release=on_release) as listener:
listener.join()
That is the code. I am really not sure why and how my scroll code is working, as the function is not being called even if I scrolled already. Thanks for a solution in advanced!
Some mistakes:
You have imported Listener twice, the keyboard listener covered mouse listener.
Keyboard listener doesn't have on_press method.
Consider that you want to monitor both the mouse and the keyboard.You need to create two threads to listen them.Maybe you need:
from pynput.mouse import Listener as mouseListener
from pynput.keyboard import Key, Listener as keyboardListener
xy = []
sizes = []
isCtrl = False
size = 11
def on_scroll(x, y, dx, dy):
global size, sizes
global isCtrl
print(isCtrl)
if isCtrl:
size += dy
sizes.append(size)
print(sizes[-1])
def on_press(key):
global isCtrl
if key == Key.ctrl:
isCtrl = True
print(isCtrl)
def on_release(key):
global isCtrl
if key == Key.ctrl:
isCtrl = False
print(isCtrl)
# Mouse listener
mouse_listener = mouseListener(on_scroll=on_scroll)
mouse_listener.start()
# Keyboard listener
with keyboardListener(on_press=on_press, on_release=on_release) as listener:
listener.join()

How to monitor the mouse doubleclick in pynput?

I am facing a problem when there is a double click during monitoring."can anyone provide me a code that how to monitor mouse doubleclick in python using pynput?"
There is no easy method to get double click when you would like get also single click.
To control double click (without controlling single click) you can remeber time when was previous click and compare with current click. If difference is ie. 0.3s then you can treat it as double click.
Code only for left click
from pynput.mouse import Listener, Button
import time
previous_left = 0
def on_click(x, y, button, pressed):
global previous_left
#text = 'Pressed' if pressed else 'Released'
#print('{0} {1} at {2}'.format(text, button, (x, y)))
double_click_left = False
# double click left button
if pressed and button == Button.left:
current_left = time.time()
diff_left = current_left - previous_left
print('diff left:', diff_left)
if diff_left < 0.3:
print('double click left')
double_click_left = True
previous_left = current_left
# other code
if double_click_left:
# Stop listener
return False
with Listener(on_click=on_click) as listener:
# ... some code ...
listener.join()
Code for other buttons is similar
from pynput.mouse import Listener, Button
import time
previous_left = 0
previous_right = 0
previous_middle = 0
def on_click(x, y, button, pressed):
global previous_left
global previous_right
global previous_middle
#text = 'Pressed' if pressed else 'Released'
#print('{0} {1} at {2}'.format(text, button, (x, y)))
double_click_left = False
double_click_right = False
double_click_middle = False
# double click left button
if pressed and button == Button.left:
current_left = time.time()
diff_left = current_left - previous_left
print('diff left:', diff_left)
if diff_left < 0.3:
print('double click left')
double_click_left = True
previous_left = current_left
# double click right button
if pressed and button == Button.right:
current_right = time.time()
diff_right = current_right - previous_right
print('diff right:', diff_right)
if diff_right < 0.3:
print('double click right')
double_click_right = True
previous_right = current_right
# double click middle button
if pressed and button == Button.middle:
current_middle = time.time()
diff_middle = current_middle - previous_middle
print('diff middle:', diff_middle)
if diff_middle < 0.3:
print('double click middle')
double_click_middle = True
previous_middle = current_middle
# other code
if double_click_left:
# Stop listener
return False
with Listener(on_click=on_click) as listener:
# ... some code ...
listener.join()
But problem is when you want also control single click because it would run some function 0.3s after first click to inform you that it wasn't double click but single click - it would need thread Timer or it would need to run other thread which runs loop wich all time compares curren time with previous_left and if there was no click 0.3s after previous_left then treats it as single click.
I don't have example for this situation.
In addition to the #furas answer, I wanna suggest how to deal with both single and double click events. You just need to create a function that will create threads, and call it from the listener:
import threading
from pynput.mouse import Listener, Button
import time
previous_left = 0
previous_right = 0
previous_middle = 0
def click_handler(x,y,button, pressed):
x = threading.Thread(target=on_click, args=(x,y,button,pressed))
x.start()
def on_click(x, y, button, pressed):
# The code from the comment above to deal with click AND double click
...
with Listener(on_click=click_handler) as listener:
listener.join()

using pynput for key events instead of tkinter

Here is my entire program. I want to change from using tkinter with a gui, to using pynput no gui for get_key events part of my code. Can anyone show me what code to use? This code is a talking vending machine that reads from the machine contents list, which is a file that gets updated by the vending machine company.
I dont want to use a gui as there will be no monitor attached. It's a Raspberry.
from gtts import gTTS
import pygame
from io import BytesIO
import sys
import time
import csv
pygame.init()
if sys.version_info[0] == 3:
# for Python3
from tkinter import *
else:
# for Python2
from Tkinter import *
def say(text):
tts = gTTS(text=text, slow=False, lang='en-us', lang_check=False)
fp = BytesIO()
tts.write_to_fp(fp)
fp.seek(0)
pygame.mixer.init()
pygame.mixer.music.load(fp)
pygame.mixer.music.play()
def load_list():
with open(r"/home/pi/VendyLogProject/vendylist.csv", mode="r") as infile:
return sorted(list(csv.reader(infile)))
def refresh_list():
global vl, vl2, baseposition
new_items = load_list()
if vl != new_items:
vl = new_items
vl2 = [item[0] for item in vl]
baseposition = vl[0]
vl = load_list()
vl2 = [item[0] for item in vl]
baseposition = vl[-1] # so when reading through it reads entry 0 first, then 1
def current(event=None):
global baseposition # baseposition was defined outside of the function, therefore we call global
say(baseposition[1]+baseposition[0])
def back(event=None):
global baseposition
currentposition = vl.index(baseposition)
if currentposition == 0:
baseposition = vl[-1]
say(baseposition[1]+baseposition[0])
else:
previousposition = int(currentposition) - 1 # previousposition is previous position
baseposition = vl[previousposition]
say(baseposition[1]+baseposition[0])
def forward(event=None):
global baseposition
currentposition = vl.index(baseposition)
if currentposition == (len(vl) - 1):
baseposition = vl[0]
say(baseposition[1]+baseposition[0])
else:
nextposition = int(currentposition) + 1 # nextposition is next position
baseposition = vl[nextposition]
say(baseposition[1]+baseposition[0])
def readnumber(int):
global vl
for item in vl:
global baseposition
currentposition = vl.index(baseposition)
if int == item[0]:
baseposition = vl[vl.index(item)]
say(baseposition[1]+baseposition[0])
def help():
say("Welcome to Vendy log! Use the plus and minus keys to go through the list of snacks or push a number to hear its contents!")
root = Tk()
prompt = ' VendyLog '
label1 = Label(root, text=prompt, width=len(prompt))
label1.pack()
#keys buffer
keybuf = []
def test_after():
if keybuf:
num = ''.join(keybuf)
keybuf.clear()
def get_key(event):
keybuf.append(event.char)
event.char = ''.join(keybuf)
root.after(500,test_after)
if event.char == '-':
back()
elif event.char == '+':
forward()
elif event.char == '.':
current()
elif event.char in vl2:
readnumber(event.char)
elif event.char == '00':
help()
elif event.char == '462.':
sys.exit()
def refresh_list_and_enqueue_next_refresh():
refresh_list()
root.after(60000, refresh_list_and_enqueue_next_refresh)
refresh_list_and_enqueue_next_refresh()
root.bind_all('<Key>', get_key)
root.mainloop()
I edited this comment because after I played with OpenGL and Pygame I found the answer of how to use pynput with tkinter.
This is the code sample what I write it to test if works.
# // Imports
import tkinter, pynput
from tkinter import messagebox
# // Global variables
# // If we define variable type I found that will speed up execution a little
root:object = tkinter.Tk()
app_title:str = "Tkinter and Pynput"
app_size:tuple = (300, 150)
listener_stop:bool = False
# // Logics Keyboard
class Keyboard:
# On button pressed
# On my case I found the "Fn" button from laptop is not triggered...
#staticmethod
def Pressed(key) -> bool:
# If listener_stop is True then stop listening
if listener_stop: print("Keyboard Events are stoped!"); return False
# Else show pressed key
else: print(f"Keyboard pressed: {key}")
# On button released
#staticmethod
def Released(key) -> None:
print(f"Keyboard released: {key}")
# Listen keybboard buttons
#staticmethod
def Listener() -> None:
k_listen = pynput.keyboard.Listener(on_press=Keyboard.Pressed,
on_release=Keyboard.Released
)
k_listen.start()
# // Logics Mouse
class Mouse:
# On move
#staticmethod
def Move(x, y) -> bool:
# If listener_stop is True then stop listening
if listener_stop: print("Mouse Events are stoped!"); return False
else: print(f"Mouse: Moved to {x}x{y}")
# On scroll
#staticmethod
def Scroll(x, y, dx, dy) -> None:
where = "down" if dy < 0 else "up"
print(f"Mouse: Scrolled {where} at {x}x{y}")
# On click
# On my case I found mouse wheel press is not triggered...
#staticmethod
def Click(x, y, button, pressed) -> None:
action = "pressed" if pressed else "released"
print(f"Mouse: {button} was {action} at {x}x{y}")
# Listen keybboard buttons
#staticmethod
def Listener() -> None:
m_listen = pynput.mouse.Listener(on_move=Mouse.Move,
on_click=Mouse.Click,
on_scroll=Mouse.Scroll
)
m_listen.start()
# // Logics Define GUI
class MainApp:
def __init__(self, master):
self.master = master
# Create tkinter interface
self.X = (self.master.winfo_screenwidth() - app_size[0]) // 2
self.Y = (self.master.winfo_screenheight() - app_size[1]) // 2
self.master.wm_title(app_title)
self.master.wm_geometry(f"{app_size[0]}x{app_size[1]}+{self.X}+{self.Y}")
# Magic hapen here :P
self.Screen(self.master)
self.InputEvents()
# Define Screen Informations
def Screen(self, root) -> None:
# Set the main frame
self.frm_main = tkinter.Frame(root)
self.frm_main.pack(expand=True, fill="x", side="top")
# Defain frame components
self.title = tkinter.Label(self.frm_main, text=app_title, font=("Comic Sans MS", 18, "bold"), fg="tomato")
self.title.pack(expand=False, fill="x", side="top")
# Input events
def InputEvents(self) -> None:
Keyboard.Listener()
Mouse.Listener()
# Safe Quit
def SafeQuit(self, master:object = root) -> None:
global listener_stop
if messagebox.askokcancel(f"{app_title} Quit", f"Are you shore you want to quit {app_title}?"):
# We need to make shore if the window was closed and
# listening event are still runing, then make them stop
# You will see in fact they are not stoped (from console point view)
# for that reason we check listener_stop on Mouse Move and on Keyboard Key press.
# If for some reason the app is quit and listener has not stoped then on first action did will stop
# Mouse move after app quit >> Mouse listener will stop
# Keyboard button pressed after app quit >> Keyboard listener will stops
if listener_stop == False:
listener_stop = True
print("Events Listening are stoped!")
master.destroy()
# // Run if this is tha main file
if __name__ == "__main__":
app:object = MainApp(root)
root.protocol("WM_DELETE_WINDOW", app.SafeQuit)
root.mainloop()
I updated the code again with stop lisening keyboard and mouse event.
PS: An updated version of them can be found on my github

Categories