How to kill a while loop with a keystroke? - python

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'

Related

detect if pressed escape key during write input (keyboard) Python [duplicate]

I am making a stopwatch type program in Python and I would like to know how to detect if a key is pressed (such as p for pause and s for stop), and I would not like it to be something like raw_input, which waits for the user's input before continuing execution.
Anyone know how to do this in a while loop?
I would like to make this cross-platform but, if that is not possible, then my main development target is Linux.
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
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()
More things can be done with keyboard module.
You can install this module using pip install keyboard
Here are some of the methods:
Method #1:
Using the function read_key():
import keyboard
while True:
if keyboard.read_key() == "p":
print("You pressed p")
break
This is gonna break the loop as the key p is pressed.
Method #2:
Using function wait:
import keyboard
keyboard.wait("p")
print("You pressed p")
It will wait for you to press p and continue the code as it is pressed.
Method #3:
Using the function on_press_key:
import keyboard
keyboard.on_press_key("p", lambda _:print("You pressed p"))
It needs a callback function. I used _ because the keyboard function returns the keyboard event to that function.
Once executed, it will run the function when the key is pressed. You can stop all hooks by running this line:
keyboard.unhook_all()
Method #4:
This method is sort of already answered by user8167727 but I disagree with the code they made. It will be using the function is_pressed but in an other way:
import keyboard
while True:
if keyboard.is_pressed("p"):
print("You pressed p")
break
It will break the loop as p is pressed.
Method #5:
You can use keyboard.record as well. It records all keys pressed and released until you press the escape key or the one you've defined in until arg and returns a list of keyboard.KeyboardEvent elements.
import keyboard
keyboard.record(until="p")
print("You pressed p")
Notes:
keyboard will read keypresses from the whole OS.
keyboard requires root on linux
As OP mention about raw_input - that means he want cli solution.
Linux: curses is what you want (windows PDCurses). Curses, is an graphical API for cli software, you can achieve more than just detect key events.
This code will detect keys until new line is pressed.
import curses
import os
def main(win):
win.nodelay(True)
key=""
win.clear()
win.addstr("Detected key:")
while 1:
try:
key = win.getkey()
win.clear()
win.addstr("Detected key:")
win.addstr(str(key))
if key == os.linesep:
break
except Exception as e:
# No input
pass
curses.wrapper(main)
For Windows you could use msvcrt like this:
import msvcrt
while True:
if msvcrt.kbhit():
key = msvcrt.getch()
print(key) # just to show the result
Use this code for find the which key pressed
from pynput import keyboard
def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
# Stop listener
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
Use PyGame to have a window and then you can get the key events.
For the letter p:
import pygame, sys
import pygame.locals
pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
windowSurface.fill(BLACK)
while True:
for event in pygame.event.get():
if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
pass #Do what you want to here
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()
neoDev's comment at the question itself might be easy to miss, but it links to a solution not mentioned in any answer here.
There is no need to import keyboard with this solution.
Solution copied from this other question, all credits to #neoDev.
This worked for me on macOS Sierra and Python 2.7.10 and 3.6.3
import sys,tty,os,termios
def getkey():
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
while True:
b = os.read(sys.stdin.fileno(), 3).decode()
if len(b) == 3:
k = ord(b[2])
else:
k = ord(b)
key_mapping = {
127: 'backspace',
10: 'return',
32: 'space',
9: 'tab',
27: 'esc',
65: 'up',
66: 'down',
67: 'right',
68: 'left'
}
return key_mapping.get(k, chr(k))
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
try:
while True:
k = getkey()
if k == 'esc':
quit()
else:
print(k)
except (KeyboardInterrupt, SystemExit):
os.system('stty sane')
print('stopping.')
Non-root version that works even through ssh: sshkeyboard. Install with pip install sshkeyboard,
then write script such as:
from sshkeyboard import listen_keyboard
def press(key):
print(f"'{key}' pressed")
def release(key):
print(f"'{key}' released")
listen_keyboard(
on_press=press,
on_release=release,
)
And it will print:
'a' pressed
'a' released
When A key is pressed. ESC key ends the listening by default.
It requires less coding than for example curses, tkinter and getch. And it does not require root access like keyboard module.
You don't mention if this is a GUI program or not, but most GUI packages include a way to capture and handle keyboard input. For example, with tkinter (in Py3), you can bind to a certain event and then handle it in a function. For example:
import tkinter as tk
def key_handler(event=None):
if event and event.keysym in ('s', 'p'):
'do something'
r = tk.Tk()
t = tk.Text()
t.pack()
r.bind('<Key>', key_handler)
r.mainloop()
With the above, when you type into the Text widget, the key_handler routine gets called for each (or almost each) key you press.
I made this kind of game based on this post (using msvcr library and Python 3.7).
The following is the main function of the game, that is detecting the keys pressed:
import msvcrt
def _secret_key(self):
# Get the key pressed by the user and check if he/she wins.
bk = chr(10) + "-"*25 + chr(10)
while True:
print(bk + "Press any key(s)" + bk)
#asks the user to type any key(s)
kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Store key's value.
if r'\xe0' in kp:
kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Refactor the variable in case of multi press.
if kp == r'\xe0\x8a':
# If user pressed the secret key, the game ends.
# \x8a is CTRL+F12, that's the secret key.
print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
print("Press any key to exit the game")
msvcrt.getch()
break
else:
print(" You pressed:'", kp + "', that's not the secret key(s)\n")
if self.select_continue() == "n":
if self.secondary_options():
self._main_menu()
break
If you want the full source code of the program you can see it or download it from GitHub
The secret keypress is:
Ctrl+F12
Using the keyboard package, especially on linux is not an apt solution because that package requires root privileges to run. We can easily implement this with the getkey package. This is analogous to the C language function getchar.
Install it:
pip install getkey
And use it:
from getkey import getkey
while True: #Breaks when key is pressed
key = getkey()
print(key) #Optionally prints out the key.
break
We can add this in a function to return the pressed key.
def Ginput(str):
"""
Now, this function is like the native input() function. It can accept a prompt string, print it out, and when one key is pressed, it will return the key to the caller.
"""
print(str, end='')
while True:
key = getkey()
print(key)
return key
Use like this:
inp = Ginput("\n Press any key to continue: ")
print("You pressed " + inp)
import cv2
key = cv2.waitKey(1)
This is from the openCV package. The delay arg is the number of milliseconds it will wait for a keypress. In this case, 1ms. Per the docs, pollKey() can be used without waiting.
The curses module does that job.
You can test it running this example from the terminal:
import curses
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)
try:
while True:
char = screen.getch()
if char == ord('q'):
break
elif char == curses.KEY_UP:
print('up')
elif char == curses.KEY_DOWN:
print('down')
elif char == curses.KEY_RIGHT:
print('right')
elif char == curses.KEY_LEFT:
print('left')
elif char == ord('s'):
print('stop')
finally:
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
Here is a cross-platform solution, both blocking and non-blocking, not requiring any external libraries:
import contextlib as _contextlib
try:
import msvcrt as _msvcrt
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [frozenset(("\x00", "\xe0"))]
_next_input = _msvcrt.getwch
_set_terminal_raw = _contextlib.nullcontext
_input_ready = _msvcrt.kbhit
except ImportError: # Unix
import sys as _sys, tty as _tty, termios as _termios, \
select as _select, functools as _functools
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [
frozenset(("\x1b",)),
frozenset(("\x1b\x5b", "\x1b\x4f"))]
#_contextlib.contextmanager
def _set_terminal_raw():
fd = _sys.stdin.fileno()
old_settings = _termios.tcgetattr(fd)
try:
_tty.setraw(_sys.stdin.fileno())
yield
finally:
_termios.tcsetattr(fd, _termios.TCSADRAIN, old_settings)
_next_input = _functools.partial(_sys.stdin.read, 1)
def _input_ready():
return _select.select([_sys.stdin], [], [], 0) == ([_sys.stdin], [], [])
_MAX_ESCAPE_SEQUENCE_LENGTH = len(_ESCAPE_SEQUENCES)
def _get_keystroke():
key = _next_input()
while (len(key) <= _MAX_ESCAPE_SEQUENCE_LENGTH and
key in _ESCAPE_SEQUENCES[len(key)-1]):
key += _next_input()
return key
def _flush():
while _input_ready():
_next_input()
def key_pressed(key: str = None, *, flush: bool = True) -> bool:
"""Return True if the specified key has been pressed
Args:
key: The key to check for. If None, any key will do.
flush: If True (default), flush the input buffer after the key was found.
Return:
boolean stating whether a key was pressed.
"""
with _set_terminal_raw():
if key is None:
if not _input_ready():
return False
if flush:
_flush()
return True
while _input_ready():
keystroke = _get_keystroke()
if keystroke == key:
if flush:
_flush()
return True
return False
def print_key() -> None:
"""Print the key that was pressed
Useful for debugging and figuring out keys.
"""
with _set_terminal_raw():
_flush()
print("\\x" + "\\x".join(map("{:02x}".format, map(ord, _get_keystroke()))))
def wait_key(key=None, *, pre_flush=False, post_flush=True) -> str:
"""Wait for a specific key to be pressed.
Args:
key: The key to check for. If None, any key will do.
pre_flush: If True, flush the input buffer before waiting for input.
Useful in case you wish to ignore previously pressed keys.
post_flush: If True (default), flush the input buffer after the key was
found. Useful for ignoring multiple key-presses.
Returns:
The key that was pressed.
"""
with _set_terminal_raw():
if pre_flush:
_flush()
if key is None:
key = _get_keystroke()
if post_flush:
_flush()
return key
while _get_keystroke() != key:
pass
if post_flush:
_flush()
return key
You can use key_pressed() inside a while loop:
while True:
time.sleep(5)
if key_pressed():
break
You can also check for a specific key:
while True:
time.sleep(5)
if key_pressed("\x00\x48"): # Up arrow key on Windows.
break
Find out special keys using print_key():
>>> print_key()
# Press up key
\x00\x48
Or wait until a certain key is pressed:
>>> wait_key("a") # Stop and ignore all inputs until "a" is pressed.
You can use pygame's get_pressed():
import pygame
while True:
keys = pygame.key.get_pressed()
if (keys[pygame.K_LEFT]):
pos_x -= 5
elif (keys[pygame.K_RIGHT]):
pos_x += 5
elif (keys[pygame.K_UP]):
pos_y -= 5
elif (keys[pygame.K_DOWN]):
pos_y += 5
I was finding how to detect different key presses subsequently until e.g. Ctrl + C break the program from listening and responding to different key presses accordingly.
Using following code,
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
if keyboard.is_pressed("up"):
print("Reach the top!")
if keyboard.is_pressed("ctrl+c"):
break
It will cause the program to keep spamming the response text, if I pressed arrow down or arrow up. I believed because it's in a while-loop, and eventhough you only press once, but it will get triggered multiple times (as written in doc, I am awared of this after I read.)
At that moment, I still haven't went to read the doc, I try adding in time.sleep()
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
time.sleep(0.5)
if keyboard.is_pressed("up"):
print("Reach the top!")
time.sleep(0.5)
if keyboard.is_pressed("ctrl+c"):
break
This solves the spamming issue.
But this is not a very good way as of subsequent very fast taps on the arrow key, will only trigger once instead of as many times as I pressed, because the program will sleep for 0.5 second right, meant the "keyboard event" happened at that 0.5 second will not be counted.
So, I proceed to read the doc and get the idea to do this at this part.
while True:
# Wait for the next event.
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN and event.name == 'down':
# do whatever function you wanna here
if event.event_type == keyboard.KEY_DOWN and event.name == 'up':
# do whatever function you wanna here
if keyboard.is_pressed("ctrl+c"):
break
Now, it's working fine and great!
TBH, I am not deep dive into the doc, used to, but I have really forgetten the content, if you know or find any better way to do the similar function, please enlighten me!
Thank you, wish you have a great day ahead!

