Make text appear immediately on key press - python

I'm making a text based game and I want the user to be able to press enter while the text is appearing letter by letter to make the remaining of the text appear immediately.
This is my code so far
import time
import sys
def print(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.01)
def sceneOne():
print ("insert\n"
"text\n"
"here\n")
input("\n[Press enter to continue]\n")
print ("insert\n"
"text\n"
"here\n")
input("\n[Press enter to continue]\n")
sceneOne()
I want the "Press enter to continue" text to be under the "insert text here" while the text is appearing letter by letter so that the user can make the text appear faster if they have already played the game and want to speed run through this part to get to the next choice faster.

install the keyboard module and then you can create an event listener. Then, modify the print function so that it does not sleep if they hit enter. See below:
def print(s):
for c in s:
if keyboard.is_pressed('enter'):
sys.stdout.write(c)
sys.stdout.flush()
else:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)

Related

Python Keyboard module executing keys to next line in CLI

I am creating a simple number only user input for CLI and also created it. But while using keyboard module when the user tries to press enter, the program closes perfectly, but the text that user enters gets executed in command line.
import keyboard
specials = "1234567890"
userinput = ""
no_of_presses = 0
print("Number to be doubled : ",end="",flush=True)
def show(e):
global no_of_presses, userinput
if(e.name in specials):
print(e.name,end="",flush=True)
no_of_presses+=1
userinput+=e.name
def output(e):
global userinput
print(f"\noutput : {int(userinput)*2}")
keyboard.on_press(show)
keyboard.on_press_key("enter",output)
keyboard.wait("enter")
Here is the image of sample error I am getting

Is there any way to detect key press in Python?

I am wanting to make a program with different responses when you press a key. Is there any way that you can detect a key press in Python?
The program is like when you press 0, it will say you pressed 0 and when you pressed ctrl-c it will say that you interrupted the program, so on.
Can you do this in a while True: loop as well?
Also, I don't want it to be like input and I am using Linux (I don't want to have to use root).
Assuming you want a command line application
you should be able to do it with
import sys
import termios
import tty
custom_messages = {'a': 'some other message'}
custom_messages['b'] = 'what?';
stdin = sys.stdin.fileno()
tattr = termios.tcgetattr(stdin)
try:
tty.setcbreak(stdin, termios.TCSANOW)
while True:
char = sys.stdin.read(1)
print(custom_messages.get(char, 'You pressed ' + char))
except KeyboardInterrupt:
print('You interrupted')
sys.exit() ## ?
finally:
termios.tcsetattr(stdin, termios.TCSANOW, tattr)
I based my answer on disabling buffering in stdin

Why is input() being ignored?

Why is the input() after the if statement not working?
I need some help, the input() after the if statement is supposed to stop the script, however it just continues. If i give it another command, for example print("...") or time.sleep(10) it will execute, it is only the input() that does not work. Any ideas?
Edit: Because it might not be clear what the intention is. When asking for an input after the if statement the script should wait before continuing. This is because I want it to pause after I move the mouse so that it does not keep spamming the keys, but I am able to resume it if needed.
import time
from pynput.keyboard import Key, Controller as KeyController
from pynput.mouse import Controller as MouseController
key = KeyController()
mouse = MouseController()
def f1_toggle():
key.press(Key.f1)
key.release(Key.f1)
def enter_toggle():
key.press(Key.enter)
key.release(Key.enter)
input("Press any key to start:")
time.sleep(5)
while True:
start_position = mouse.position
key.press(Key.ctrl_l)
print("Ctrl pressed")
f1_toggle()
print("F1 toggled")
key.release(Key.ctrl_l)
print("Ctrl released")
time.sleep(1)
enter_toggle()
print("Enter toggled")
time.sleep(.5)
end_position = mouse.position
if start_position != end_position:
input("Press any key to continue ")
You're calling enter_toggle() before you ask for input. This is simulating pressing the Enter key. This is being used as the response to the input() call, so it doesn't wait for the user to enter something manually.
Are you sure the two variables are different?
I don't have pyinput, and I am using python 3.8, but in my computer, the input isn't skipped (I commented the pyinput).
Try this:
try:
input("Press any key to continue ")
except Exception as e:
print(e);
Try to see if this helps and what it prints.

I try to do a threading system in Python but I can't

I'm trying to make a threading system that continuously runs a while cycle but at the same time performs another function that is waiting for a string.
For example, a while cycle to write "Hello World" and a function waiting for something to be typed.
So i try with this code but it's not worked :(
import threading
from time import sleep
import time
data = []
def get_input():
data.append(input()) # Something akin to this
return data
input_thread = threading.Thread(target=get_input)
input_thread.start()
while (True):
print ("Hello World")
time.sleep(1)
input_thread.join()
if data.pop=="a":
print ("This message will be writed, only when user typed something")
A few things.
Check the array length before popping
The input thread must have a loop also
You need to press enter when you input a string
Here is the updated code:
import threading
from time import sleep
import time
data = []
def get_input():
while True:
data.append(input()) # must press enter to submit
input_thread = threading.Thread(target=get_input)
input_thread.start()
while (True):
print ("Hello World")
time.sleep(1)
if (len(data) and data.pop()=="a"):
print ("This message will be writed, only when user typed something")
input_thread.join() # never gets here

How to continue code after thread? Confused about the flow of this code

