2222import io
2323import os
2424import sys
25- import time
26- import msvcrt
2725
2826import ctypes
2927from ctypes .wintypes import (
4442from .windows_eventqueue import EventQueue
4543
4644try :
47- from ctypes import GetLastError , WinDLL , windll , WinError # type: ignore[attr-defined]
45+ from ctypes import get_last_error , GetLastError , WinDLL , windll , WinError # type: ignore[attr-defined]
4846except :
4947 # Keep MyPy happy off Windows
5048 from ctypes import CDLL as WinDLL , cdll as windll
5149
5250 def GetLastError () -> int :
5351 return 42
5452
53+ def get_last_error () -> int :
54+ return 42
55+
5556 class WinError (OSError ): # type: ignore[no-redef]
5657 def __init__ (self , err : int | None , descr : str | None = None ) -> None :
5758 self .err = err
@@ -108,6 +109,12 @@ def __init__(self, err: int | None, descr: str | None = None) -> None:
108109ALT_ACTIVE = 0x01 | 0x02
109110CTRL_ACTIVE = 0x04 | 0x08
110111
112+ WAIT_TIMEOUT = 0x102
113+ WAIT_FAILED = 0xFFFFFFFF
114+
115+ # from winbase.h
116+ INFINITE = 0xFFFFFFFF
117+
111118
112119class _error (Exception ):
113120 pass
@@ -409,12 +416,8 @@ def _getscrollbacksize(self) -> int:
409416 return info .srWindow .Bottom # type: ignore[no-any-return]
410417
411418 def _read_input (self , block : bool = True ) -> INPUT_RECORD | None :
412- if not block :
413- events = DWORD ()
414- if not GetNumberOfConsoleInputEvents (InHandle , events ):
415- raise WinError (GetLastError ())
416- if not events .value :
417- return None
419+ if not block and not self .wait (timeout = 0 ):
420+ return None
418421
419422 rec = INPUT_RECORD ()
420423 read = DWORD ()
@@ -522,14 +525,16 @@ def getpending(self) -> Event:
522525
523526 def wait (self , timeout : float | None ) -> bool :
524527 """Wait for an event."""
525- # Poor man's Windows select loop
526- start_time = time .time ()
527- while True :
528- if msvcrt .kbhit (): # type: ignore[attr-defined]
529- return True
530- if timeout and time .time () - start_time > timeout / 1000 :
531- return False
532- time .sleep (0.01 )
528+ if timeout is None :
529+ timeout = INFINITE
530+ else :
531+ timeout = int (timeout )
532+ ret = WaitForSingleObject (InHandle , timeout )
533+ if ret == WAIT_FAILED :
534+ raise WinError (get_last_error ())
535+ elif ret == WAIT_TIMEOUT :
536+ return False
537+ return True
533538
534539 def repaint (self ) -> None :
535540 raise NotImplementedError ("No repaint support" )
@@ -649,14 +654,15 @@ class INPUT_RECORD(Structure):
649654 ReadConsoleInput .argtypes = [HANDLE , POINTER (INPUT_RECORD ), DWORD , POINTER (DWORD )]
650655 ReadConsoleInput .restype = BOOL
651656
652- GetNumberOfConsoleInputEvents = _KERNEL32 .GetNumberOfConsoleInputEvents
653- GetNumberOfConsoleInputEvents .argtypes = [HANDLE , POINTER (DWORD )]
654- GetNumberOfConsoleInputEvents .restype = BOOL
655657
656658 FlushConsoleInputBuffer = _KERNEL32 .FlushConsoleInputBuffer
657659 FlushConsoleInputBuffer .argtypes = [HANDLE ]
658660 FlushConsoleInputBuffer .restype = BOOL
659661
662+ WaitForSingleObject = _KERNEL32 .WaitForSingleObject
663+ WaitForSingleObject .argtypes = [HANDLE , DWORD ]
664+ WaitForSingleObject .restype = DWORD
665+
660666 OutHandle = GetStdHandle (STD_OUTPUT_HANDLE )
661667 InHandle = GetStdHandle (STD_INPUT_HANDLE )
662668else :
@@ -670,7 +676,7 @@ def _win_only(*args, **kwargs):
670676 GetConsoleMode = _win_only
671677 SetConsoleMode = _win_only
672678 ReadConsoleInput = _win_only
673- GetNumberOfConsoleInputEvents = _win_only
674679 FlushConsoleInputBuffer = _win_only
680+ WaitForSingleObject = _win_only
675681 OutHandle = 0
676682 InHandle = 0
0 commit comments