Spaces:
No application file
No application file
File size: 5,804 Bytes
ba8d952 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# -*- 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
@staticmethod
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)
@contextlib.contextmanager
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
@contextlib.contextmanager
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
|