Python script does not exit after function run - python

I have a following program that simply reads what buttons are pressed using keyboard and in case user hits Escape button, the script should stop working. The problem is that it does not do it - it stops printing buttons but does not end its operation. I tried adding sys.exit() function but without success.
Any suggestions would be appreciated!
from __future__ import print_function
from inputs import get_key
from inputs import DeviceManager
def main():
devices = DeviceManager()
dictionaries = devices.codes
qt = False
while qt == False:
events = get_key()
for event in events:
if (event.code in dictionaries["Key"].values() and event.code != "KEY_ESC" and event.state == 1):
print(event.code, event.state)
elif (event.code in dictionaries["Key"].values() and event.code == "KEY_ESC" and event.state == 1):
qt = True
break
return
if __name__ == "__main__":
main()

As suggested in comments it was package-connected issue. In this case the proper solution to problem was using try statement:
from __future__ import print_function
from inputs import get_key
from inputs import DeviceManager
def main():
devices = DeviceManager()
dictionaries = devices.codes
qt = False
try:
while True:
events = get_key()
for event in events:
if (event.code in dictionaries["Key"].values() and event.state == 1):
print(event.code, event.state)
except KeyboardInterrupt:
return
if __name__ == "__main__":
main()

There are 2 loops in the code, while and for. You are breaking only the for loop. You should break the while loop too.

Related

Python Threading for Camera

I am trying to put the camera footage into a different thread as the cv2.wait() does not work correctly anymore for access keys even when using an '& and hexadecimal'.
Does anyone know what I have done wrong with the daemon thread I have created for displaying camera footage in the main as when placed in the main while loop it fails while loop?
How do I use a thread to continuously display camera footage in my while loop in the main program?
quote My thread for the ViewCamera function isn't working right - can anyone help?
from djitellopy import Tello
# Access the telopy libray.
import cv2, math, time
from time import sleep, perf_counter
from threading import Thread
stop = True
def ViewCamera():
global stop
while stop == True:
try:
#camera window
img = frame_read.frame
cv2.imshow("drone", img)
print ('thread test')
except Exception as e:
print ("Cerror is : ,", e)
drone = Tello()
'''
create an instance of the Tellopy libray
drone.connect() #connect to drone using wifi
drone.streamon()
#make use of a data stream to drone to pass on keyboard commands
#frame_read = drone.get_frame_read() #read cammera data using frame per frame rate
'''
key = 0
# drone.takeoff()
if __name__ == "__main__":
print ('main program')
# Create a camera thread - runs in background.
t1 = Thread(target=ViewCamera, args=())
t1.daemon = True
print('starting thread')
t1.start()
while True:
key = ord(input('please enter letter'))
if key == ord('j'):
drone.land()
print('stopping thread')
stop = False
break
elif key == ord('w'): # Forward
drone.move_forward(30)
print('moving forwards')
elif key == ord('s'): # Move backwards
drone.move_back(30)
elif key == ord('a'): # Move left
drone.move_left(30)
elif key == ord('d'): # Move right
drone.move_right(30)
elif key == ord('e'): # Rotate right
drone.rotate_clockwise(30)
elif key == ord('q'): # Rotate left
drone.rotate_counter_clockwise(30)
elif key == ord('r'): # Move up
drone.move_up(30)
elif key == ord('f'): # Move down
drone.move_down(30)
print('stopping thread')
t1.join()
drone.land()
The threading daemon isn't seeming to work it should be running in background and continually allowing the camera images in a window to be viewed - any ideas why it is not?

name 'values' is not defined when using Multithreaded and pysimplegui

import threading
from PySimpleGUI import PySimpleGUI as sg
def thread2():
while (x == True):
if values["radio"] == True:
print("true")
def thread1():
tab1_layout = [
[sg.Radio('G', "RADIO1", default=True, size=(10,1), key='radio'), sg.Radio('R', "RADIO1")]
]
(...)
while True:
events, values = janela.read()
threading.Thread(target=thread1).start()
sleep(5)
threading.Thread(target=thread12).start()
My code is something like that
How can I acess user values option of the radio using Multithreaded and pysimplegui?
error:
name 'values' is not defined
It looks that the structure of your script is something wrong, the GUI part should be under main thread.
import threading
import PySimpleGUI as sg
def thread(window, values):
...
while (x == True):
if values["radio"]:
print("true")
...
def main():
tab1_layout = [
[sg.Radio('G', "RADIO1", default=True, size=(10,1), key='radio'), sg.Radio('R', "RADIO1")]
[sg.Button('Submit')],
]
...
while True:
event, values = janela.read()
if event == sg.WINDOW_CLOSED:
break
elif event == 'Submit':
threading.Thread(target=thread, args=(window, values), daemon=True).start()
window.close()
main()

