Python: detect specific key press and prompt the user - python

I need to print out sentence "Hello World" every 10 seconds. However, if the user either 'c' or 'Enter', the program should stop printing the sentence and prompt the user to provide with the another sentence. The user-provided sentence is checked and if the sentence contains any digits, a message shows up: "cannot contain digits". Otherwise a message shows up: "correct sentence". After displaying either of the messages, the program continues printing "Hello World".
Here is the code I have strated with. Any hints on how to continue further would be greatly appreciated.
Thanks!
import threading
def looping():
threading.Timer(10.0, looping).start()
print("Hello World!")
looping()

From my understanding of your assignment's instructions, it looks like you're on the right track with using a timer to print "Hello World"! I'd like to upvote Irmen de Jong's comment on your question with regard to the statement "threads and console input/output don't work nicely together", since I've experienced this myself in C programming.
Once you have the timer going, the text it prints to the screen shouldn't have an effect on responding to keyboard input. If it's really required to respond directly to a keypress of 'c' (not followed by 'Enter', as one would normally have to do when reading input from the keyboard with input()), I recommend following one of the solutions in Python method for reading keypress? to figure out how you would like to implement that.
EDIT: Implementing a solution using a thread-based timer is a bit more tricky than I thought.
As you may have found in your research on this problem, the threading.Timer object has both start() and stop() methods that you can use to control the execution of individual thread timers if you've saved a reference to the timer in a variable (e.g. doing my_timer = threading.Timer(10.0, looping) then calling my_timer.start() to start the timer). If you do this, you may be able to call my_timer.stop() to pause the looping, provided you've kept a proper reference to the current timer instance that you need to stop at that point in time.
To make things a bit easier, I chose to create a global variable PAUSE_LOOPING that, when set to False, will stop a new timer instance from being started when looping is called, thereby halting all further repetitions of the function until PAUSE_LOOPING is set back to True and looping() is called again:
import threading
from msvcrt import getch
PAUSE_LOOPING = False
def looping():
global PAUSE_LOOPING
if not PAUSE_LOOPING:
threading.Timer(10.0, looping).start()
print("Hello World!")
looping()
while True:
# key = ord(getch())
# if key == 13: # Enter
# PAUSE_LOOPING = True
input_string = input()
if input_string == "":
PAUSE_LOOPING = True
else:
PAUSE_LOOPING = False
looping()
Commented out in the last code block is one way to grab a key press directly (without needing to press the 'Enter' key as is required by input()) taken from the stackoverflow question I linked to earlier in my answer. This should work as long as you're using Python for Windows (so you have the MS VC++ runtime library msvcrt installed), but to make the script stop when pressing 'Enter' you can use the standard input() function. In my example, typing any other string of characters before pressing 'Enter' will resume looping after it's been paused.
NOTE: Beware of using Python's IDLE to run this code. It won't work. Instead, you must run it from the command line.

Related

How to kill a thread that uses an input?