Sorry I'm new to programming, and don't really understand how this Thread thing works. My goal was for this input to be timed, and I found some code that does that. However, I'm confused about the structure of this Thread because if you are "too slow", the program never continues on to print "checkpoint" as desired. It just sort of... freezes... Why is it getting stuck?
import time
from threading import Thread
answer = None
def check():
# waits for user input for 3 seconds
for i in range(3):
time.sleep(1)
if answer != None:
return
print('too slow')
Thread(target = check).start()
answer = input("Input something: ")
print('checkpoint')
One thing I tried is:
t = Thread(target = check)
t.start()
answer = input("Input something: ")
# also tried t.join()
if t.is_alive:
print('hi')
I tried to solve this program by trying to raise and catch an exception. However, I couldn't catch the exception. How do I catch it? (Or is there another solution to the problem I am having?)
import time
from threading import Thread
answer = None
def check():
# waits for user input for 3 seconds
for i in range(3):
time.sleep(1)
if answer != None:
return
print('too slow')
# was hoping to catch this as an exception
raise TimeoutError
# starts new thread
Thread(target = check).start()
# prompts user for an input
answer = input("Input something: ")
print('checkpoint')
What's good:
When you type something into the input prompt within 3 seconds, it prints "checkpoint" and continues on with code.
What's bad:
If you take "too long", the program prints "too slow!" as expected, BUT then it stops executing code and just sort of... freezes. So to try to fix this, I was hoping to raise a Timeout Error and then catch it, but I don't know how to catch it. This didn't catch the error:
try:
Thread(target = check).start()
except:
pass
This didn't either:
try:
answer = input("Input something: ")
except:
pass
Could I get some help? Thank you!
Edit: Forgot to mention that I am using linux so a lot of the solutions for my application did not work for me like msvcrt or keyboard. And modules that do work for Linux seem not to be "non-blocking."
You should think of the two threads as two separate programs, but sharing the same variables.
Thread 1 consists of everything that isn't indented in your code. It launches a thread, then it waits for user input, then it prints "checkpoint". Then it's done.
Thread 2 consists of the function check. It checks to see if the variable isn't None. If that happens it's done. If that doesn't happen in three seconds, it prints "too slow" and now it's done.
Neither thread "knows" what the other one is doing, except they share one variable, answer.
The program as a whole will exit when all its threads are finished.
That's it. That's what you've written. So if you type something, the program exits because Thread 1 will always exit after you type something. Thread 2 exits once it sees the variable isn't None.
If you don't type anything, Thread 1 will just sit there and wait for you, forever. That's how the input function works. Thread 2 will exit after 3 seconds or less, but that doesn't affect Thread 1.
You can't throw an Exception from one Thread to another. So you can't throw an exception from Thread 2 and have Thread 1 handle it.
Have you tried typing something AFTER the message "too slow" appears? When you do, Thread 1 (and therefore your program) will exit.
The bottom line is that you can't use the input function in cases like this, because that function blocks the flow of its thread until the user types something. There is nothing any other thread can do to make it continue.
DISCLAIMER: THIS DOESN'T ANSWER THE QUESTION BUT IN CASE YOU WANT TO KNOW HOW I GOT AROUND THE "INPUT" THING, HERE IS MY SOLUTION TO THE PROBLEM.
Actually I found something that works! It's a little strange but it works for what I am trying to do, thanks to #rayryeng 's answer here: detect key press in python?.
Problem Statement: Continue the program when 'enter' is pressed, and timeout if input takes too long. This does exactly that, although it displays strangely to the console... PS. I had to run this in my terminal as 'sudo' or it wouldn't work in my scratch file for whatever reason.
import curses
import os
from time import time, sleep
def main(win):
win.nodelay(True) # True turns on "non-blocking"
key=""
win.clear()
win.addstr("Please press 'Enter' to continue:")
start_time = time()
while 1:
end_time = time()
try:
if end_time-start_time > 5: # 5 seconds
return 'You are too slow!'
else:
key = win.getkey()
if key == os.linesep:
return 'OK. Continuing on...'
except Exception as e:
# No input
pass
p = curses.wrapper(main)
print(p) #-> either 'You are too slow!' or 'OK. Continuing on...'
I guess if you actually wanted to store the input you can modify it to be something like this:
def main(win):
win.nodelay(True) # True turns on "non-blocking"
key=""
win.clear()
win.addstr("Please press 'Enter' to continue:")
start_time = time()
while 1:
end_time = time()
try:
if end_time-start_time > 5: # 5 seconds
return 'You are too slow!'
else:
key = win.getkey() # gets a single char
if key: # == os.linesep:
return str(key) # returns that single char
except Exception as e:
# No input
pass
p = curses.wrapper(main)
print(p) #-> either 'You are too slow!' or character entered
And if you want to store more characters you could do something like this (just be aware that it also stores the "enter" key in the resulting string):
import curses
import os
from time import time, sleep
def main(win):
win.nodelay(True) # True turns on "non-blocking"
key=""
win.clear()
win.addstr("Please press 'Enter' to continue:")
start_time = time()
result = key # empty string
while 1:
end_time = time()
try:
if end_time-start_time > 5: # 5 seconds
return 'You are too slow!'
else:
key = win.getkey() # gets single char
result = result + str(key) # adds characters to the empty string
if key == os.linesep: # "new line"
return result
except Exception as e:
# No input
pass
p = curses.wrapper(main)
print(p) #-> either 'You are too slow!' or characters entered

Categories