How to temporarily disable keyboard input using Python - python

I'm writing a simple program for Windows using Python, and this program takes advantage of the time module. Specifically, I'm using time.sleep(x) to pause the program for a short moment, generally 0.5-2 seconds. Here's basically what I'm doing:
import time
time.sleep(2)
while True:
x = input(prompt)
if x == 'spam':
break
The problem with this is, if the user presses enter while time.sleep has it paused, then those enters will be counted towards the input in the while loop. This results in prompt being printed several times, which is frustrating.
I want to know if there's a way to temporarily disable keyboard input while time.sleep is going on, and then enable it afterwards. Something like this:
import time
disable_keyboard_input()
time.sleep(2)
enable_keyboard_input()
while True:
etc.
Does anyone know of a way to do this using Python? Thank you in advance!

I found this worked brilliantly:
import time
class keyboardDisable():
def start(self):
self.on = True
def stop(self):
self.on = False
def __call__(self):
while self.on:
msvcrt.getwch()
def __init__(self):
self.on = False
import msvcrt
disable = keyboardDisable()
disable.start()
time.sleep(10)
disable.stop()
It stops the user from typing anything; when you press a key on the keyboard, nothing happens.

The other 2 answers are perfect if you are using it to make a real software and want to diable keyboard input only in the output screen. However, if it's for personal usage or you want to disable the keyboard for the whole system, you can use this code:
import keyboard
import time
a = int(input("Enter the time (in seconds) for which you want to disable keyboard: "))
for i in range(150):
keyboard.block_key(i)
time.sleep(a)
Don't forget to run pip install keyboard in the terminal before executing this code otherwise, you will get an error.

Try this.
stdout = sys.stdout
sys.stdout = sys.stderr
time.sleep(2)
sys.stdout = stdout
while True:
pass
Didn't tried this. But I hope all that was typed before sleep is ended will sended to stderr... Don't sure, but maybe Python have access to linux's std/null?

Related

Break loop using hotkey

There are hundreds of similar questions but none of them appear to be a solution in my case.
My code is shaped in this way
def iterative_func():
# do things
while True:
iterative_func()
Then I would like it to stop when I press a hotkey let's say 'ctrl+k'.
I tried pynput but the listener is not applicable since it waits for an Input and the rest of the script (iterative_func()) won't run, in my case the script should continuously run until I press some hotkey.
Also the solution
while True:
try:
iterative_func()
except KeyboardInterrupt:
break
doesn't work for me (I don't know why, but maybe it's because I'm running VSCode), anyway it's not code I want to implement because the script will be deployed as a .exe file.
PS.
I cannot import Key and Controller from pynput, it prompts an error and I have no clue on how to fix this so also solutions using these should be avoided.
I tried pynput but the listener is not applicable since it waits for
an Input and the rest of the script (iterative_func()) won't run
I can shed some light on how to overcome this problem, which made you optout pynput. See the below approach:
from pynput import keyboard
running = True # flag on loop runs
def stop_run(): # function to stop the program
global running
running = False
# register a hotkey, and call stop_run() when it is pressed
with keyboard.GlobalHotKeys({'<ctrl>+k': stop_run}) as h:
while running:
print("Running ... ")
This will run your code and wait for hotkey to stop the loop by a flag.

Whole program typing effect

