stop a pynput listener python - 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

Related

Detect NO KEY PRESSES with keyboard module python

I'm making a tkinter program and want to detect a key press and do something when there is, however if no key is pressed the keyboard.read_key() will not execute and not let any other code run until a key is pressed.
Is there an alternative I can use or a way to check if no key was pressed?
def on_press():
global running
global turn
if keyboard.read_key() == 'q':
ws.destroy()
elif keyboard.read_key() == 'a':
if turn:
print('turning off')
running = False
turn = False
else:
print('turning on')
running = True
turn = True
start()
else:
start()
def start():
global running
global turn
print('start')
if running:
print('clicking')
mouse.click(Button.left, cps_val)
time.sleep(1)
on_press()
on_press()
Key is no pressed for the most of the time. Because computer is fast and human is slow so I would assumed that that key is no pressed at the beginnig and I would run code at once (without checking if it no pressed). And I would run "clicking code" all time in while at the beginning and I would use keys only to pause this loop (key a) or exit this loop (key q) - without checking if key is no pressed.
import keyboard
#import mouse
import time
# --- functions ---
def pause():
global turn
if turn:
print('turning off')
turn = False
else:
print('turning on')
turn = True
def finish():
global running
running = False
def main():
global counter
print('start')
while running:
if turn:
counter += 1
print('clicking', counter)
#mouse.click(Button.left, cps_val)
time.sleep(1)
# --- main ---
turn = True
running = True
counter = 0
keyboard.add_hotkey('q', finish)
keyboard.add_hotkey('a', pause)
main()
If it has to run with tkinter then while loop will block tkinter (tkinter will freeze because it will have no time to get key/mouse events from system, send them to widgets, update widgets, and redraw widgets in window).
I would use tkinter.after(milliseconds, function) instead of sleep() and while and tkinter will have time to work.
import tkinter as tk
import keyboard
#import mouse
import time
# --- functions ---
def pause():
global turn
if turn:
print('turning off')
turn = False
else:
print('turning on')
turn = True
def finish():
global running
running = False
root.destroy()
def main():
print('start')
loop() # run first time at once
#root.after(1000, loop) # run first time after 1s
def loop():
global counter
if turn:
counter += 1
#print('clicking', counter)
label['text'] = f'clicking {counter}'
#mouse.click(Button.left, cps_val)
if running:
root.after(1000, loop) # run again after 1s
# --- main ---
turn = True
running = True
counter = 0
keyboard.add_hotkey('q', finish)
keyboard.add_hotkey('a', pause)
root = tk.Tk()
label = tk.Label(root, text='clicking 0')
label.pack()
main()
root.mainloop()

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()

UnboundLocalError: local variable 'toggled' referenced before assignment

I was working on a random python script but I've encountered the above error and cannot figure out how to work it out.
Code:
from pynput.keyboard import Key, Controller, Listener
import time
keyboard = Controller
key = "e"
toggle = Key.f6
toggled = False
def on_press(key):
print(f"on_press() triggered, key = {key}")
if key == toggle:
toggled = not toggled
def on_release(key):
print(f"on_release() triggered, key = {key}")
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
while True:
if toggled:
keyboard.press(key)
time.sleep(3)
keyboard.release(key)
time.sleep(1)

Convert Hold Left Click to Multiple Left Clicks

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

Python while key pressed function [duplicate]

I am controlling a remote toy car using python code. As of now, the code is as below:
def getkey():
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO
new[6][TERMIOS.VMIN] = 1
new[6][TERMIOS.VTIME] = 0
termios.tcsetattr(fd, TERMIOS.TCSANOW, new)
c = None
try:
c = os.read(fd, 1)
finally:
termios.tcsetattr(fd, TERMIOS.TCSAFLUSH, old)
return c
def car():
while True:
key = getkey()
if key == 's': #Down arrow
print "Down"
Backward()
elif key == 'w': #Up arrow
print "Up"
forward()
elif key == 'a':
print "left"
Left()
elif key == 'd':
print "Right"
Right()
elif key == 'q': #Quit
print "That's It"
break
def forward():
GPIO.output(11,True) #Move forward
When I press 'w' forward() method is called and the car moves forward but wont stop until I quit the program or call GPIO.output(11, False) from some other method.
Is there any key Listener which detects the key release of any particular key?
For example, if 'w' pressed called this method and if released call some other method
Sudo code:
if w_isPressed()
forward()
else if w_isReleased()
stop()
I've seen Pygame game development library being successfully used in similar scenarios before, handling realtime systems and machinery in production, not just toy examples. I think it's a suitable candidate here too. Check out pygame.key module for what is possible to do with the keyboard input.
In short, if you are not familiar with game development, you basically continuously poll for events such as input state changes inside an 'infinite' game loop and react accordingly. Usually update the parameters of the system using deltas per time elapsed. There's plenty of tutorials on that and Pygame available around and Pygame docs are pretty solid.
A simple example of how to go about it:
import pygame
pygame.init()
# to spam the pygame.KEYDOWN event every 100ms while key being pressed
pygame.key.set_repeat(100, 100)
while 1:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
print 'go forward'
if event.key == pygame.K_s:
print 'go backward'
if event.type == pygame.KEYUP:
print 'stop'
You'll need to play with pygame.KEYDOWN, pygame.KEYUP and pygame.key.set_repeat depending on how your car movement is implemented.
Faced a similar problem (I am no Python expert) but this worked for me
import pynput
from pynput import keyboard
def on_press(key):
try:
print('Key {0} pressed'.format(key.char))
#Add your code to drive motor
except AttributeError:
print('Key {0} pressed'.format(key))
#Add Code
def on_release(key):
print('{0} released'.format(key))
#Add your code to stop motor
if key == keyboard.Key.esc:
# Stop listener
# Stop the Robot Code
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()

Categories