diff --git a/click/_termui_impl.py b/click/_termui_impl.py index a4e421ecb..f44db5900 100644 --- a/click/_termui_impl.py +++ b/click/_termui_impl.py @@ -13,7 +13,7 @@ import sys import time import math - +import contextlib from ._compat import _default_text_stdout, range_type, PY2, isatty, \ open_stream, strip_ansi, term_len, get_best_encoding, WIN, int_types, \ CYGWIN @@ -525,6 +525,10 @@ def _translate_ch_to_exc(ch): if WIN: import msvcrt + @contextlib.contextmanager + def raw_terminal(): + yield + def getchar(echo): rv = msvcrt.getch() if echo: @@ -541,7 +545,8 @@ def getchar(echo): import tty import termios - def getchar(echo): + @contextlib.contextmanager + def raw_terminal(): if not isatty(sys.stdin): f = open('/dev/tty') fd = f.fileno() @@ -552,9 +557,7 @@ def getchar(echo): old_settings = termios.tcgetattr(fd) try: tty.setraw(fd) - ch = os.read(fd, 32) - if echo and isatty(sys.stdout): - sys.stdout.write(ch) + yield fd finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) sys.stdout.flush() @@ -562,5 +565,11 @@ def getchar(echo): f.close() except termios.error: pass - _translate_ch_to_exc(ch) - return ch.decode(get_best_encoding(sys.stdin), 'replace') + + def getchar(echo): + with raw_terminal() as fd: + ch = os.read(fd, 32) + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + _translate_ch_to_exc(ch) + return ch.decode(get_best_encoding(sys.stdin), 'replace') diff --git a/click/termui.py b/click/termui.py index f3dee0bdb..98bf6bd31 100644 --- a/click/termui.py +++ b/click/termui.py @@ -567,6 +567,11 @@ def getchar(echo=False): return f(echo) +def raw_terminal(): + from ._termui_impl import raw_terminal as f + return f() + + def pause(info='Press any key to continue ...', err=False): """This command stops execution and waits for the user to press any key to continue. This is similar to the Windows batch "pause"