I'm making a text adventure game in Python 3. Is there any way to add a typing effect to any text that gets printed without repeating a command after every line?
Assuming that with "typing effect" you mean that the messages should slowly appear one character at a time, you can define a function that iterates the given message and prints it one character at a time, using time.sleep in between to wait a bit. Make sure to flush the buffer after each character.
import time
def slow_print(msg):
for c in msg:
print(c, end="", flush=True)
time.sleep(0.1)
print()
slow_print("Hello World!")
If you really want to apply this for each and every output in your game (which I'd really not recommend) you can overwrite the print function, keeping a reference to the original print function to use within your new slow print function.
original_print = print
def slow_print(msg):
# same as above, but using original_print instead of print
print = slow_print
print("Hello World!")
You could also just def print(...) directly, but I'd recommend defining it as a separate function and then assigning it to print. This way, you can still make this optional, as this will most likely annoy the player after the first few minutes.
I assume you want the characters to appear as if someone were typing them so I'll just assume that
Import modules
import os
import sys
import time
from colr import color
Define your function
def function_name(phrase,speed,r_value,g_value,b_value):
for char in phrase:
sys.stdout.write(color(char, fore=(r_value,g_value,b_value)))
sys.stdout.flush()
time.sleep(speed)
Test the function
function_name("Hello",0.05,0,255,0)
#prints the phrase "Hello" in green text
Alternatively you could write the function using the threading library, which would allow users to skip the typing effect if they so wish.
import time, threading, os, sys, tty, termios
from colr import color
def slow_type_interrupt(phrase,speed,r_value,g_value,b_value):
done = False # this acts as the kill switch, using if statements, you can make certain button presses stop the message printing and outright display it
def type_out():
for char in phrase:
if done:
break
sys.stdout.write(color(char,fore=(r_value,g_value,b_value)))
sys.stdout.flush()
time.sleep(speed)
os.system('clear')
print(color(phrase,fore=(r_value,g_value,b_value)))
t = threading.Thread(target=type_out)
t.start()
def getkey():
ky = sys.stdin.fileno()
Ab = termios.tcgetattr(ky)
try:
tty.setraw(sys.stdin.fileno())
key = sys.stdin.read(1)
finally:
termios.tcsetattr(ky, termios.TCSADRAIN, Ab)
return key
while not done:
key_press = getkey()
if key_press == 'a': #You can replace a with whatever key you want to act as the "kill key"
done = True
os.system('clear')
print(color(phrase,fore=(r_value,g_value,b_value)))
slow_type_interrupt("Hello this is a test. Pressing 'a' will end this and immediatley display the message",.05,0,255,0)
As I mentioned in the comments of the code, a can be replaced by whatever you want. The reason I use this particular method for retrieving keypresses is because it works on almost anything that runs Python. I would suggest reading up on some other ways to retrieve keyboard inputs.
Hope I could help :)

Python: display dynamic information on user input

I would like to be able to receive command line input from user in a python script, and at the same time display to the user some dynamic information.
The user should be able to enter text, but this should not block the displaying of information.
My goal is to create a game, where I show users a countdown while they still have time to enter an answer.
Is this achievable?
Yeah. To create a countdown in the console, you could do something like this:
from time import sleep
for num in reversed(range(0,11)):
print(num)
sleep(1.0)
or
from time import sleep
time = 10
while time != 0:
print(time)
time = time - 1
sleep(1.0)
Either will countdown from 10 to 0 with a second in between each number. Since you might want the user to be able to enter answers as quickly or slowly as like before reaching 0... you might want to look into running two loops concurrently. this thread might be helpful for that. You'll want to figure out how to break out of both loops if the user gets the right answer (and have something come up that says they got the right answer) or if the user runs out of time.
Well sounded like an interesting thing to look into so I did, ran into a few problems pretty soon.
First, I was able to make a running counter but the problem is, since it is a loop, the next layer the counter loop will reset everything you've answered on the previous layer unless you've pressed enter to input answer(answer + enter , during that 1 second period).
if you are making reflex based thing that you only need to press single keys you might be able to succeed with my code by using module getch.
There were few modules that I could use for making the timer and program run at the same time, threading and multiprocessing(better results with threading).
It's basically a working thing if you just remove the counter function which adds the loop, but you won't see the timer.
Pygame might be a good thing to do this with, haven't used it myself but I'd presume so.
here is my code
import time
import threading
import os
timel = 5
def question():
q = input("",)
print(q)
if q == "2":
print("\nCorrect")
else:
exit("\nFalse, You lose!!")
def counter():
timel = 5
for i in range(0, timel):
print("How much is 1+1?", timel)
timel -= 1
time.sleep(1)
os.system("cls")
def timer(seconds):
time.sleep(seconds)
exit("\nTIMES UP, You lose!!")
def exit(msg):
print(msg)
os._exit(1)
def main():
thread = threading.Thread(target=timer, args=(int("{}".format(timel)),))
thread2 = threading.Thread(target=counter)
thread.start()
thread2.start()
question()
if __name__ == "__main__":
main()

