Spaces:
No application file
No application file
| # -*- coding: utf-8 -*- | |
| """Module containing Windows version of :class:`Terminal`.""" | |
| from __future__ import absolute_import | |
| # std imports | |
| import time | |
| import msvcrt # pylint: disable=import-error | |
| import contextlib | |
| # 3rd party | |
| from jinxed import win32 # pylint: disable=import-error | |
| # local | |
| from .terminal import WINSZ | |
| from .terminal import Terminal as _Terminal | |
| class Terminal(_Terminal): | |
| """Windows subclass of :class:`Terminal`.""" | |
| def getch(self): | |
| r""" | |
| Read, decode, and return the next byte from the keyboard stream. | |
| :rtype: unicode | |
| :returns: a single unicode character, or ``u''`` if a multi-byte | |
| sequence has not yet been fully received. | |
| For versions of Windows 10.0.10586 and later, the console is expected | |
| to be in ENABLE_VIRTUAL_TERMINAL_INPUT mode and the default method is | |
| called. | |
| For older versions of Windows, msvcrt.getwch() is used. If the received | |
| character is ``\x00`` or ``\xe0``, the next character is | |
| automatically retrieved. | |
| """ | |
| if win32.VTMODE_SUPPORTED: | |
| return super(Terminal, self).getch() | |
| rtn = msvcrt.getwch() | |
| if rtn in ('\x00', '\xe0'): | |
| rtn += msvcrt.getwch() | |
| return rtn | |
| def kbhit(self, timeout=None): | |
| """ | |
| Return whether a keypress has been detected on the keyboard. | |
| This method is used by :meth:`inkey` to determine if a byte may | |
| be read using :meth:`getch` without blocking. This is implemented | |
| by wrapping msvcrt.kbhit() in a timeout. | |
| :arg float timeout: When ``timeout`` is 0, this call is | |
| non-blocking, otherwise blocking indefinitely until keypress | |
| is detected when None (default). When ``timeout`` is a | |
| positive number, returns after ``timeout`` seconds have | |
| elapsed (float). | |
| :rtype: bool | |
| :returns: True if a keypress is awaiting to be read on the keyboard | |
| attached to this terminal. | |
| """ | |
| end = time.time() + (timeout or 0) | |
| while True: | |
| if msvcrt.kbhit(): | |
| return True | |
| if timeout is not None and end < time.time(): | |
| break | |
| time.sleep(0.01) # Sleep to reduce CPU load | |
| return False | |
| def _winsize(fd): | |
| """ | |
| Return named tuple describing size of the terminal by ``fd``. | |
| :arg int fd: file descriptor queries for its window size. | |
| :rtype: WINSZ | |
| :returns: named tuple describing size of the terminal | |
| WINSZ is a :class:`collections.namedtuple` instance, whose structure | |
| directly maps to the return value of the :const:`termios.TIOCGWINSZ` | |
| ioctl return value. The return parameters are: | |
| - ``ws_row``: width of terminal by its number of character cells. | |
| - ``ws_col``: height of terminal by its number of character cells. | |
| - ``ws_xpixel``: width of terminal by pixels (not accurate). | |
| - ``ws_ypixel``: height of terminal by pixels (not accurate). | |
| """ | |
| window = win32.get_terminal_size(fd) | |
| return WINSZ(ws_row=window.lines, ws_col=window.columns, | |
| ws_xpixel=0, ws_ypixel=0) | |
| def cbreak(self): | |
| """ | |
| Allow each keystroke to be read immediately after it is pressed. | |
| This is a context manager for ``jinxed.w32.setcbreak()``. | |
| .. note:: You must explicitly print any user input you would like | |
| displayed. If you provide any kind of editing, you must handle | |
| backspace and other line-editing control functions in this mode | |
| as well! | |
| **Normally**, characters received from the keyboard cannot be read | |
| by Python until the *Return* key is pressed. Also known as *cooked* or | |
| *canonical input* mode, it allows the tty driver to provide | |
| line-editing before shuttling the input to your program and is the | |
| (implicit) default terminal mode set by most unix shells before | |
| executing programs. | |
| """ | |
| if self._keyboard_fd is not None: | |
| filehandle = msvcrt.get_osfhandle(self._keyboard_fd) | |
| # Save current terminal mode: | |
| save_mode = win32.get_console_mode(filehandle) | |
| save_line_buffered = self._line_buffered | |
| win32.setcbreak(filehandle) | |
| try: | |
| self._line_buffered = False | |
| yield | |
| finally: | |
| win32.set_console_mode(filehandle, save_mode) | |
| self._line_buffered = save_line_buffered | |
| else: | |
| yield | |
| def raw(self): | |
| """ | |
| A context manager for ``jinxed.w32.setcbreak()``. | |
| Although both :meth:`break` and :meth:`raw` modes allow each keystroke | |
| to be read immediately after it is pressed, Raw mode disables | |
| processing of input and output. | |
| In cbreak mode, special input characters such as ``^C`` are | |
| interpreted by the terminal driver and excluded from the stdin stream. | |
| In raw mode these values are receive by the :meth:`inkey` method. | |
| """ | |
| if self._keyboard_fd is not None: | |
| filehandle = msvcrt.get_osfhandle(self._keyboard_fd) | |
| # Save current terminal mode: | |
| save_mode = win32.get_console_mode(filehandle) | |
| save_line_buffered = self._line_buffered | |
| win32.setraw(filehandle) | |
| try: | |
| self._line_buffered = False | |
| yield | |
| finally: | |
| win32.set_console_mode(filehandle, save_mode) | |
| self._line_buffered = save_line_buffered | |
| else: | |
| yield | |