Python input single character without enter - python

What I am trying to do is make a simple pi memorization game in Python. What I need is a way to get input from the user without having to press 'enter' after every character. It sounds like I need something like getch, but I can't get it to work. I got a getch-like function from here: https://gist.github.com/chao787/2652257#file-getch-py. I don't really understand anything that's in there. When I do 'x = getch.getch()' it says "AttributeError: '_Getch' object has no attribute 'getch'". It looks like msvcrt can do it for Windows, but I have a Mac. It also looks like curses is a thing that has getch, but it says I need to do initscr first, but then I get the error "File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/curses/__init__.py", line 30, in initscr
fd=_sys.__stdout__.fileno())
_curses.error: setupterm: could not find terminal".
This is my file just using input, where you would have to press enter every time (I actually put in 1000 digits, not an ellipsis).
pi = '3.1415926535...'
def main():
print('Welcome to PiGame!')
pigame()
while True:
yn = input('Play again? y/n ')
if yn == 'y':
pigame()
else: return
def pigame():
n=0
print('Go!')
while n<=1000:
x = input()
if x == pi[n]:
n += 1
else:
print('I\'m sorry. The next digit was '+pi[n]+'.')
print('You got to '+str(n)+' digits!')
return
print('You got to 1000! Hooray!')

You can define your own version of getch using the termios, sys and tty packages:
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()

This is a tested (on RPi, Py 3) code that can read a specified length of chars without need to hit Enter button
But consider one thing :
This must run on terminal otherwise raises an error
import termios, sys , tty
def _getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1) #This number represents the length
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
getch = _getch()
print(getch)

Related

Python: input from keyboard and print at the same time [duplicate]

What I am trying to do is make a simple pi memorization game in Python. What I need is a way to get input from the user without having to press 'enter' after every character. It sounds like I need something like getch, but I can't get it to work. I got a getch-like function from here: https://gist.github.com/chao787/2652257#file-getch-py. I don't really understand anything that's in there. When I do 'x = getch.getch()' it says "AttributeError: '_Getch' object has no attribute 'getch'". It looks like msvcrt can do it for Windows, but I have a Mac. It also looks like curses is a thing that has getch, but it says I need to do initscr first, but then I get the error "File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/curses/__init__.py", line 30, in initscr
fd=_sys.__stdout__.fileno())
_curses.error: setupterm: could not find terminal".
This is my file just using input, where you would have to press enter every time (I actually put in 1000 digits, not an ellipsis).
pi = '3.1415926535...'
def main():
print('Welcome to PiGame!')
pigame()
while True:
yn = input('Play again? y/n ')
if yn == 'y':
pigame()
else: return
def pigame():
n=0
print('Go!')
while n<=1000:
x = input()
if x == pi[n]:
n += 1
else:
print('I\'m sorry. The next digit was '+pi[n]+'.')
print('You got to '+str(n)+' digits!')
return
print('You got to 1000! Hooray!')
You can define your own version of getch using the termios, sys and tty packages:
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()
This is a tested (on RPi, Py 3) code that can read a specified length of chars without need to hit Enter button
But consider one thing :
This must run on terminal otherwise raises an error
import termios, sys , tty
def _getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1) #This number represents the length
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
getch = _getch()
print(getch)

Sense CTRL+X while raw_input>

I have a script that looks like (I have imported all required modules.):
def _find_getch():
try:
import termios
except ImportError:
# Non-POSIX. Return msvcrt's (Windows') getch.
import msvcrt
return msvcrt.getch
# POSIX system. Create and return a getch that manipulates the tty.
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
getch = _find_getch()
#keypress for CTRL+X is 88
if len(sys.argv) == 1:
controlPressed = False
file = ''
while not controlPressed:
latest = raw_input("> ")
key = getch
if key == '<function _getch at 0x7f9602558e60>':
controlPressed = True
sys.exit()
I run this script in the terminal and it never senses when I press CTRL+X. How would I sense CTRL+X while raw_input is running?
The _getch function didn't work properly.

Why usage of end argument of print function changing the output time?

Maybe I wrote smth strange in a question title, I'l try to explain.
I'm trying to do password input as in linux-based systems (no symbols shows while you type).
I found one function that did it.
def getchar():
import tty, termios, sys
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
pwd = ''
print('Type password:', end=' ') # HERE IS THE PROBLEM
while True:
ch = getchar()
if ch == '\r':
break
pwd += ch
print(pwd)
If I do not use end argument it looks like that:
But with end argument:
Line 'Type password:' will appear after while loop end.
Why is this and what can I do?
By default, sys.stdout is line buffered, which means that anything written to it is buffered up until a newline is seen.
Because you replaced the standard end='\n' with a space, no newline is seen yet and the buffer is not flushed. Set flush=True to force a buffer flush anyway:
print('Type password:', end=' ', flush=True)

Python input without new line [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

raw_input without pressing enter

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

Resources