How to have a continuous beep or other simple sound until key press event in python

I've written the following simple program in python in order for the user to test/adjust their sound volume. It uses winsound.Beep() to make a repeating beeping noise until it's interrupted by a msvcrt.kbhit() event, and uses threading to allow input while the winsound.Beep() is going on:
import winsound, threading, msvcrt
class soundThread(threading.Thread):
def __init__(self, threadID, pitch, duration):
threading.Thread.__init__(self)
self.threadID = threadID
self.pitch = pitch
self.duration = duration
def run(self):
soundTone(self.pitch,self.duration)
def soundTone(pitch,duration):
winsound.Beep(pitch,int(duration*1000))
def main():
"""main code module"""
print("The computer will play a beeping tone at a frequency of 440 MHz.")
print("It will continue to do so until you press a key which will cause the")
print("sound to stop and the program to exit. While the tone is sounding")
print("adjust your volume so that you can hear the tone clearly and")
print("comfortably.")
print("")
print("Tone starting now...")
loopBool = True
soundBool = True
i = 0;
while loopBool:
i+=1
# make beeping sound
if soundBool:
beep = soundThread(i,440,2.0)
beep.start()
# stop loop if a key is pressed
if msvcrt.kbhit():
loopBool = False
print("Key press detected. Waiting for sound to stop...")
# don't make new beep thread if current one is still active
if beep.isAlive():
soundBool = False
else:
soundBool = True
print("Sound stopped. Exiting program.")
if __name__ == '__main__':
main()
So the code itself works fine. However aesthetically I don't really like having the winsound.Beep() having to start and stop over and over again, and when a key is pressed the program has to wait for the current Beep() thread to end before the entire program can end. However, I can't think of any way to do it using winsound, and I can't find any other built in modules that allow simple generation of sounds like this.
I saw some very similar questions on this site, but all the solutions required non-standard modules like audiolab or PyMedia, but I'd like to do this using standard modules if possible. Is there some way to have a continuous beep until a keyboard interrupt, without having to install any non-standard modules? If there isn't any way with the basic modules, I'm using the Anaconda python distribution, so I at least have access to numpy and scipy, etc., though I kind of doubt those packages would be helpful here.
There is minor correction to your code.
The method name should be in snake_case:
# don't make new beep thread if current one is still active
if beep.is_alive():
not CamelCase:
# don't make new beep thread if current one is still active
if beep.isAlive():

How do I abort reading a user's input in Python 3.x?

I have a thread that monitors user input which looks like this:
def keyboard_monitor(temp): #temp is sys.stdin
global flag_exit
while True:
keyin = temp.readline().rstrip().lower()
if keyin == "exit":
flag_exit = True
print("Stopping...")
if flag_exit == True:
break
If I type exit the flag is properly set and all the other threads terminate. If another one of my threads sets the flag, this thread refuses to finish because it's hanging on the user input. I have to input something to get it to finish. How do I change this code so that the program finishes when the flag is set externally?
Its hard to tell exactly what is going wrong without more of your code, but as an easy solution you could rather exit() which is a python built in. This should reliably terminate the application, also sys.exit()
From wim's comment:
You can use the atexit module to register clean up handlers
import atexit
def cleanup():
pass
# TODO cleanup
atexit.register(cleanup)

Categories

Resources