Python - creating a simple killswitch for a function that runs with multiprocessing

So, i would claim that i understand how Asyncio, Multiprocessing, Threading etc. works, basically. I know how to listen for keystrokes too - there are many good examples on this site.
However i was unable to combine both into one. I have a programm that runs continously in a loop, until it runs into certain cases where it stops. In these cases, it uses a Multiprocessing.Queue() to prompt for user input on wether it should continue or not.
All of this works, so far so good. Now i want to add a second catch case here: The programm should, once it starts running, immediatly cease working as soon as i press a certain button (lets say Escape).
This is the very dumbed down version of my programm:
test.py:
from test3 import Counter
from multiprocessing import Process, Queue
import sys
def main(q, passed_variable):
foo = Counter()
p1 = Process(target=foo.counting, args=(q,passed_variable))
p1.start()
p1.join()
if q.get() == False:
x = input("Keep going?")
print(x)
if x == "y":
main(q, user_Input)
else:
sys.exit()
if __name__ == "__main__":
q = Queue()
user_Input = ("What you want from me, man?")
print("Starting")
main(q, passed_variable=user_Input)
test3.py:
import time
class Counter:
def counting(self, q, user_input):
x = 0
while True:
print(str(x) + " " + user_input)
if x == 4:
q.put(False)
break
time.sleep(1)
x += 1
I tried everything i could think of, in no case did i get the desired result, and no question i found here was able to help me in this specific case.
You can solve this using keyboard and then creating a second Queue():
from test3 import Counter
from multiprocessing import Process, Queue
import sys
import keyboard
def main(q, queue2, passed_variable):
foo = Counter()
p1 = Process(target=foo.counting, args=(q,passed_variable))
p1.start()
p2 = Process(target=keyCatcher, args=(queue2,))
p2.start()
if queue2.get() == False:
p1.terminate()
print("Terminating Programm")
sys.exit()
if q.get() == False:
x = input("Keep going?")
print(x)
if x == "y":
main(q, queue2, user_Input)
else:
sys.exit()
def keyCatcher(queue2):
while True:
if keyboard.is_pressed('q'): # if key 'q' is pressed
queue2.put(False)
if __name__ == "__main__":
q = Queue()
queue2 = Queue()
user_Input = ("What you want from me, man?")
print("Starting")
main(q, queue2, passed_variable=user_Input)
The crux is:
p1.start()
p1.join()
Which means after main() starts p1, it waits for it to finish. So there's no chance to interrupt it while processing.
You need to:
wait for p1 to finish
while waiting, see if the main process gets a 'q'
if the main process gets a 'q', stop it.
Something like:
p1.start()
while p1.is_alive():
k = keyboard.read_key()
if k == 'q':
p1.terminate()

Detect a key pressed within a while Python

I want to detect a key pressed in python without using "with", because I want it to show a text in a while
all this with the pynput library:
import time
from pynput import keyboard
i = 0
while True:
if event.key == keyboard.Key.esc:
break
else:
if a == "hello":
print("y")
else:
print("n")
if i % 2 = 0:
a = "hello"
else
a = "good bye"
i += 1
print(a)
time.sleep(2)
pynput's Events blocks by default. You can .get to limit how long it blocks for:
from pynput import keyboard
import time
i = 0
a = "start"
while True:
if a == "hello":
print("y")
else:
print("n")
if i % 2 == 0:
a = "hello"
else:
a = "good bye"
i += 1
print(a)
# Not needed anymore, we're going to block waiting for key events for 2 seconds
# time.sleep(2)
with keyboard.Events() as events:
# Block at most for two seconds
event = events.get(2.0)
if event is not None:
if event.key == keyboard.Key.esc:
break
This won't necessarily always block for two seconds if the user presses some other key. You can either add code to check for that condition and keep calling events.get till enough time has passed, or use keyboard.Listener to react to events in real time.

How to kill a while loop with a keystroke?

