Hello i'm trying to make a program to play snake using pynput.
When I press space the program runs but even if I press backspace i can't stop it, I know that I have to use threading but I don't figure how it works, thank you
my code :
from pynput import keyboard
from pynput.keyboard import Key, Controller
import threading
import time
kb = Controller()
def droite(key):
kb.press(Key.right)
kb.release(Key.right)
def gauche(key):
kb.press(Key.left)
kb.release(Key.left)
def haut(key):
kb.press(Key.up)
kb.release(Key.up)
def bas(key):
kb.press(Key.down)
kb.release(Key.down)
def on_press(key):
if key == Key.space:
print('yes')
droite(Key.right)
time.sleep(1.7)
haut(Key.up)
time.sleep(0.9)
gauche(Key.left)
time.sleep(2.15)
bas(Key.down)
time.sleep(1.9)
droite(Key.right)
time.sleep(2.15)
for i in range(255):
for i in range(6):
haut(Key.up)
time.sleep(0.1 )
gauche(Key.left)
time.sleep(2.1)
haut(Key.up)
time.sleep(0.1)
droite(Key.right)
time.sleep(2.1)
gauche(Key.left)
time.sleep(2.15)
bas(Key.down)
time.sleep(1.9)
droite(Key.right)
def on_release(key):
if key == Key.backspace:
print('no')
KeyboardInterrupt
return False
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
th1 = threading.Thread(target=on_press)
th1.start()
th2 = threading.Thread(target=on_release)
th2.start()
th1.join()
th2.join()
I'm trying to stop the program even if I'm in a loop when I press a key
Related
I am working on a script that will listen to keystrokes till the 'q' button is pressed, afterwards it should stop the script and print out the mouse positions that were saved in 2 seconds intervals. I can't manage the threads and I am still learning this topic. Each time I run the code nothing happens but the process is running:
from pynput.keyboard import Listener
import pyautogui
from multiprocessing import Process
import time
mouse_positions = []
def func1():
while True:
time.sleep(2)
mouse_positions.append(pyautogui.position())
cordinates = []
quit_status = False
keystrokes = []
def on_press(key):
if "q" in str(key) :
print('q was pressed!')
exit("Stopped running")
#qprint(key)
keystrokes.append(key)
print(keystrokes)
#print(keystrokes)
if __name__ == '__main__':
p1 = Process(target=func1)
p1.start()
p1.join()
with Listener(on_press=on_press) as listener: # Create an instance of Listener
listener.join() # Join the listener thread to the main thread to keep waiting for keys
EDIT :
To anyone intrested, here is a click macro I built, script I built previously was more like mouse capture movement. The script below will record your mouse clicks and afterwards will replay them. Much better.
from pynput.keyboard import Listener
import pyautogui
from pynput import mouse
import time
x_pos = []
y_pos = []
both_pos = []
pressed_key = None
def on_click(x, y, button, pressed):
if pressed:
#print ("{0} {1}".format(x,y))
print(pressed_key)
if pressed_key == "1":
both_pos.append("{0}".format(x,y))
both_pos.append("{1}".format(x,y))
#print("test" + x_pos + y_pos)
print (x_pos + y_pos)
else:
pass
if pressed_key == 'q':
return False
def on_press(key):
print("To replay press 'q' , to stop recording press '1' , to record again press '1' .")
global pressed_key
if 'Key.esc' in str(key):
return False
if '1' in str(key):
pressed_key= None if pressed_key == '1' else '1'
if 'q' in str(key):
print("Replaying actions")
print(str(len(both_pos)))
for point in range(0,len(both_pos),2):
time.sleep(3)
print("clicking")
pyautogui.click(x=int(both_pos[point]),y=int(both_pos[point+1]))
print("done...")
return False
mouse_listener = mouse.Listener(on_click=on_click)
mouse_listener.start()
with Listener(on_press=on_press) as listener: # Create an instance of Listener
listener.join()
#print(mouse_listener.mouse_positions)
Hi you can use threading module.
I have created class MouseListener which inherit from threading.Thread class. Everything what you want to run put into run method. As thread stopper I used still_run attribute.
When you are typing, I pass to on_press function pressed key and mouse_listener. If q is pressed I set mouse_listener.still_run to False, what leads to stop the mouse listener.
mouse_positions I moved from global scope to MouseListener.
import threading
from pynput.keyboard import Listener
import pyautogui
import time
class MouseListener(threading.Thread):
still_run = True
mouse_positions = []
def run(self):
self.func()
def func(self):
while self.still_run:
time.sleep(2)
self.mouse_positions.append(pyautogui.position())
print(self.mouse_positions)
coordinates = []
quit_status = False
keystrokes = []
def on_press(key, mouse_listener):
print('kp')
if "q" in str(key):
print('q was pressed!')
mouse_listener.still_run = False
print(key)
exit("Stopped running")
keystrokes.append(key)
print(keystrokes)
print(keystrokes)
if __name__ == '__main__':
mouse_listener = MouseListener()
mouse_listener.start()
with Listener(on_press=lambda key: on_press(key, mouse_listener)) as listener: # Create an instance of Listener
listener.join()
print(mouse_listener.mouse_positions)
I have this code here and what I want is for the code to type "potato" every 5 seconds. I also want a "quit" command, and I want it so that when I press = it will stop the program. However, not only does the code not work, but it also types "=" after it types/enters "potato". Can someone help? Thanks.
from pynput.keyboard import Key, Controller
import time
keyboard = Controller()
time.sleep(3)
while True:
keyboard.type('potato')
keyboard.press(Key.enter)
keyboard.release(Key.enter)
if keyboard.type('asdf'):
quit()
time.sleep(5)
P.S. no errors or anything
The most obvious answer here would be to change the "asdf" to "=" in the if statement, but if that doesn't fix the problem, you could add a listener to detect keypresses.
from pynput import keyboard, Key, Controller
import time
# set your termination key here
cut_key = "="
# check if key pressed is cut_key, if so, quit
def on_press(key):
try:
if key.char == cut_key:
quit()
except AttributeError:
if key == cut_key:
quit()
# non-blocking listener
listener = keyboard.Listener(
on_press=on_press)
listener.start()
keyboard = Controller()
time.sleep(3)
while True:
keyboard.type('potato')
keyboard.press(Key.enter)
keyboard.release(Key.enter)
time.sleep(5)
I didn't test this code, please comment if it doesn't work.
https://pynput.readthedocs.io/en/latest/keyboard.html
My code uses mouse events to send messages but I have no idea how to stop using an f1 key. I didn't find a stop () method as in Listener () in Events ().
import pynput
import pyautogui
import time
from pynput import mouse
from pynput import keyboard
running = True
mouse_event = mouse.Events()
def on_press(key):
global running
if key == keyboard.Key.f1:
running = False
print('end')
return False
def msg():
mouse_event.start()
for event in mouse_event:
if running:
if isinstance(event,mouse.Events.Click):
if not event.pressed:
pyautogui.typewrite('hello world\n',interval=0.009)
else:
time.sleep(1)
return False
while 1:
print("Choose the desired option")
print("1. Message")
option = int(input("Option:"))
if option == 1:
running = True
with keyboard.Listener(on_press=on_press) as listener:
if running:
msg()
elif not listener.running:
time.sleep(2)
break
Is there a way to interrupt a mouse event with the press of a key?
One attempt was to pass the method as on_press to Events () does not work.
I've had to do something similar in the past and I ended up using threading to have one thread listen for the mouse/keyboard input while the other runs my main program.
import time
from pynput import keyboard
from threading import Thread
def exit_program():
def on_press(key):
if str(key) == 'Key.f1':
main.status = 'pause'
user_input = input('Program paused, would you like to continue? (y/n) ')
while user_input != 'y' and user_input != 'n':
user_input = input('Incorrect input, try either "y" or "n" ')
if user_input == 'y':
main.status = 'run'
elif user_input == 'n':
main.status = 'exit'
exit()
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
def main():
main.status = 'run'
while True:
print('running')
time.sleep(1)
while main.status == 'pause':
time.sleep(1)
if main.status == 'exit':
print('Main program closing')
break
Thread(target=main).start()
Thread(target=exit_program).start()
Here Is the keylogger Code:
''' from pynput.keyboard import Key, Listener
import logging
log_dir = r"/Users/user/Desktop/submit/Keylogger.txt "
logging.basicConfig(filename=(log_dir + "keyLog.txt"), level=logging.DEBUG, format='%(asctime)s: %(message)s')
def on_press(key):
logging.info(str(key))
def on_release(key):
print('{}'.format(key))
if str(key) == 'Key.esc':
print('Exiting...')
return False
with Listener(on_press=on_press) as listener:
listener.join() '''
When ever I run it, it works fine but for one thing: It records in double, so ill see A A and B B for one word. How can I fix this? (python3, MacOS)
I'm trying to develop a multithreaded program with a TUI interface . Basically I have a main Loop deciding what to do and some task (like the TUI or reading data from a queue and processing it ) are running in separate thread .
My TUI is using curses and is a thread derived class that look like this (i removed non essential code for clarity) :
import threading
from time import sleep
import curses
import logging
from curses.textpad import Textbox, rectangle
from datetime import datetime
import re
from curses import panel
import os
import sys
class GenericTUI(threading.Thread):
def __init__(self, logger=logging.getLogger()):
threading.Thread.__init__(self,name="genericTUI" + str(os.getpid()), daemon=True)
self.keyPressedList = list()
self.alive = True
self._myStdscr = None
self.title = ""
self.logger = logger
self.lock = threading.Lock()
def run(self):
curses.wrapper(self.main)
curses.nocbreak()
curses.echo()
curses.noraw()
sys.exit(0)
def main(self,stdscr):
self._myStdscr = stdscr
self._myStdscr.nodelay(True)
self._myStdscr.keypad(True)
self._myStdscr.box()
while self.alive:
sleep(0.4)
try :
key = self._myStdscr.getkey()
if re.match('[A-Z_\+\-\*/]', key):
self.keyPressedList.append(key)
except Exception as e:
## ignoring no key presssed
pass
try :
with self.lock :
self._myStdscr.clear()
self._myStdscr.addstr(1, 2, str(datetime.now())+" "+ sys.argv[0] +" "+self.title )
### printing other things
self._myStdscr.refresh()
except Exception as e:
self.logger.error(e, exc_info=True)
continue
self._myStdscr.clear()
self._myStdscr.keypad(0)
def getKeyPressed(self):
if self.keyPressedList :
return self.keyPressedList.pop()
else :
return None
def stop(self):
self.alive = False
def updateTitle(self,title):
with self.lock : self.title = title
if __name__ == "__main__":
## the main is used for some test when the lib is called directly
testGUI = GenericTUI()
alive = True
testGUI.logger.addHandler(logging.StreamHandler())
testGUI.logger.setLevel(logging.DEBUG)
testGUI.start()
while alive :
testGUI.updateTitle('title %s'%str(datetime.now() ))
k = testGUI.getKeyPressed()
if k is not None:
if k=='Q' :
alive = False
else :
testGUI.addMessage('unknown key %s'%k , maj=True)
sleep(0.1)
the main loop of my program instantiate and start a genericTUI object and get keypressed from it or set value to display.
But when i quit the program , my terminal is in a funny state even if I used the curses wrapper function or try to reset manually using curses.nocbreak() and others.
I can't figure what I did wrong ? Am i mistaken using curses inside a thread ??
I found the answer but puting it in the comment section makes it hard to read . So I also put it here :
the curses wapper does not like the thread in daemon mode :
so the following code works fine and restore the terminal in a correct state :
class GenericTUI(threading.Thread):
def __init__(self, logger=logging.getLogger()):
threading.Thread.__init__(self,name="genericTUI" + str(os.getpid()), daemon=False)
self.keyPressedList = list()
and in the stop function adding a curses.endwin() helps :
def stop(self):
curses.endwin()
self.alive = False
hope it helps other
#WesModes I use the stop to have a clean way to stop the TUI. The endwin is cleaning the screen .
example :
testGUI=GenericTUI()
alive = True
testGUI.start()
while alive:
try :
k = testGUI.getKeyPressed()
if k is not None:
if k== 'Q':
testGUI.stop()
alive = False