I am trying to make an online game using socket and threading. It is a competitive hangman game, where the fastest one to complete the word wins. I want that, when one of the players wins/runs out of lives, the other player gets kicked out of its game and is told that they have won/lost. However, I have run into a problem.
1: If I use "threading", there is no way to close the thread (since the program needs to read user input, I need to use the input() function, which means that the player's thread can't be terminated until they insert a character).
2: If I use "multiprocessing" (which has a terminate() function), I can't use input() (multiprocessing doesn't allow it).
I am in a stalemate, what should I do?
P.D: This is my first stackoverflow post ever, please tell me if I made a mistake at writing the post!
Ok, I got it, it is an ugly and complicated solution, but it works.
I created a program that emulates the "input" command, without being the input command itself (so it doesn't stop the processes).
Here it is:
import pynput.keyboard
global string
string=""
c=0
global oldprinted
oldprinted=""
def GetInput():
import pynput
def on_press(key):
global oldprinted
global string
if key==pynput.keyboard.Key.enter:
listener.stop()
else:
prompt="Introduce your input: "
try:
if key==pynput.keyboard.Key.backspace and len(string)>0:
string=string[:-1]
else:
string+=str(key.char)
prompt+=(string)
print(" "*len(oldprinted),end="\r")
print(prompt,end="\r")
oldprinted=prompt
except:
pass
print("Introduce your input: ",end="\r")
with pynput.keyboard.Listener(suppress=True,on_press=on_press) as listener:
listener.join()
return string
data=GetInput()
print("\n")

How to use Python keyboard module to persistently detect input?

I'm trying to write a script so that when I press "0" I will get an output, but I want to work without restarting the script, and I haven't been successful using the keyboard module which I've seen as being the most commonly used for detecting key inputs in Python.
What I have so far is
import keyboard
def goto(linenum):
global line
line = linenum
line = 1
if line == 1:
while True:
if keyboard.is_pressed('0'):
print('pressed 0')
break
goto(1)
What I tried doing was after the loop breaks to refer back to the beginning of the loop and try again from there, however the script ends after I press 0. If I remove the break then it constantly outputs "pressed 0", which is not what I want to happen.
You can use pynput to detect key input.
I would do something like this:
from pynput.keyboard import Key, Listener
def on_press(key):
if str(key).replace("'","") == '0':
print('pressed 0')
listener = Listener(on_press=on_press)
listener.start()
Once you start the listener, it will be always waiting for the key press and you can still add code after. In fact, with this example I recommend to add something after, maybe an input() so the script won't close immediately.
I think there are a few problems going on here.
goto is a pretty bad pattern to use and I don't think there's anything here to make your implementation work. It kinda sounds like you're going for some kind of recursion like approach here where when 0 is pressed, then it does some 'reset' and starts looping again. If that is the case you could do something like this:
def wait_for_zero():
# wait for press here
# Should add some sort of exit check too
# 'reset' logic, if any here
wait_for_zero()
looping with a weak condition is pretty fast cycling and generally a bad idea without some time delay. This is mentioned in the documentation for keybaord. There also is an example in the documentation for keyboard to wait for a keypress: https://github.com/boppreh/keyboard#waiting-for-a-key-press-one-time

Python Curses while Multithreading

I have a multithreaded program written in Python where I have a number of things happening at the same time:
reading raw data from an external source
organizing such data into different lists (parsing)
saving the post-parsed data into mass storage
some threads being used to flush some buffers from time to time and other optimizations
displaying parts of such data for real-time monitoring, using Curses.
The program is latency-sensitive, so I really need this to be multithreaded.
I got the curses thread to display correctly what I want to.
The problem is that while I had everything working without the curses thread, I had a "killswitch" in the main() function that terminated all activity at the press of a key.
I have this global variable called "killThreads" that goes into all functions who are called as threads, and all these functions only work as:
def oneThread():
while (not killThreads):
doStuff()
...
And then the main function defines the killThread as False, initializes all threads and turns the killThread as True after a raw_input():
killThreads=False
thisThread=threading.Thread(target=oneThread)
otherThread=threading.Thread(target=twoThread)
thisThread.setDaemon(True)
otherThread.setDaemon(True)
thisThread.start()
otherThread.start()
raw_input('Press to end the program')
killThreads=True
Everything ran fine until I ran a thread with the Curses module to display data.
It seems that while the Curses thread is on, it takes over all input commands. I tried to use getch() with no success. All I could do to keep everything running was to establish a timer within the Curses function:
def displayData():
screen=curses.initscr()
screen.nodelay(1)
timeKill=0
while (timeKill<80):
#stuff is drawn#
time.sleep(0.25)
timeKill+=1
Could anyone tell me how to go over Curses and get my keyboard input to "reach" the main function and kill all threads? Or do I always have to input to Curses and then make the Curses function alter the killThreads variable? If so, how do I do it (or where do I find the documentation for that)?
Thank you so much for your help.
Nice to meet you.
I'm trying to accomplish the same today. Look at this solution:
killThreads=False
thisThread=threading.Thread(target=oneThread)
otherThread=threading.Thread(target=twoThread)
thisThread.setDaemon(True)
otherThread.setDaemon(True)
thisThread.start()
otherThread.start()
raw_input('Press "q" to end the program')
key = ''
while key != ord('q'):
key = screen.getch()
killThreads=True
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
See, while will looping very fastly and waiting for q button be pressed, before switch your var killThreads to True.
It is pretty common practice. However, this while loop making thousands of idle loops in second, may be there can be more elegant way or better to embed into this while loop time.sleep(0.1) at least.

Correct way to pause a Python program

I've been using the input function as a way to pause my scripts:
print("something")
wait = input("Press Enter to continue.")
print("something")
Is there a formal way to do this?
It seems fine to me (or raw_input() in Python 2.X). Alternatively, you could use time.sleep() if you want to pause for a certain number of seconds.
import time
print("something")
time.sleep(5.5) # Pause 5.5 seconds
print("something")
For Windows only, use:
import os
os.system("pause")
So, I found this to work very well in my coding endeavors. I simply created a function at the very beginning of my program,
def pause():
programPause = raw_input("Press the <ENTER> key to continue...")
and now I can use the pause() function whenever I need to just as if I was writing a batch file. For example, in a program such as this:
import os
import system
def pause():
programPause = raw_input("Press the <ENTER> key to continue...")
print("Think about what you ate for dinner last night...")
pause()
Now obviously this program has no objective and is just for example purposes, but you can understand precisely what I mean.
NOTE: For Python 3, you will need to use input as opposed to raw_input
I assume you want to pause without input.
Use:
time.sleep(seconds)
I have had a similar question and I was using signal:
import signal
def signal_handler(signal_number, frame):
print "Proceed ..."
signal.signal(signal.SIGINT, signal_handler)
signal.pause()
So you register a handler for the signal SIGINT and pause waiting for any signal. Now from outside your program (e.g. in bash), you can run kill -2 <python_pid>, which will send signal 2 (i.e. SIGINT) to your python program. Your program will call your registered handler and proceed running.
I use the following for Python 2 and Python 3 to pause code execution until user presses Enter
import six
if six.PY2:
raw_input("Press the <Enter> key to continue...")
else:
input("Press the <Enter> key to continue...")
print ("This is how you pause")
input()
As pointed out by mhawke and steveha's comments, the best answer to this exact question would be:
Python 3.x:
input('Press <ENTER> to continue')
Python 2.x:
raw_input('Press <ENTER> to continue')
For a long block of text, it is best to use input('Press <ENTER> to continue') (or raw_input('Press <ENTER> to continue') on
Python 2.x) to prompt the user, rather than a time delay. Fast readers
won't want to wait for a delay, slow readers might want more time on
the delay, someone might be interrupted while reading it and want a
lot more time, etc. Also, if someone uses the program a lot, he/she
may become used to how it works and not need to even read the long
text. It's just friendlier to let the user control how long the block
of text is displayed for reading.
Anecdote: There was a time where programs used "press [ANY] key to continue". This failed because people were complaining they could not find the key ANY on their keyboard :)
Very simple:
raw_input("Press Enter to continue ...")
print("Doing something...")
By this method, you can resume your program just by pressing any specified key you've specified that:
import keyboard
while True:
key = keyboard.read_key()
if key == 'space': # You can put any key you like instead of 'space'
break
The same method, but in another way:
import keyboard
while True:
if keyboard.is_pressed('space'): # The same. you can put any key you like instead of 'space'
break
Note: you can install the keyboard module simply by writing this in you shell or cmd:
pip install keyboard
cross-platform way; works everywhere
import os, sys
if sys.platform == 'win32':
os.system('pause')
else:
input('Press any key to continue...')
I work with non-programmers who like a simple solution:
import code
code.interact(banner='Paused. Press ^D (Ctrl+D) to continue.', local=globals())
This produces an interpreter that acts almost exactly like the real interpreter, including the current context, with only the output:
Paused. Press ^D (Ctrl+D) to continue.
>>>
The Python Debugger is also a good way to pause.
import pdb
pdb.set_trace() # Python 2
or
breakpoint() # Python 3
I think I like this solution:
import getpass
getpass.getpass("Press Enter to Continue")
It hides whatever the user types in, which helps clarify that input is not used here.
But be mindful on the OS X platform. It displays a key which may be confusing.
Probably the best solution would be to do something similar to the getpass module yourself, without making a read -s call. Maybe making the foreground color match the background?
user12532854 suggested using keyboard.readkey() but the it requires specific key (I tried to run it with no input args but it ended up immediately returning 'enter' instead of waiting for the keystroke).
By phrasing the question in a different way (looking for getchar() equivalent in python), I discovered readchar.readkey() does the trick after exploring readchar package prompted by this answer.
import readchar
readchar.readkey()
For cross Python 2/3 compatibility, you can use input via the six library:
import six
six.moves.input( 'Press the <ENTER> key to continue...' )
I think that the best way to stop the execution is the time.sleep() function.
If you need to suspend the execution only in certain cases you can simply implement an if statement like this:
if somethinghappen:
time.sleep(seconds)
You can leave the else branch empty.