I am reading serial data and writing to a csv file using a while loop. I want the user to be able to kill the while loop once they feel they have collected enough data.
while True:
#do a bunch of serial stuff
#if the user presses the 'esc' or 'return' key:
break
I have done something like this using opencv, but it doesn't seem to be working in this application (and i really don't want to import opencv just for this function anyway)...
# Listen for ESC or ENTER key
c = cv.WaitKey(7) % 0x100
if c == 27 or c == 10:
break
So. How can I let the user break out of the loop?
Also, I don't want to use keyboard interrupt, because the script needs to continue to run after the while loop is terminated.
The easiest way is to just interrupt it with the usual Ctrl-C (SIGINT).
try:
while True:
do_something()
except KeyboardInterrupt:
pass
Since Ctrl-C causes KeyboardInterrupt to be raised, just catch it outside the loop and ignore it.
There is a solution that requires no non-standard modules and is 100% transportable:
import _thread
def input_thread(a_list):
raw_input() # use input() in Python3
a_list.append(True)
def do_stuff():
a_list = []
_thread.start_new_thread(input_thread, (a_list,))
while not a_list:
stuff()
the following code works for me. It requires openCV (import cv2).
The code is composed of an infinite loop that is continuously looking for a key pressed. In this case, when the 'q' key is pressed, the program ends. Other keys can be pressed (in this example 'b' or 'k') to perform different actions such as change a variable value or execute a function.
import cv2
while True:
k = cv2.waitKey(1) & 0xFF
# press 'q' to exit
if k == ord('q'):
break
elif k == ord('b'):
# change a variable / do something ...
elif k == ord('k'):
# change a variable / do something ...
For Python 3.7, I copied and changed the very nice answer by user297171 so it works in all scenarios in Python 3.7 that I tested.
import threading as th
keep_going = True
def key_capture_thread():
global keep_going
input()
keep_going = False
def do_stuff():
th.Thread(target=key_capture_thread, args=(), name='key_capture_thread', daemon=True).start()
while keep_going:
print('still going...')
do_stuff()
pip install keyboard
import keyboard
while True:
# do something
if keyboard.is_pressed("q"):
print("q pressed, ending loop")
break
Here is a solution that worked for me. Got some ideas from posts here and elsewhere. Loop won't end until defined key (abortKey) is pressed. The loop stops as fast as possible and does not try to run to next iteration.
from pynput import keyboard
from threading import Thread
from time import sleep
def on_press(key, abortKey='esc'):
try:
k = key.char # single-char keys
except:
k = key.name # other keys
print('pressed %s' % (k))
if k == abortKey:
print('end loop ...')
return False # stop listener
def loop_fun():
while True:
print('sleeping')
sleep(5)
if __name__ == '__main__':
abortKey = 't'
listener = keyboard.Listener(on_press=on_press, abortKey=abortKey)
listener.start() # start to listen on a separate thread
# start thread with loop
Thread(target=loop_fun, args=(), name='loop_fun', daemon=True).start()
listener.join() # wait for abortKey
pyHook might help. http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial#tocpyHook%5FTutorial4
See keyboard hooks; this is more generalized-- if you want specific keyboard interactions and not just using KeyboardInterrupt.
Also, in general (depending on your use) I think having the Ctrl-C option still available to kill your script makes sense.
See also previous question: Detect in python which keys are pressed
There is always sys.exit().
The system library in Python's core library has an exit function which is super handy when prototyping.
The code would be along the lines of:
import sys
while True:
selection = raw_input("U: Create User\nQ: Quit")
if selection is "Q" or selection is "q":
print("Quitting")
sys.exit()
if selection is "U" or selection is "u":
print("User")
#do_something()
I modified the answer from rayzinnz to end the script with a specific key, in this case the escape key
import threading as th
import time
import keyboard
keep_going = True
def key_capture_thread():
global keep_going
a = keyboard.read_key()
if a== "esc":
keep_going = False
def do_stuff():
th.Thread(target=key_capture_thread, args=(), name='key_capture_thread', daemon=True).start()
i=0
while keep_going:
print('still going...')
time.sleep(1)
i=i+1
print (i)
print ("Schleife beendet")
do_stuff()
This is the solution I found with threads and standard libraries
Loop keeps going on until one key is pressed
Returns the key pressed as a single character string
Works in Python 2.7 and 3
import thread
import sys
def getch():
import termios
import sys, tty
def _getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
return _getch()
def input_thread(char):
char.append(getch())
def do_stuff():
char = []
thread.start_new_thread(input_thread, (char,))
i = 0
while not char :
i += 1
print "i = " + str(i) + " char : " + str(char[0])
do_stuff()
From following this thread down the rabbit hole, I came to this, works on Win10 and Ubuntu 20.04. I wanted more than just killing the script, and to use specific keys, and it had to work in both MS and Linux..
import _thread
import time
import sys
import os
class _Getch:
"""Gets a single character from standard input. Does not echo to the screen."""
def __init__(self):
try:
self.impl = _GetchWindows()
except ImportError:
self.impl = _GetchUnix()
def __call__(self): return self.impl()
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
class _GetchWindows:
def __init__(self):
import msvcrt
def __call__(self):
import msvcrt
msvcrt_char = msvcrt.getch()
return msvcrt_char.decode("utf-8")
def input_thread(key_press_list):
char = 'x'
while char != 'q': #dont keep doing this after trying to quit, or 'stty sane' wont work
time.sleep(0.05)
getch = _Getch()
char = getch.impl()
pprint("getch: "+ str(char))
key_press_list.append(char)
def quitScript():
pprint("QUITTING...")
time.sleep(0.2) #wait for the thread to die
os.system('stty sane')
sys.exit()
def pprint(string_to_print): #terminal is in raw mode so we need to append \r\n
print(string_to_print, end="\r\n")
def main():
key_press_list = []
_thread.start_new_thread(input_thread, (key_press_list,))
while True:
#do your things here
pprint("tick")
time.sleep(0.5)
if key_press_list == ['q']:
key_press_list.clear()
quitScript()
elif key_press_list == ['j']:
key_press_list.clear()
pprint("knock knock..")
elif key_press_list:
key_press_list.clear()
main()
This may be helpful
install pynput with --
pip install pynput
from pynput.keyboard import Key, Listener
def on_release(key):
if key == Key.esc:
# Stop listener
return False
# Collect events until released
while True:
with Listener(
on_release=on_release) as listener:
listener.join()
break
Here is a simple Windows solution that safely ends current iteration and then quits. I used it with a counter example that breaks the loop with 'Esc' key and quits. It uses kbhit() and getch() functions from msvcrt package. Time package is only called for easement reasons (to set time delay between events).
import msvcrt, time
print("Press 'Esc' to stop the loop...")
x = 0
while True:
x += 1
time.sleep(0.5)
print(x)
if msvcrt.kbhit():
if msvcrt.getch() == b'\x1b':
print("You have pressed Esc! See you!")
time.sleep(2)
break
kbhit() function returns True if a keypress is waiting to be read
getch() function reads a keypress and returns the resulting character as a byte string. It can be used with any key
b'\x1b' is the byte string character for the 'Esc' key.
Here another example using threading.Event, without the need for catching SIGINT (Ctrl+c).
As #Atcold has mentioned in a comment below the accepted answer, pressing Ctrl+c in the loop, may interrupt a long running operation and leave it in an undefined state. This can specially annoying, when that long running operation comes from a library that you are calling.
In the example below, the user needs to press q and then press Enter. If you want to capture the key stroke immediately, you need something like _Getch() from this answer.
import time
from threading import Thread, Event
def read_input(q_entered_event):
c = input()
if c == "q":
print("User entered q")
q_entered_event.set()
def do_long_running_stuff():
q_pressed_event = Event()
input_thread = Thread(target=read_input,
daemon=True,
args=(q_pressed_event,))
input_thread.start()
while True:
print("I am working ...")
time.sleep(1)
if q_pressed_event.is_set():
break
print("Process stopped by user.")
if __name__ == "__main__":
do_long_running_stuff()
from time import sleep
from threading import Thread
import threading
stop_flag = 0
def Wait_Char():
global stop_flag
v = input("Enter Char")
if(v == "z"):
stop_flag = 1
def h():
while(True):
print("Hello Feto")
time.sleep(1)
if(stop_flag == 1):
break
thread1 = Thread(target=Wait_Char)
thread2 = Thread(target=h)
thread1.start()
thread2.start()
print("threads finished...exiting")
This isn't the best way but it can do the job you want,
Running 2 Threads one waiting for the Key you want to stop the loop with
(Wait_Char Method)
and one for loop
(H Method)
And both see a global variable stop_flag which control the stoping process
Stop when I press z
from pynput import keyboard
def on_press(key):
if key == keyboard.Key.esc:
return False
i = 0
with keyboard.Listener(on_press=on_press) as listener:
# Your infinite loop
while listener.running:
print(i)
i=i+1
print("Done")
It works ...
import keyboard
while True:
print('please say yes')
if keyboard.is_pressed('y'):
break
print('i got u :) ')
print('i was trying to write you are a idiot ')
print(' :( ')
for enter use 'ENTER'

Categories