Python has a keyboard module with many features. Install it, perhaps with this command:
pip3 install keyboard
Then use it in code like:
import keyboard # using module keyboard
while True: # making a loop
try: # used try so that if user pressed other than the given key error will not be shown
if keyboard.is_pressed('q'): # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
except:
break # if user pressed a key other than the given key the loop will break
Answer from user8167727 on Stack OverflowHow to detect a keypress when the program is running?
python - How can I check for a key press at any point during a loop? - Stack Overflow
python - How to kill a while loop with a keystroke? - Stack Overflow
How to break this loop in Python by detecting key press - Stack Overflow
Python has a keyboard module with many features. Install it, perhaps with this command:
pip3 install keyboard
Then use it in code like:
import keyboard # using module keyboard
while True: # making a loop
try: # used try so that if user pressed other than the given key error will not be shown
if keyboard.is_pressed('q'): # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
except:
break # if user pressed a key other than the given key the loop will break
For those who are on windows and were struggling to find an working answer here's mine: pynput.
Here is the pynput official "Monitoring the keyboard" source code example:
from pynput.keyboard import Key, Listener
def on_press(key):
print('{0} pressed'.format(
key))
def on_release(key):
print('{0} release'.format(
key))
if key == Key.esc:
# Stop listener
return False
# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
The function above will print whichever key you are pressing plus start an action as you release the 'esc' key. The keyboard documentation is here for a more variated usage.
Markus von Broady highlighted a potential issue that is: This answer doesn't require you being in the current window to this script be activated, a solution to windows would be:
from win32gui import GetWindowText, GetForegroundWindow
current_window = (GetWindowText(GetForegroundWindow()))
desired_window_name = "Stopwatch" #Whatever the name of your window should be
#Infinite loops are dangerous.
while True: #Don't rely on this line of code too much and make sure to adapt this to your project.
if current_window == desired_window_name:
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
I have a program which takes user input and outputs an answer. Now, I'd like to make it so that when the user presses a certain key, it exits the program. But how can you make it so that the program tries to detect that exit keypress at all times? Even when its looking for a user input?
I am only able to do one step at a time, like user input/output, then exit, or I can put exit first but that will just exit before anything happens
Thanks in advance!
Using callback is common approach in such case, here is solution:
import time
import keyboard
m = 2
s = 0
count_down = True
break_loop_flag = False
def handle_q_button():
print('q pressed')
global break_loop_flag
break_loop_flag = True
keyboard.add_hotkey('q', handle_q_button)
while True:
if break_loop_flag:
break
print(f"{m} minutes, {s} seconds")
if count_down:
if s == 0:
m -= 1q
s = 60
s -= 1
elif not count_down:
s += 1
if s == 60:
m += 1
s = 0
if m == 0 and s == 0:
count_down = False
time.sleep(1)
If you want to do any two things in parallel, independently of another, you need to consider using multiprocessing. However, even if you do, your loop will either still need to check if a key has been registered in the other process, or you need to terminate the process running the loop forcefully, which may result in unexpected outcomes.
However, in your case, since there are no side effects like files being written, this would work:
import time
import keyboard
from multiprocessing import Process
def print_loop():
m = 2
s = 0
count_down = True
while True:
print(f"{m} minutes, {s} seconds")
if count_down:
if s == 0:
m -= 1
s = 60
s -= 1
elif not count_down:
s += 1
if s == 60:
m += 1
s = 0
if m == 0 and s == 0:
count_down = False
time.sleep(1)
def main():
p = Process(target=print_loop)
p.start()
# this loop runs truly in parallel with the print loop, constantly checking
while True:
if keyboard.is_pressed('q'):
break
# force the print loop to stop immediately, without finishing the current iteration
p.kill()
if __name__ == '__main__':
main()
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()
You want your code to be more like this:
from subprocess import call
while True:
try:
call(["raspivid -n -b 2666666.67 -t 5000 -o test.mp4"], shell=True)
call(["raspivid -n -b 2666666.67 -t 5000 -o test1.mp4"], shell=True)
except KeyboardInterrupt:
break # The answer was in the question!
You break a loop exactly how you would expect.
Use a different thread to listen for a "ch".
import sys
import thread
import tty
import termios
from time import sleep
breakNow = False
def getch():
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
def waitForKeyPress():
global breakNow
while True:
ch = getch()
if ch == "b": # Or skip this check and just break
breakNow = True
break
thread.start_new_thread(waitForKeyPress, ())
print "That moment when I will break away!"
while breakNow == False:
sys.stdout.write("Do it now!\r\n")
sleep(1)
print "Finally!"
The standard approach is to use the select module.
However, this doesn't work on Windows. For that, you can use the msvcrt module's keyboard polling.
Often, this is done with multiple threads -- one per device being "watched" plus the background processes that might need to be interrupted by the device.
A solution using the curses module. Printing a numeric value corresponding to each key pressed:
import curses
def main(stdscr):
# do not wait for input when calling getch
stdscr.nodelay(1)
while True:
# get keyboard input, returns -1 if none available
c = stdscr.getch()
if c != -1:
# print numeric value
stdscr.addstr(str(c) + ' ')
stdscr.refresh()
# return curser to start position
stdscr.move(0, 0)
if __name__ == '__main__':
curses.wrapper(main)
One of the ways that you could do it is to create a new thread to run the key detector. Here's an example:
import threading
class KeyEventThread(threading.Thread):
def run(self):
# your while-loop here
kethread = KeyEventThread()
kethread.start()
Note that the while loop will not run until you call the thread's start() function. Also, it will not repeat the function automatically - you must wrap your code in a while-loop for it to repeat.
Do not call the thread's run() function explicitly, as that will cause the code to run in-line with all of the other code, not in a separate thread. You must use the start() function defined in threading.Thread so it can create the new thread.
Also note: If you plan on using the atexit module, creating new threads will make that module not work correctly. Just a heads-up. :)
I hope this helped!
It sounds like what you're looking for is a while loop based off of the input. If you put a list of desired states into an array, then you can check the input each time to see if it is one of the inputs you are trying to catch.
z = getch()
chars = [9, 27]
while ord(z) not in chars:
z = getch()
if ord(z) == 9:
do_something()
if ord(z) == 27:
do_something_else()
do_more_things()