3 from ctypes import pythonapi, cdll, c_size_t, c_char_p, c_void_p, cast, CFUNCTYPE, POINTER, addressof
5 PyMem_Malloc = pythonapi.PyMem_Malloc
6 PyMem_Malloc.restype = c_size_t
7 PyMem_Malloc.argtypes = [c_size_t]
9 strncpy = cdll.msvcrt.strncpy
10 strncpy.restype = c_char_p
11 strncpy.argtypes = [c_char_p, c_char_p, c_size_t]
13 HOOKFUNC = CFUNCTYPE(c_char_p, c_void_p, c_void_p, c_char_p)
15 PyOS_ReadlineFunctionPointer = c_void_p.in_dll(pythonapi, "PyOS_ReadlineFunctionPointer")
18 def new_zero_terminated_string(b):
19 p = PyMem_Malloc(len(b) + 1)
20 strncpy(cast(p, c_char_p), b, len(b) + 1)
24 class ReadlineHookManager:
26 self.readline_wrapper_ref = HOOKFUNC(self.readline_wrapper)
27 self.address = c_void_p.from_address(addressof(self.readline_wrapper_ref)).value
28 self.original_address = PyOS_ReadlineFunctionPointer.value
29 self.readline_hook = None
31 def readline_wrapper(self, stdin, stdout, prompt):
34 if sys.stdin.encoding != sys.stdout.encoding:
35 raise ValueError("sys.stdin.encoding != sys.stdout.encoding, readline hook doesn't know, which one to use to decode prompt")
38 traceback.print_exc(file=sys.stderr)
40 prompt = prompt.decode("utf-8")
41 except UnicodeDecodeError:
45 prompt = prompt.decode(sys.stdout.encoding)
48 line = self.readline_hook(prompt)
49 except KeyboardInterrupt:
52 return new_zero_terminated_string(line.encode(sys.stdin.encoding))
55 print("Intenal win_unicode_console error", file=sys.stderr)
56 traceback.print_exc(file=sys.stderr)
57 return new_zero_terminated_string(b"\n")
59 def install_hook(self, hook):
60 self.readline_hook = hook
61 PyOS_ReadlineFunctionPointer.value = self.address
63 def restore_original(self):
64 self.readline_hook = None
65 PyOS_ReadlineFunctionPointer.value = self.original_address
69 sys.stdout.write(prompt)
71 return sys.stdin.readline()
74 class PyReadlineManager:
76 self.original_codepage = pyreadline.unicode_helper.pyreadline_codepage
78 def set_codepage(self, codepage):
79 pyreadline.unicode_helper.pyreadline_codepage = codepage
81 def restore_original(self):
82 self.set_codepage(self.original_codepage)
85 import pyreadline.unicode_helper
89 pyreadline_manager = PyReadlineManager()
91 manager = ReadlineHookManager()
94 def enable(*, use_pyreadline=True):
95 if use_pyreadline and pyreadline:
96 pyreadline_manager.set_codepage(sys.stdin.encoding)
97 # pyreadline assumes that encoding of all sys.stdio objects is the same
99 manager.install_hook(readline)
103 pyreadline_manager.restore_original()
105 manager.restore_original()