diff options
author | Chris Eibl <138194463+chris-eibl@users.noreply.github.com> | 2025-04-29 18:03:45 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-29 18:03:45 +0200 |
commit | acb222ce8ff1962b09112accabbcc4ed3d61cf6e (patch) | |
tree | 86d3a5231ce8a51cc616017d5f71f1e956d7f6ba /Lib | |
parent | ae37f3d3c0cc41a68174efd1a665f7baa0804801 (diff) | |
download | cpython-acb222ce8ff1962b09112accabbcc4ed3d61cf6e.tar.gz cpython-acb222ce8ff1962b09112accabbcc4ed3d61cf6e.zip |
GH-130328: pasting in new REPL is slow on Windows (GH-132884)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/_pyrepl/windows_console.py | 48 |
1 files changed, 27 insertions, 21 deletions
diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index 47fd3fd8f89..17942c8df07 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -22,8 +22,6 @@ from __future__ import annotations import io import os import sys -import time -import msvcrt import ctypes from ctypes.wintypes import ( @@ -44,7 +42,7 @@ from .utils import wlen from .windows_eventqueue import EventQueue try: - from ctypes import GetLastError, WinDLL, windll, WinError # type: ignore[attr-defined] + from ctypes import get_last_error, GetLastError, WinDLL, windll, WinError # type: ignore[attr-defined] except: # Keep MyPy happy off Windows from ctypes import CDLL as WinDLL, cdll as windll @@ -52,6 +50,9 @@ except: def GetLastError() -> int: return 42 + def get_last_error() -> int: + return 42 + class WinError(OSError): # type: ignore[no-redef] def __init__(self, err: int | None, descr: str | None = None) -> None: self.err = err @@ -108,6 +109,12 @@ CLEAR = "\x1b[H\x1b[J" ALT_ACTIVE = 0x01 | 0x02 CTRL_ACTIVE = 0x04 | 0x08 +WAIT_TIMEOUT = 0x102 +WAIT_FAILED = 0xFFFFFFFF + +# from winbase.h +INFINITE = 0xFFFFFFFF + class _error(Exception): pass @@ -409,12 +416,8 @@ class WindowsConsole(Console): return info.srWindow.Bottom # type: ignore[no-any-return] def _read_input(self, block: bool = True) -> INPUT_RECORD | None: - if not block: - events = DWORD() - if not GetNumberOfConsoleInputEvents(InHandle, events): - raise WinError(GetLastError()) - if not events.value: - return None + if not block and not self.wait(timeout=0): + return None rec = INPUT_RECORD() read = DWORD() @@ -522,14 +525,16 @@ class WindowsConsole(Console): def wait(self, timeout: float | None) -> bool: """Wait for an event.""" - # Poor man's Windows select loop - start_time = time.time() - while True: - if msvcrt.kbhit(): # type: ignore[attr-defined] - return True - if timeout and time.time() - start_time > timeout / 1000: - return False - time.sleep(0.01) + if timeout is None: + timeout = INFINITE + else: + timeout = int(timeout) + ret = WaitForSingleObject(InHandle, timeout) + if ret == WAIT_FAILED: + raise WinError(get_last_error()) + elif ret == WAIT_TIMEOUT: + return False + return True def repaint(self) -> None: raise NotImplementedError("No repaint support") @@ -649,14 +654,15 @@ if sys.platform == "win32": ReadConsoleInput.argtypes = [HANDLE, POINTER(INPUT_RECORD), DWORD, POINTER(DWORD)] ReadConsoleInput.restype = BOOL - GetNumberOfConsoleInputEvents = _KERNEL32.GetNumberOfConsoleInputEvents - GetNumberOfConsoleInputEvents.argtypes = [HANDLE, POINTER(DWORD)] - GetNumberOfConsoleInputEvents.restype = BOOL FlushConsoleInputBuffer = _KERNEL32.FlushConsoleInputBuffer FlushConsoleInputBuffer.argtypes = [HANDLE] FlushConsoleInputBuffer.restype = BOOL + WaitForSingleObject = _KERNEL32.WaitForSingleObject + WaitForSingleObject.argtypes = [HANDLE, DWORD] + WaitForSingleObject.restype = DWORD + OutHandle = GetStdHandle(STD_OUTPUT_HANDLE) InHandle = GetStdHandle(STD_INPUT_HANDLE) else: @@ -670,7 +676,7 @@ else: GetConsoleMode = _win_only SetConsoleMode = _win_only ReadConsoleInput = _win_only - GetNumberOfConsoleInputEvents = _win_only FlushConsoleInputBuffer = _win_only + WaitForSingleObject = _win_only OutHandle = 0 InHandle = 0 |