GH-130328: pasting in new REPL is slow on Windows (GH-132884)

This commit is contained in:
Chris Eibl 2025-04-29 18:03:45 +02:00 committed by GitHub
parent ae37f3d3c0
commit acb222ce8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 28 additions and 21 deletions

View file

@ -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