How do I run two tasks at the same time in Python? [duplicate]

I am making a stopwatch type program in Python and I would like to know how to detect if a key is pressed (such as p for pause and s for stop), and I would not like it to be something like raw_input, which waits for the user's input before continuing execution.
Anyone know how to do this in a while loop?
I would like to make this cross-platform but, if that is not possible, then my main development target is Linux.
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
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()
More things can be done with keyboard module.
You can install this module using pip install keyboard
Here are some of the methods:
Method #1:
Using the function read_key():
import keyboard
while True:
if keyboard.read_key() == "p":
print("You pressed p")
break
This is gonna break the loop as the key p is pressed.
Method #2:
Using function wait:
import keyboard
keyboard.wait("p")
print("You pressed p")
It will wait for you to press p and continue the code as it is pressed.
Method #3:
Using the function on_press_key:
import keyboard
keyboard.on_press_key("p", lambda _:print("You pressed p"))
It needs a callback function. I used _ because the keyboard function returns the keyboard event to that function.
Once executed, it will run the function when the key is pressed. You can stop all hooks by running this line:
keyboard.unhook_all()
Method #4:
This method is sort of already answered by user8167727 but I disagree with the code they made. It will be using the function is_pressed but in an other way:
import keyboard
while True:
if keyboard.is_pressed("p"):
print("You pressed p")
break
It will break the loop as p is pressed.
Method #5:
You can use keyboard.record as well. It records all keys pressed and released until you press the escape key or the one you've defined in until arg and returns a list of keyboard.KeyboardEvent elements.
import keyboard
keyboard.record(until="p")
print("You pressed p")
Notes:
keyboard will read keypresses from the whole OS.
keyboard requires root on linux
As OP mention about raw_input - that means he want cli solution.
Linux: curses is what you want (windows PDCurses). Curses, is an graphical API for cli software, you can achieve more than just detect key events.
This code will detect keys until new line is pressed.
import curses
import os
def main(win):
win.nodelay(True)
key=""
win.clear()
win.addstr("Detected key:")
while 1:
try:
key = win.getkey()
win.clear()
win.addstr("Detected key:")
win.addstr(str(key))
if key == os.linesep:
break
except Exception as e:
# No input
pass
curses.wrapper(main)
For Windows you could use msvcrt like this:
import msvcrt
while True:
if msvcrt.kbhit():
key = msvcrt.getch()
print(key) # just to show the result
Use this code for find the which key pressed
from pynput import keyboard
def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
# Stop listener
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
Use PyGame to have a window and then you can get the key events.
For the letter p:
import pygame, sys
import pygame.locals
pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
windowSurface.fill(BLACK)
while True:
for event in pygame.event.get():
if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
pass #Do what you want to here
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()
neoDev's comment at the question itself might be easy to miss, but it links to a solution not mentioned in any answer here.
There is no need to import keyboard with this solution.
Solution copied from this other question, all credits to #neoDev.
This worked for me on macOS Sierra and Python 2.7.10 and 3.6.3
import sys,tty,os,termios
def getkey():
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
while True:
b = os.read(sys.stdin.fileno(), 3).decode()
if len(b) == 3:
k = ord(b[2])
else:
k = ord(b)
key_mapping = {
127: 'backspace',
10: 'return',
32: 'space',
9: 'tab',
27: 'esc',
65: 'up',
66: 'down',
67: 'right',
68: 'left'
}
return key_mapping.get(k, chr(k))
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
try:
while True:
k = getkey()
if k == 'esc':
quit()
else:
print(k)
except (KeyboardInterrupt, SystemExit):
os.system('stty sane')
print('stopping.')
Non-root version that works even through ssh: sshkeyboard. Install with pip install sshkeyboard,
then write script such as:
from sshkeyboard import listen_keyboard
def press(key):
print(f"'{key}' pressed")
def release(key):
print(f"'{key}' released")
listen_keyboard(
on_press=press,
on_release=release,
)
And it will print:
'a' pressed
'a' released
When A key is pressed. ESC key ends the listening by default.
It requires less coding than for example curses, tkinter and getch. And it does not require root access like keyboard module.
You don't mention if this is a GUI program or not, but most GUI packages include a way to capture and handle keyboard input. For example, with tkinter (in Py3), you can bind to a certain event and then handle it in a function. For example:
import tkinter as tk
def key_handler(event=None):
if event and event.keysym in ('s', 'p'):
'do something'
r = tk.Tk()
t = tk.Text()
t.pack()
r.bind('<Key>', key_handler)
r.mainloop()
With the above, when you type into the Text widget, the key_handler routine gets called for each (or almost each) key you press.
I made this kind of game based on this post (using msvcr library and Python 3.7).
The following is the main function of the game, that is detecting the keys pressed:
import msvcrt
def _secret_key(self):
# Get the key pressed by the user and check if he/she wins.
bk = chr(10) + "-"*25 + chr(10)
while True:
print(bk + "Press any key(s)" + bk)
#asks the user to type any key(s)
kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Store key's value.
if r'\xe0' in kp:
kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Refactor the variable in case of multi press.
if kp == r'\xe0\x8a':
# If user pressed the secret key, the game ends.
# \x8a is CTRL+F12, that's the secret key.
print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
print("Press any key to exit the game")
msvcrt.getch()
break
else:
print(" You pressed:'", kp + "', that's not the secret key(s)\n")
if self.select_continue() == "n":
if self.secondary_options():
self._main_menu()
break
If you want the full source code of the program you can see it or download it from GitHub
The secret keypress is:
Ctrl+F12
Using the keyboard package, especially on linux is not an apt solution because that package requires root privileges to run. We can easily implement this with the getkey package. This is analogous to the C language function getchar.
Install it:
pip install getkey
And use it:
from getkey import getkey
while True: #Breaks when key is pressed
key = getkey()
print(key) #Optionally prints out the key.
break
We can add this in a function to return the pressed key.
def Ginput(str):
"""
Now, this function is like the native input() function. It can accept a prompt string, print it out, and when one key is pressed, it will return the key to the caller.
"""
print(str, end='')
while True:
key = getkey()
print(key)
return key
Use like this:
inp = Ginput("\n Press any key to continue: ")
print("You pressed " + inp)
import cv2
key = cv2.waitKey(1)
This is from the openCV package. The delay arg is the number of milliseconds it will wait for a keypress. In this case, 1ms. Per the docs, pollKey() can be used without waiting.
The curses module does that job.
You can test it running this example from the terminal:
import curses
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)
try:
while True:
char = screen.getch()
if char == ord('q'):
break
elif char == curses.KEY_UP:
print('up')
elif char == curses.KEY_DOWN:
print('down')
elif char == curses.KEY_RIGHT:
print('right')
elif char == curses.KEY_LEFT:
print('left')
elif char == ord('s'):
print('stop')
finally:
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
Here is a cross-platform solution, both blocking and non-blocking, not requiring any external libraries:
import contextlib as _contextlib
try:
import msvcrt as _msvcrt
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [frozenset(("\x00", "\xe0"))]
_next_input = _msvcrt.getwch
_set_terminal_raw = _contextlib.nullcontext
_input_ready = _msvcrt.kbhit
except ImportError: # Unix
import sys as _sys, tty as _tty, termios as _termios, \
select as _select, functools as _functools
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [
frozenset(("\x1b",)),
frozenset(("\x1b\x5b", "\x1b\x4f"))]
#_contextlib.contextmanager
def _set_terminal_raw():
fd = _sys.stdin.fileno()
old_settings = _termios.tcgetattr(fd)
try:
_tty.setraw(_sys.stdin.fileno())
yield
finally:
_termios.tcsetattr(fd, _termios.TCSADRAIN, old_settings)
_next_input = _functools.partial(_sys.stdin.read, 1)
def _input_ready():
return _select.select([_sys.stdin], [], [], 0) == ([_sys.stdin], [], [])
_MAX_ESCAPE_SEQUENCE_LENGTH = len(_ESCAPE_SEQUENCES)
def _get_keystroke():
key = _next_input()
while (len(key) <= _MAX_ESCAPE_SEQUENCE_LENGTH and
key in _ESCAPE_SEQUENCES[len(key)-1]):
key += _next_input()
return key
def _flush():
while _input_ready():
_next_input()
def key_pressed(key: str = None, *, flush: bool = True) -> bool:
"""Return True if the specified key has been pressed
Args:
key: The key to check for. If None, any key will do.
flush: If True (default), flush the input buffer after the key was found.
Return:
boolean stating whether a key was pressed.
"""
with _set_terminal_raw():
if key is None:
if not _input_ready():
return False
if flush:
_flush()
return True
while _input_ready():
keystroke = _get_keystroke()
if keystroke == key:
if flush:
_flush()
return True
return False
def print_key() -> None:
"""Print the key that was pressed
Useful for debugging and figuring out keys.
"""
with _set_terminal_raw():
_flush()
print("\\x" + "\\x".join(map("{:02x}".format, map(ord, _get_keystroke()))))
def wait_key(key=None, *, pre_flush=False, post_flush=True) -> str:
"""Wait for a specific key to be pressed.
Args:
key: The key to check for. If None, any key will do.
pre_flush: If True, flush the input buffer before waiting for input.
Useful in case you wish to ignore previously pressed keys.
post_flush: If True (default), flush the input buffer after the key was
found. Useful for ignoring multiple key-presses.
Returns:
The key that was pressed.
"""
with _set_terminal_raw():
if pre_flush:
_flush()
if key is None:
key = _get_keystroke()
if post_flush:
_flush()
return key
while _get_keystroke() != key:
pass
if post_flush:
_flush()
return key
You can use key_pressed() inside a while loop:
while True:
time.sleep(5)
if key_pressed():
break
You can also check for a specific key:
while True:
time.sleep(5)
if key_pressed("\x00\x48"): # Up arrow key on Windows.
break
Find out special keys using print_key():
>>> print_key()
# Press up key
\x00\x48
Or wait until a certain key is pressed:
>>> wait_key("a") # Stop and ignore all inputs until "a" is pressed.
You can use pygame's get_pressed():
import pygame
while True:
keys = pygame.key.get_pressed()
if (keys[pygame.K_LEFT]):
pos_x -= 5
elif (keys[pygame.K_RIGHT]):
pos_x += 5
elif (keys[pygame.K_UP]):
pos_y -= 5
elif (keys[pygame.K_DOWN]):
pos_y += 5
I was finding how to detect different key presses subsequently until e.g. Ctrl + C break the program from listening and responding to different key presses accordingly.
Using following code,
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
if keyboard.is_pressed("up"):
print("Reach the top!")
if keyboard.is_pressed("ctrl+c"):
break
It will cause the program to keep spamming the response text, if I pressed arrow down or arrow up. I believed because it's in a while-loop, and eventhough you only press once, but it will get triggered multiple times (as written in doc, I am awared of this after I read.)
At that moment, I still haven't went to read the doc, I try adding in time.sleep()
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
time.sleep(0.5)
if keyboard.is_pressed("up"):
print("Reach the top!")
time.sleep(0.5)
if keyboard.is_pressed("ctrl+c"):
break
This solves the spamming issue.
But this is not a very good way as of subsequent very fast taps on the arrow key, will only trigger once instead of as many times as I pressed, because the program will sleep for 0.5 second right, meant the "keyboard event" happened at that 0.5 second will not be counted.
So, I proceed to read the doc and get the idea to do this at this part.
while True:
# Wait for the next event.
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN and event.name == 'down':
# do whatever function you wanna here
if event.event_type == keyboard.KEY_DOWN and event.name == 'up':
# do whatever function you wanna here
if keyboard.is_pressed("ctrl+c"):
break
Now, it's working fine and great!
TBH, I am not deep dive into the doc, used to, but I have really forgetten the content, if you know or find any better way to do the similar function, please enlighten me!
Thank you, wish you have a great day ahead!

