Skip to content

Commit 7ee978a

Browse files
cleanup
1 parent ac510bb commit 7ee978a

File tree

1 file changed

+97
-83
lines changed

1 file changed

+97
-83
lines changed

src/prompt_toolkit/input/win32.py

Lines changed: 97 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def __init__(self, stdin: TextIO | None = None) -> None:
8181
self._use_virtual_terminal_input = _is_win_vt100_input_enabled()
8282

8383
if self._use_virtual_terminal_input:
84-
self.console_input_reader = Vt100InputReader()
84+
self.console_input_reader = Vt100ConsoleInputReader()
8585
else:
8686
self.console_input_reader = ConsoleInputReader()
8787

@@ -135,88 +135,6 @@ def handle(self) -> HANDLE:
135135
return self.console_input_reader.handle
136136

137137

138-
class Vt100InputReader:
139-
def __init__(self) -> None:
140-
self._fdcon = None
141-
142-
self._buffer: list[KeyPress] = [] # Buffer to collect the Key objects.
143-
self._vt100_parser = Vt100Parser(
144-
lambda key_press: self._buffer.append(key_press)
145-
)
146-
147-
# When stdin is a tty, use that handle, otherwise, create a handle from
148-
# CONIN$.
149-
self.handle: HANDLE
150-
if sys.stdin.isatty():
151-
self.handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
152-
else:
153-
self._fdcon = os.open("CONIN$", os.O_RDWR | os.O_BINARY)
154-
self.handle = HANDLE(msvcrt.get_osfhandle(self._fdcon))
155-
156-
def close(self) -> None:
157-
"Close fdcon."
158-
if self._fdcon is not None:
159-
os.close(self._fdcon)
160-
161-
def read(self) -> Iterable[KeyPress]:
162-
"""
163-
Return a list of `KeyPress` instances. It won't return anything when
164-
there was nothing to read. (This function doesn't block.)
165-
166-
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx
167-
"""
168-
max_count = 2048 # Max events to read at the same time.
169-
170-
read = DWORD(0)
171-
arrtype = INPUT_RECORD * max_count
172-
input_records = arrtype()
173-
174-
# Check whether there is some input to read. `ReadConsoleInputW` would
175-
# block otherwise.
176-
# (Actually, the event loop is responsible to make sure that this
177-
# function is only called when there is something to read, but for some
178-
# reason this happened in the asyncio_win32 loop, and it's better to be
179-
# safe anyway.)
180-
if not wait_for_handles([self.handle], timeout=0):
181-
return
182-
183-
# Get next batch of input event.
184-
windll.kernel32.ReadConsoleInputW(
185-
self.handle, pointer(input_records), max_count, pointer(read)
186-
)
187-
188-
# First, get all the keys from the input buffer, in order to determine
189-
# whether we should consider this a paste event or not.
190-
for key_data in self._get_keys(read, input_records):
191-
self._vt100_parser.feed(key_data)
192-
193-
# Return result.
194-
result = self._buffer
195-
self._buffer = []
196-
return result
197-
198-
def _get_keys(
199-
self, read: DWORD, input_records: Array[INPUT_RECORD]
200-
) -> Iterator[str]:
201-
"""
202-
Generator that yields `KeyPress` objects from the input records.
203-
"""
204-
for i in range(read.value):
205-
ir = input_records[i]
206-
207-
# Get the right EventType from the EVENT_RECORD.
208-
# (For some reason the Windows console application 'cmder'
209-
# [http://gooseberrycreative.com/cmder/] can return '0' for
210-
# ir.EventType. -- Just ignore that.)
211-
if ir.EventType in EventTypes:
212-
ev = getattr(ir.Event, EventTypes[ir.EventType])
213-
214-
# Process if this is a key event. (We also have mouse, menu and
215-
# focus events.)
216-
if isinstance(ev, KEY_EVENT_RECORD) and ev.KeyDown:
217-
yield ev.uChar.UnicodeChar
218-
219-
220138
class ConsoleInputReader:
221139
"""
222140
:param recognize_paste: When True, try to discover paste actions and turn
@@ -648,6 +566,102 @@ def _handle_mouse(self, ev: MOUSE_EVENT_RECORD) -> list[KeyPress]:
648566
return [KeyPress(Keys.WindowsMouseEvent, data)]
649567

650568

569+
class Vt100ConsoleInputReader:
570+
"""
571+
Similar to `ConsoleInputReader`, but for usage when
572+
`ENABLE_VIRTUAL_TERMINAL_INPUT` is enabled. This assumes that Windows sends
573+
us the right vt100 escape sequences and we parse those with our vt100
574+
parser.
575+
576+
(Using this instead of `ConsoleInputReader` results in the "data" attribute
577+
from the `KeyPress` instances to be more correct in edge cases, because
578+
this responds to for instance the terminal being in application cursor keys
579+
mode.)
580+
"""
581+
582+
def __init__(self) -> None:
583+
self._fdcon = None
584+
585+
self._buffer: list[KeyPress] = [] # Buffer to collect the Key objects.
586+
self._vt100_parser = Vt100Parser(
587+
lambda key_press: self._buffer.append(key_press)
588+
)
589+
590+
# When stdin is a tty, use that handle, otherwise, create a handle from
591+
# CONIN$.
592+
self.handle: HANDLE
593+
if sys.stdin.isatty():
594+
self.handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
595+
else:
596+
self._fdcon = os.open("CONIN$", os.O_RDWR | os.O_BINARY)
597+
self.handle = HANDLE(msvcrt.get_osfhandle(self._fdcon))
598+
599+
def close(self) -> None:
600+
"Close fdcon."
601+
if self._fdcon is not None:
602+
os.close(self._fdcon)
603+
604+
def read(self) -> Iterable[KeyPress]:
605+
"""
606+
Return a list of `KeyPress` instances. It won't return anything when
607+
there was nothing to read. (This function doesn't block.)
608+
609+
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx
610+
"""
611+
max_count = 2048 # Max events to read at the same time.
612+
613+
read = DWORD(0)
614+
arrtype = INPUT_RECORD * max_count
615+
input_records = arrtype()
616+
617+
# Check whether there is some input to read. `ReadConsoleInputW` would
618+
# block otherwise.
619+
# (Actually, the event loop is responsible to make sure that this
620+
# function is only called when there is something to read, but for some
621+
# reason this happened in the asyncio_win32 loop, and it's better to be
622+
# safe anyway.)
623+
if not wait_for_handles([self.handle], timeout=0):
624+
return
625+
626+
# Get next batch of input event.
627+
windll.kernel32.ReadConsoleInputW(
628+
self.handle, pointer(input_records), max_count, pointer(read)
629+
)
630+
631+
# First, get all the keys from the input buffer, in order to determine
632+
# whether we should consider this a paste event or not.
633+
for key_data in self._get_keys(read, input_records):
634+
self._vt100_parser.feed(key_data)
635+
636+
# Return result.
637+
result = self._buffer
638+
self._buffer = []
639+
return result
640+
641+
def _get_keys(
642+
self, read: DWORD, input_records: Array[INPUT_RECORD]
643+
) -> Iterator[str]:
644+
"""
645+
Generator that yields `KeyPress` objects from the input records.
646+
"""
647+
for i in range(read.value):
648+
ir = input_records[i]
649+
650+
# Get the right EventType from the EVENT_RECORD.
651+
# (For some reason the Windows console application 'cmder'
652+
# [http://gooseberrycreative.com/cmder/] can return '0' for
653+
# ir.EventType. -- Just ignore that.)
654+
if ir.EventType in EventTypes:
655+
ev = getattr(ir.Event, EventTypes[ir.EventType])
656+
657+
# Process if this is a key event. (We also have mouse, menu and
658+
# focus events.)
659+
if isinstance(ev, KEY_EVENT_RECORD) and ev.KeyDown:
660+
u_char = ev.uChar.UnicodeChar
661+
if u_char != "\x00":
662+
yield u_char
663+
664+
651665
class _Win32Handles:
652666
"""
653667
Utility to keep track of which handles are connectod to which callbacks.

0 commit comments

Comments
 (0)