Once I press "q" it prints this text many times. I want to print it once.
import keyboard
while True:
try:
if keyboard.is_pressed("q"):
print('q pressed')
except:
break
Your current code is constantly repeating check until q is pressed, which is not cpu efficient, and also once the q is pressed is_pressed will always be True - it does not automatically reset.
There is a good example of what you want in the docs. Do something like this:
keyboard.wait('q')
print('q pressed, continue...')
Note that this will block execution until q is pressed, and will continue after that. If you want to repeat process, simply put it inside while loop:
while True
keyboard.wait('q')
print('q pressed, waiting on it again...')
Hi you need to break in your try clause after printing in order for loop to end, just like you did in except;
while True:
try:
if keyboard.is_pressed("q"):
print('q pressed')
break
except:
break
The reason your code repeats is that you do not check for when q is released. this causes the condition if keyboard.is_pressed("q") to run multiple times
to stop this. you need to check for when q is released
for example
import keyboard
is_pressed = False
while True:
try:
if keyboard.is_pressed("q") && not is_pressed:
print('q pressed')
is_pressed = True:
if not keyboard.is_pressed("q"):
is_pressed = False
except:
break
Related
I recently got to know about the python module signal. With that, we can capture a SIGINT and do what we want after capturing it. I used it as below. In that case I am just using SIGINT to print that program is going to be stopped and stop the program.
import signal
import os
import time
def signalHandler(signalnumb, frame):
print("Signal Number:", signalnumb, " Frame: ", frame)
print('Exiting the program...')
os._exit(0)
signal.signal(signal.SIGINT, signalHandler)
c=0
# Loop infinite times using the while(1) which is always true
while 1:
print(c)
#sleep for 1 seconds using the sleep() function in time
time.sleep(1)
c=c+1
Now I want to give any signal from keyboard(for example pressing 'q') and as soon as signal was recieved, the python program should be stopped. Has anyone got some experience on how to do that? Any other method rather than using signal module (for example using multithreading) is accepted.
Edit1-
Later I tried to use pynput module as suggested in one of a similar kind of question. For sure I have done a mistake. It doesn't work as I expected. It means with a key press, I couldn't stop the for loop from running.
from pynput import keyboard
import time
def on_press(key):
for i in range(100):
print(i)
time.sleep(1)
if key == keyboard.Key.esc:
return False # stop listener
try:
k = key.char # single-char keys
except:
k = key.name # other keys
if k in ['1', '2', 'left', 'right']: # keys of interest
# self.keys.append(k) # store it in global-like variable
print('Key pressed: ' + k)
return False # stop listener; remove this if want more keys
listener = keyboard.Listener(on_press=on_press)
listener.start() # start to listen on a separate thread
listener.join() # remove if main thread is polling self.keyspython
Can someone point out how to do it using pynput in correct way?
This was my original implementation:
a = input('Press a key to exit')
if a:
exit(0)
However, it seems that you need a piece of code that will allow for any key to be clicked and immediately exit out of the program, without hitting enter afterwards. This may be a better way to do that:
import readchar
print("Press Any Key To Exit")
k = readchar.readchar()
Hope this helps!
After carefully understanding about the threads and pynput module, I managed to stop a for loop (or any program which runs as a separate thread) using a key press callback.
from pynput import keyboard
import os
import threading
import time
loop_running = False
def on_press(key):
print(dir(key))
global loop_running
#if key == keyboard.Key.delete and not loop_running:
if ('char' in dir(key)) and (key.char == 's') and (not loop_running):
t=threading.Thread(target=start_loop)
t.start()
#elif key==keyboard.Key.tab: #if this is used, the attributes related to 'key' will be changed. you can see them since I have used a print(dir(key))
elif key.char == 'q':
loop_running=False
def start_loop():
global loop_running
loop_running = True
for i in range(100):
if not loop_running:
os._exit(0)
print(i)
time.sleep(1)
with keyboard.Listener(on_press=on_press) as listner:
listner.join()
I have the following code:
while True:
try:
#DoSomething
except KeyboardInterrupt:
break
But instead of using Crtl + C, I want to type another key to end the loop. How can I do this?
You can use the keyboard module:
import keyboard
while True:
if keyboard.is_pressed("some key"):
break
do_something()
This will keep doing something until some key is pressed. Then, it will break out of the endless loop.
To catch hotkeys, use the add_hotkey function:
import keyboard
def handle_keypress(key):
global running
running = False
print(key + " was pressed!")
running = True
keyboard.add_hotkey("ctrl+e", lambda: handle_keypress("Ctrl-E"))
while running:
do_something()
Or you can use pynput:
from pynput.keyboard import Listener
def on_press(key):
print('{0} pressed'.format(
key))
with Listener(
on_press=on_press) as listener:
listener.join()
Here's a simple example of using that keyboard module I mentioned in my second comment. It handles most of steps I mentioned in my first comment and works on several platforms. The loop will stop if and when the user presses the Ctrl + B key.
Note that Ctrl + C will still raise a KeyboardInterrupt.
import keyboard
from time import sleep
def callback(keyname):
global stopped
print(f'{keyname} was pressed!')
stopped = True
keyboard.add_hotkey('ctrl+b', lambda: callback('Ctrl-B'))
stopped = False
print('Doing something...')
while not stopped:
sleep(1) # Something
print('-fini-')
The background is to design a program, which is running in an endless loop, to read live data from somewhere. I want this program to be controlled by interactions through keyboard (without 'Enter'). For this purpose I came across the following snippet.
import msvcrt
def keypress():
try:
if msvcrt.kbhit(): #Keyboard hit?
key = msvcrt.getch().decode("utf-8").lower()
return key
except UnicodeDecodeError:
pass
while not False:
print('rainy rainy rain rain')
if keypress() == "e": #e: exit
exit()
if keypress() == "w": # w: wait
waiting = True
while waiting == True:
print("waiting waiting waiting")
if keypress() == "w":
waiting = False
I know its frivolous to call a new endless loop just for waiting, but the crazy thing is the hit of "e" seems to be more often succesful than the hit of the "w". But in every case some few hits aren't even registered by no means at all. -> Is there way this issue can be solved? Windows as well is able to catch every keyboard hit!
while not False:
print('rainy rainy rain rain')
key = keypress()
if key == "e": #e: exit
exit()
if key == "w": # w: wait
waiting = True
while waiting == True:
print("waiting waiting waiting")
if keypress() == "w":
waiting = False
...this little change, solved the problem. I think calling the keypress() [and therefore also the msvcrt.getch() function] takes 'a lot' of time what prevents another keyboard hit from beeing recognized. But why? Shouldn't the hit of key beeing buffered!? And therefore the elapsed time shouldn't matter!?
So I'm trying to utilize msvcrt.getch() to make an option to quit(without using KeyBoardInterrupt) anywhere in the program.
My code currently looks like this:
import msvcrt
import sys
print("Press q at any time to quit")
while True:
pressedKey = msvcrt.getch()
if pressedKey == 'q':
sys.exit()
else:
# do some setup
if myvar == "string":
try:
# do stuff
except:
# do stuff
else:
#do stuff
How do I run the while loop to detect the keypress of q at the same time as I'm running the other (the # do stuff blocks)?
That way, if the user goes ahead with the program, they it'll only run it once. But if they hit q, then the program will quit.
You could read keys in a separate thread or (better) use msvcrt.kbhit() as #martineau suggested:
#!/usr/bin/env python
import msvcrt
from Queue import Empty, Queue
from threading import Thread
def read_keys(queue):
for key in iter(msvcrt.getch, 'q'): # until `q`
queue.put(key)
queue.put(None) # signal the end
q = Queue()
t = Thread(target=read_keys, args=[q])
t.daemon = True # die if the program exits
t.start()
while True:
try:
key = q.get_nowait() # doesn't block
except Empty:
key = Empty
else:
if key is None: # end
break
# do stuff
If I wanted to do something in the main code when the second thread detected a certain keypress, how would I act on that?
You do not react to the key press in the main thread until code reaches q.get_nowait() again i.e., you won't notice the key press until "do stuff" finishes the current iteration of the loop. If you need to do something that may take a long time then you might need to run it in yet another thread (start new thread or use a thread pool if blocking at some point is acceptable).
I have an infinite while loop that I want to break out of when the user presses a key. Usually I use raw_input to get the user's response; however, I need raw_input to not wait for the response. I want something like this:
print 'Press enter to continue.'
while True:
# Do stuff
#
# User pressed enter, break out of loop
This should be a simple, but I can't seem to figure it out. I'm leaning towards a solution using threading, but I would rather not have to do that. How can I accomplish this?
You can use non-blocking read from stdin:
import sys
import os
import fcntl
import time
fl = fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL)
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK)
while True:
print("Waiting for user input")
try:
stdin = sys.stdin.read()
if "\n" in stdin or "\r" in stdin:
break
except IOError:
pass
time.sleep(1)
I think you can do better with msvcrt:
import msvcrt, time
i = 0
while True:
i = i + 1
if msvcrt.kbhit():
if msvcrt.getwche() == '\r':
break
time.sleep(0.1)
print(i)
Sadly, still windows-specific.
On python 3.5 you can use the following code. It can be adjusted for a specific keystroke. The while loop will keep running until the user presses a key.
import time
import threading
# set global variable flag
flag = 1
def normal():
global flag
while flag==1:
print('normal stuff')
time.sleep(2)
if flag==False:
print('The while loop is now closing')
def get_input():
global flag
keystrk=input('Press a key \n')
# thread doesn't continue until key is pressed
print('You pressed: ', keystrk)
flag=False
print('flag is now:', flag)
n=threading.Thread(target=normal)
i=threading.Thread(target=get_input)
n.start()
i.start()
I could not get some of the popular answers working. So I came up with another approach using the CTRL + C to plug in user input and imbibe a keyboard interrupt. A simple solution can be using a try-catch block,
i = 0
try:
while True:
i+=1
print(i)
sleep(1)
except:
pass
# do what you want to do after it...
I got this idea from running a number of servers like flask and django. This might be slightly different from what the OP asked, but it might help someone else who wanted a similar thing.
Using the msvcrt module as thebjorn recommended I was able to come up with something that works. The following is a basic example that will exit the loop if any key is pressed, not just enter.
import msvcrt, time
i = 0
while True:
i = i + 1
if msvcrt.kbhit():
break
time.sleep(0.1)
print i
What you need is a non-blocking raw input, if you don't want to use threads there is a simple solution like this one below where he is doing a timeout of 20 ms and then raise and exception if the user doesn't press a key, if he does then the class returns the key pressed.
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
Source code
I have defined the function which ask number input from the user and returns the factorial of that number. If user wants to stop they have to press 0 and then it will exit from the loop. We can specify any specific key to input 'n' to exit from the loop.
import math
def factorial_func(n):
return math.factorial(n)
while True:
n = int(input("Please enter the number to find factorial: "))
print(factorial_func(n))
if n == 0:
exit()