How to detect if a key is being held down [duplicate]

I am making a stopwatch type program in Python and I would like to know how to detect if a key is pressed (such as p for pause and s for stop), and I would not like it to be something like raw_input, which waits for the user's input before continuing execution.
Anyone know how to do this in a while loop?
I would like to make this cross-platform but, if that is not possible, then my main development target is Linux.
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
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()
More things can be done with keyboard module.
You can install this module using pip install keyboard
Here are some of the methods:
Method #1:
Using the function read_key():
import keyboard
while True:
if keyboard.read_key() == "p":
print("You pressed p")
break
This is gonna break the loop as the key p is pressed.
Method #2:
Using function wait:
import keyboard
keyboard.wait("p")
print("You pressed p")
It will wait for you to press p and continue the code as it is pressed.
Method #3:
Using the function on_press_key:
import keyboard
keyboard.on_press_key("p", lambda _:print("You pressed p"))
It needs a callback function. I used _ because the keyboard function returns the keyboard event to that function.
Once executed, it will run the function when the key is pressed. You can stop all hooks by running this line:
keyboard.unhook_all()
Method #4:
This method is sort of already answered by user8167727 but I disagree with the code they made. It will be using the function is_pressed but in an other way:
import keyboard
while True:
if keyboard.is_pressed("p"):
print("You pressed p")
break
It will break the loop as p is pressed.
Method #5:
You can use keyboard.record as well. It records all keys pressed and released until you press the escape key or the one you've defined in until arg and returns a list of keyboard.KeyboardEvent elements.
import keyboard
keyboard.record(until="p")
print("You pressed p")
Notes:
keyboard will read keypresses from the whole OS.
keyboard requires root on linux
As OP mention about raw_input - that means he want cli solution.
Linux: curses is what you want (windows PDCurses). Curses, is an graphical API for cli software, you can achieve more than just detect key events.
This code will detect keys until new line is pressed.
import curses
import os
def main(win):
win.nodelay(True)
key=""
win.clear()
win.addstr("Detected key:")
while 1:
try:
key = win.getkey()
win.clear()
win.addstr("Detected key:")
win.addstr(str(key))
if key == os.linesep:
break
except Exception as e:
# No input
pass
curses.wrapper(main)
For Windows you could use msvcrt like this:
import msvcrt
while True:
if msvcrt.kbhit():
key = msvcrt.getch()
print(key) # just to show the result
Use this code for find the which key pressed
from pynput import keyboard
def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
# Stop listener
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
Use PyGame to have a window and then you can get the key events.
For the letter p:
import pygame, sys
import pygame.locals
pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
windowSurface.fill(BLACK)
while True:
for event in pygame.event.get():
if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
pass #Do what you want to here
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()
neoDev's comment at the question itself might be easy to miss, but it links to a solution not mentioned in any answer here.
There is no need to import keyboard with this solution.
Solution copied from this other question, all credits to #neoDev.
This worked for me on macOS Sierra and Python 2.7.10 and 3.6.3
import sys,tty,os,termios
def getkey():
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
while True:
b = os.read(sys.stdin.fileno(), 3).decode()
if len(b) == 3:
k = ord(b[2])
else:
k = ord(b)
key_mapping = {
127: 'backspace',
10: 'return',
32: 'space',
9: 'tab',
27: 'esc',
65: 'up',
66: 'down',
67: 'right',
68: 'left'
}
return key_mapping.get(k, chr(k))
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
try:
while True:
k = getkey()
if k == 'esc':
quit()
else:
print(k)
except (KeyboardInterrupt, SystemExit):
os.system('stty sane')
print('stopping.')
Non-root version that works even through ssh: sshkeyboard. Install with pip install sshkeyboard,
then write script such as:
from sshkeyboard import listen_keyboard
def press(key):
print(f"'{key}' pressed")
def release(key):
print(f"'{key}' released")
listen_keyboard(
on_press=press,
on_release=release,
)
And it will print:
'a' pressed
'a' released
When A key is pressed. ESC key ends the listening by default.
It requires less coding than for example curses, tkinter and getch. And it does not require root access like keyboard module.
You don't mention if this is a GUI program or not, but most GUI packages include a way to capture and handle keyboard input. For example, with tkinter (in Py3), you can bind to a certain event and then handle it in a function. For example:
import tkinter as tk
def key_handler(event=None):
if event and event.keysym in ('s', 'p'):
'do something'
r = tk.Tk()
t = tk.Text()
t.pack()
r.bind('<Key>', key_handler)
r.mainloop()
With the above, when you type into the Text widget, the key_handler routine gets called for each (or almost each) key you press.
I made this kind of game based on this post (using msvcr library and Python 3.7).
The following is the main function of the game, that is detecting the keys pressed:
import msvcrt
def _secret_key(self):
# Get the key pressed by the user and check if he/she wins.
bk = chr(10) + "-"*25 + chr(10)
while True:
print(bk + "Press any key(s)" + bk)
#asks the user to type any key(s)
kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Store key's value.
if r'\xe0' in kp:
kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Refactor the variable in case of multi press.
if kp == r'\xe0\x8a':
# If user pressed the secret key, the game ends.
# \x8a is CTRL+F12, that's the secret key.
print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
print("Press any key to exit the game")
msvcrt.getch()
break
else:
print(" You pressed:'", kp + "', that's not the secret key(s)\n")
if self.select_continue() == "n":
if self.secondary_options():
self._main_menu()
break
If you want the full source code of the program you can see it or download it from GitHub
The secret keypress is:
Ctrl+F12
Using the keyboard package, especially on linux is not an apt solution because that package requires root privileges to run. We can easily implement this with the getkey package. This is analogous to the C language function getchar.
Install it:
pip install getkey
And use it:
from getkey import getkey
while True: #Breaks when key is pressed
key = getkey()
print(key) #Optionally prints out the key.
break
We can add this in a function to return the pressed key.
def Ginput(str):
"""
Now, this function is like the native input() function. It can accept a prompt string, print it out, and when one key is pressed, it will return the key to the caller.
"""
print(str, end='')
while True:
key = getkey()
print(key)
return key
Use like this:
inp = Ginput("\n Press any key to continue: ")
print("You pressed " + inp)
import cv2
key = cv2.waitKey(1)
This is from the openCV package. The delay arg is the number of milliseconds it will wait for a keypress. In this case, 1ms. Per the docs, pollKey() can be used without waiting.
The curses module does that job.
You can test it running this example from the terminal:
import curses
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)
try:
while True:
char = screen.getch()
if char == ord('q'):
break
elif char == curses.KEY_UP:
print('up')
elif char == curses.KEY_DOWN:
print('down')
elif char == curses.KEY_RIGHT:
print('right')
elif char == curses.KEY_LEFT:
print('left')
elif char == ord('s'):
print('stop')
finally:
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
Here is a cross-platform solution, both blocking and non-blocking, not requiring any external libraries:
import contextlib as _contextlib
try:
import msvcrt as _msvcrt
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [frozenset(("\x00", "\xe0"))]
_next_input = _msvcrt.getwch
_set_terminal_raw = _contextlib.nullcontext
_input_ready = _msvcrt.kbhit
except ImportError: # Unix
import sys as _sys, tty as _tty, termios as _termios, \
select as _select, functools as _functools
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [
frozenset(("\x1b",)),
frozenset(("\x1b\x5b", "\x1b\x4f"))]
#_contextlib.contextmanager
def _set_terminal_raw():
fd = _sys.stdin.fileno()
old_settings = _termios.tcgetattr(fd)
try:
_tty.setraw(_sys.stdin.fileno())
yield
finally:
_termios.tcsetattr(fd, _termios.TCSADRAIN, old_settings)
_next_input = _functools.partial(_sys.stdin.read, 1)
def _input_ready():
return _select.select([_sys.stdin], [], [], 0) == ([_sys.stdin], [], [])
_MAX_ESCAPE_SEQUENCE_LENGTH = len(_ESCAPE_SEQUENCES)
def _get_keystroke():
key = _next_input()
while (len(key) <= _MAX_ESCAPE_SEQUENCE_LENGTH and
key in _ESCAPE_SEQUENCES[len(key)-1]):
key += _next_input()
return key
def _flush():
while _input_ready():
_next_input()
def key_pressed(key: str = None, *, flush: bool = True) -> bool:
"""Return True if the specified key has been pressed
Args:
key: The key to check for. If None, any key will do.
flush: If True (default), flush the input buffer after the key was found.
Return:
boolean stating whether a key was pressed.
"""
with _set_terminal_raw():
if key is None:
if not _input_ready():
return False
if flush:
_flush()
return True
while _input_ready():
keystroke = _get_keystroke()
if keystroke == key:
if flush:
_flush()
return True
return False
def print_key() -> None:
"""Print the key that was pressed
Useful for debugging and figuring out keys.
"""
with _set_terminal_raw():
_flush()
print("\\x" + "\\x".join(map("{:02x}".format, map(ord, _get_keystroke()))))
def wait_key(key=None, *, pre_flush=False, post_flush=True) -> str:
"""Wait for a specific key to be pressed.
Args:
key: The key to check for. If None, any key will do.
pre_flush: If True, flush the input buffer before waiting for input.
Useful in case you wish to ignore previously pressed keys.
post_flush: If True (default), flush the input buffer after the key was
found. Useful for ignoring multiple key-presses.
Returns:
The key that was pressed.
"""
with _set_terminal_raw():
if pre_flush:
_flush()
if key is None:
key = _get_keystroke()
if post_flush:
_flush()
return key
while _get_keystroke() != key:
pass
if post_flush:
_flush()
return key
You can use key_pressed() inside a while loop:
while True:
time.sleep(5)
if key_pressed():
break
You can also check for a specific key:
while True:
time.sleep(5)
if key_pressed("\x00\x48"): # Up arrow key on Windows.
break
Find out special keys using print_key():
>>> print_key()
# Press up key
\x00\x48
Or wait until a certain key is pressed:
>>> wait_key("a") # Stop and ignore all inputs until "a" is pressed.
You can use pygame's get_pressed():
import pygame
while True:
keys = pygame.key.get_pressed()
if (keys[pygame.K_LEFT]):
pos_x -= 5
elif (keys[pygame.K_RIGHT]):
pos_x += 5
elif (keys[pygame.K_UP]):
pos_y -= 5
elif (keys[pygame.K_DOWN]):
pos_y += 5
I was finding how to detect different key presses subsequently until e.g. Ctrl + C break the program from listening and responding to different key presses accordingly.
Using following code,
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
if keyboard.is_pressed("up"):
print("Reach the top!")
if keyboard.is_pressed("ctrl+c"):
break
It will cause the program to keep spamming the response text, if I pressed arrow down or arrow up. I believed because it's in a while-loop, and eventhough you only press once, but it will get triggered multiple times (as written in doc, I am awared of this after I read.)
At that moment, I still haven't went to read the doc, I try adding in time.sleep()
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
time.sleep(0.5)
if keyboard.is_pressed("up"):
print("Reach the top!")
time.sleep(0.5)
if keyboard.is_pressed("ctrl+c"):
break
This solves the spamming issue.
But this is not a very good way as of subsequent very fast taps on the arrow key, will only trigger once instead of as many times as I pressed, because the program will sleep for 0.5 second right, meant the "keyboard event" happened at that 0.5 second will not be counted.
So, I proceed to read the doc and get the idea to do this at this part.
while True:
# Wait for the next event.
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN and event.name == 'down':
# do whatever function you wanna here
if event.event_type == keyboard.KEY_DOWN and event.name == 'up':
# do whatever function you wanna here
if keyboard.is_pressed("ctrl+c"):
break
Now, it's working fine and great!
TBH, I am not deep dive into the doc, used to, but I have really forgetten the content, if you know or find any better way to do the similar function, please enlighten me!
Thank you, wish you have a great day ahead!

