from ctypes import windll, byref, c_int, create_unicode_buffer import io import sys import time kernel32 = windll.kernel32 GetStdHandle = kernel32.GetStdHandle ReadConsoleW = kernel32.ReadConsoleW WriteConsoleW = kernel32.WriteConsoleW STDIN_HANDLE = GetStdHandle(-10) STDOUT_HANDLE = GetStdHandle(-11) STDERR_HANDLE = GetStdHandle(-12) STDIN_FILENO = 0 STDOUT_FILENO = 1 STDERR_FILENO = 2 ENDLINE = "\r\n" EOF = "\x1a" CHUNK = 1024 class UnicodeConsoleIOBase(io.TextIOBase): encoding = "utf-8" errors = "strict" # input() raises (TypeError: bad argument type for built-in operation) without them defined # stdin shouldn't have stdin fileno – in that case GNU readline is called def __init__(self, name, handle): self.name = name self.handle = handle def __repr__(self): return "<{} {}>".format(self.__class__.__name__, repr(self.name)) def flush(self): pass def isatty(self): return True class UnicodeConsoleReader(UnicodeConsoleIOBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._buffer = "" def readable(self): return True @staticmethod def _read(n): characters_read = c_int() text = create_unicode_buffer(n) retval = ReadConsoleW(STDIN_HANDLE, text, n, byref(characters_read), None) if not characters_read.value: time.sleep(0.01) # wait for KeyboardInterrupt if not retval: raise OSError return text.value.replace(ENDLINE, "\n") def _read_prompt(self): # console reads whole lines # this will get the whole input so nothing lefts in console internal input buffer chunk = self._read(CHUNK) if chunk.startswith(EOF): raise EOFError else: self._buffer += chunk while not self._buffer.endswith("\n"): self._buffer += self._read(CHUNK) def read(self, n=None): if n is None: n = -1 if n < 0: try: while True: self._read_prompt() except EOFError: text = self._buffer self._buffer = "" return text else: try: while n > len(self._buffer): self._read_prompt() except EOFError: pass text, self._buffer = self._buffer[:n], self._buffer[n:] return text def readline(self, limit=None): if "\n" not in self._buffer: try: self._read_prompt() except EOFError: line = self._buffer self._buffer = "" return line buf = self._buffer index = buf.index("\n") + 1 line, self._buffer = buf[:index], buf[index:] return line class UnicodeConsoleWriter(UnicodeConsoleIOBase): def writeble(self): return True def write(self, text): text = text.replace("\n", ENDLINE) characters_written = c_int() retval = WriteConsoleW(self.handle, text, len(text), byref(characters_written), None) return characters_written.value unicode_in = UnicodeConsoleReader("stdin", STDIN_HANDLE) unicode_out = UnicodeConsoleWriter("stdout", STDOUT_HANDLE) unicode_err = UnicodeConsoleWriter("stderr", STDERR_HANDLE) def disable(): sys.stdin.flush() sys.stdout.flush() sys.stderr.flush() sys.stdin = sys.__stdin__ sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ def check_stream(stream, fileno): try: _fileno = stream.fileno() except io.UnsupportedOperation: return False else: if _fileno == fileno: stream.flush() return True else: return False def enable_reader(): if check_stream(sys.stdin, STDIN_FILENO): sys.stdin = unicode_in def enable_writer(): if check_stream(sys.stdout, STDOUT_FILENO): sys.stdout = unicode_out def enable_error_writer(): if check_stream(sys.stderr, STDERR_FILENO): sys.stderr = unicode_err def enable(): enable_reader() enable_writer() enable_error_writer()