Avoiding raw_input to take keys pressed while in a loop for windows

I am trying to make a program which has a raw_input in a loop, if anyone presses a key while the long loop is running the next raw_input takes that as input, how do I avoid that?
I don't know what else to add to this simple question. Do let me know if more is required.
EDIT
Some code
for i in range(1000):
var = raw_input("Enter the number")
#.... do some long magic and stuff here which takes afew seconds
print 'Output is'+str(output)
So if someone presses something inside the magic phase, that is take as the input for the next loop. That is where the problem begins. (And yes the loop has to run for 1000 times).
This works for me with Windows 7 64bit, python 2.7.
import msvcrt
def flush_input():
while msvcrt.kbhit():
msvcrt.getch()
I put the OS in the title, window 7 64 bit to be specific. I saw the
answers there. They do apply but by god they are so big. Aren't there
other n00b friendly and safer ways to take inputs?
Let me try to explain why you need to do such an elaborate process. When you press a key it is stored in a section of computer memory called keyboard buffer (not to be confused with stdin buffer). This buffer stores the key's pressed until it is processed by your program. Python doesn't provide any platform independent wrapper to do this task. You have to rely on OS specific system calls to access this buffer, and flush it, read it or query it. msvcrt is a MS VC++ Runtime Library and python msvcrt provides a wrapper over it. Unless you wan't a platform independent solution, it is quite straight forward.
Use msvcrt getch to read a character from console. msvcrt.kbhit() to test if a key press is present in the keyboard buffer and so on. So as MattH has shown, it just a couple of lines code. And if you think you are a noob take this opportunity to learn something new.
Just collect your input outside of the loop (before you enter the loop). Do you really want the user to enter 1000 numbers? well maybe you do. but just include a loop at the top and collect the 1000 numbers at the start, and store them in an array.
then on the bottom half change your loop so it just does all the work. then if someone enters something no the keyboard, it doesn't really matter anymore.
something like this:
def getvars(top=1000):
vars = []
for i in range(0,top):
anum = int(raw_input('%d) Please enter another number: ' % i))
vars.append(anum)
return vars
def doMagic(numbers):
top = len(numbers)
for number in numbers:
# do magic number stuff
print 'this was my raw number %s' % number
if __name__ == "__main__":
numbers = getvars(top=10)
doMagic(numbers)
presented in a different sort of way and less os dependent
There is another way to do it that should work. I don't have a windows box handy to test it out on but its a trick i used to use and its rather undocumented. Perhaps I'm giving away secrets... but its basically like this: trick the os into thinking your app is a screensaver by calling the api that turns on the screensaver function at the start of your magic calculations. at the end of your magic calculations or when you are ready to accept input again, call the api again and turn off the screensaver functionality.
That would work.
There is another way to do it as well. Since you are in windows this will work too. but its a fair amount of work but not really too much. In windows, the window that is foreground (at the top of the Z order) that window gets the 'raw input thread'. The raw input thread receives the mouse and keyboard input. So to capture all input all you need to do is create a function that stands up a transparent or (non transparent) window that sits at the top of the Z order setWindowPos would do the trick , have it cover the entire screen and perhaps display a message such as Even Geduld or Please wait
when you are ready to prompt the user for more input, you use showwindow() to hide the window, show the previous results, get the input and then reshow the window and capture the keys/mouse all over again.
Of course all these solutions tie you to a particular OS unless you implement some sort of try/except handling and/or wrapping of the low level windows SDK calls.

Categories