How to do something till an input is detected in python3?

I want to execute a piece of code till the user enters an input(detects a random keypress), how do I do that in Python 3.x?
Here is the pseudo-code:
while input == False:
print(x)
You can do it like this:
try:
while True:
print("Running")
except KeyboardInterrupt:
print("User pressed CTRL+c. Program terminated.")
The user just need to press Control+c.
Python provide the built-in exception KeyboardInterrupt to handle this.
To do it with any random key-press with pynput
import threading
from pynput.keyboard import Key, Listener
class MyClass():
def __init__(self) -> None:
self.user_press = False
def RandomPress(self, key):
self.user_press = True
def MainProgram(self):
while self.user_press == False:
print("Running")
print("Key pressed, program stop.")
def Run(self):
t1 = threading.Thread(target=self.MainProgram)
t1.start()
# Collect events until released
with Listener(on_press=self.RandomPress) as listener:
listener.join()
MyClass().Run()
If you want to interact with users, you may follow the below way:
flag = input("please enter yes or no?")
if flag == "no":
print(x)

input 4 digit number after typing without pressing enter with python [duplicate]

I'm using raw_input in Python to interact with user in shell.
c = raw_input('Press s or n to continue:')
if c.upper() == 'S':
print 'YES'
It works as intended, but the user has to press enter in the shell after pressing 's'. Is there a way to accomplish what I need from an user input without needing to press enter in the shell? I'm using *nixes machines.
Under Windows, you need the msvcrt module, specifically, it seems from the way you describe your problem, the function msvcrt.getch:
Read a keypress and return the
resulting character. Nothing is echoed
to the console. This call will block
if a keypress is not already
available, but will not wait for Enter
to be pressed.
(etc -- see the docs I just pointed to). For Unix, see e.g. this recipe for a simple way to build a similar getch function (see also several alternatives &c in the comment thread of that recipe).
Actually in the meantime (almost 10 years from the start of this thread) a cross-platform module named pynput appeared.
Below a first cut - i.e. that works with lowercase 's' only.
I have tested it on Windows but I am almost 100% positive that it should work on Linux.
from pynput import keyboard
print('Press s or n to continue:')
with keyboard.Events() as events:
# Block for as much as possible
event = events.get(1e6)
if event.key == keyboard.KeyCode.from_char('s'):
print("YES")
Python does not provide a multiplatform solution out of the box.
If you are on Windows you could try msvcrt with:
import msvcrt
print 'Press s or n to continue:\n'
input_char = msvcrt.getch()
if input_char.upper() == 'S':
print 'YES'
curses can do that as well :
import curses, time
def input_char(message):
try:
win = curses.initscr()
win.addstr(0, 0, message)
while True:
ch = win.getch()
if ch in range(32, 127):
break
time.sleep(0.05)
finally:
curses.endwin()
return chr(ch)
c = input_char('Do you want to continue? y/[n]')
if c.lower() in ['y', 'yes']:
print('yes')
else:
print('no (got {})'.format(c))
To get a single character, I have used getch, but I don't know if it works on Windows.
Instead of the msvcrt module you could also use WConio:
>>> import WConio
>>> ans = WConio.getkey()
>>> ans
'y'
On a side note, msvcrt.kbhit() returns a boolean value determining if any key on the keyboard is currently being pressed.
So if you're making a game or something and want keypresses to do things but not halt the game entirely, you can use kbhit() inside an if statement to make sure that the key is only retrieved if the user actually wants to do something.
An example in Python 3:
# this would be in some kind of check_input function
if msvcrt.kbhit():
key = msvcrt.getch().decode("utf-8").lower() # getch() returns bytes data that we need to decode in order to read properly. i also forced lowercase which is optional but recommended
if key == "w": # here 'w' is used as an example
# do stuff
elif key == "a":
# do other stuff
elif key == "j":
# you get the point
I know this is old, but the solution wasn't good enough for me.
I need the solution to support cross-platform and without installing any external Python packages.
My solution for this, in case anyone else comes across this post
Reference: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
from tkinter import Tk, Frame
def __set_key(e, root):
"""
e - event with attribute 'char', the released key
"""
global key_pressed
if e.char:
key_pressed = e.char
root.destroy()
def get_key(msg="Press any key ...", time_to_sleep=3):
"""
msg - set to empty string if you don't want to print anything
time_to_sleep - default 3 seconds
"""
global key_pressed
if msg:
print(msg)
key_pressed = None
root = Tk()
root.overrideredirect(True)
frame = Frame(root, width=0, height=0)
frame.bind("<KeyRelease>", lambda f: __set_key(f, root))
frame.pack()
root.focus_set()
frame.focus_set()
frame.focus_force() # doesn't work in a while loop without it
root.after(time_to_sleep * 1000, func=root.destroy)
root.mainloop()
root = None # just in case
return key_pressed
def __main():
c = None
while not c:
c = get_key("Choose your weapon ... ", 2)
print(c)
if __name__ == "__main__":
__main()
If you can use an external library, blessed (cross platform) can do do this quite easily:
from blessed import Terminal
term = Terminal()
with term.cbreak(): # set keys to be read immediately
print("Press any key to continue")
inp = term.inkey() # wait and read one character
Note that while inside the with block, line editing capabilities of the terminal will be disabled.
Documentation for cbreak, inkey, and an example with inkey.
Standard library solution for Unix-like operating systems (including Linux):
def getch():
import sys, termios
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~termios.ICANON
new[6][termios.VMIN] = 1
new[6][termios.VTIME] = 0
try:
termios.tcsetattr(fd, termios.TCSAFLUSH, new)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
This works by putting the terminal into non-canonical input mode before reading from the terminal.
Alternative solution that does not echo the user's input (e.g. if the user presses z, z will not appear on screen):
def getch():
import sys, termios, tty
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
try:
tty.setcbreak(fd) # or tty.setraw(fd) if you prefer raw mode's behavior.
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
Usage example:
print('Press s or n to continue: ', end='', flush=True)
c = getch()
print()
if c.upper() == 'S':
print('YES')
use readchar:
import readchar
key = readchar.readkey()
if key == "a":
print("text")
https://pypi.org/project/readchar/ to webpage

Categories