22
22
import io
23
23
import os
24
24
import sys
25
- import time
26
- import msvcrt
27
25
28
26
import ctypes
29
27
from ctypes .wintypes import (
44
42
from .windows_eventqueue import EventQueue
45
43
46
44
try :
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]
48
46
except :
49
47
# Keep MyPy happy off Windows
50
48
from ctypes import CDLL as WinDLL , cdll as windll
51
49
52
50
def GetLastError () -> int :
53
51
return 42
54
52
53
+ def get_last_error () -> int :
54
+ return 42
55
+
55
56
class WinError (OSError ): # type: ignore[no-redef]
56
57
def __init__ (self , err : int | None , descr : str | None = None ) -> None :
57
58
self .err = err
@@ -108,6 +109,12 @@ def __init__(self, err: int | None, descr: str | None = None) -> None:
108
109
ALT_ACTIVE = 0x01 | 0x02
109
110
CTRL_ACTIVE = 0x04 | 0x08
110
111
112
+ WAIT_TIMEOUT = 0x102
113
+ WAIT_FAILED = 0xFFFFFFFF
114
+
115
+ # from winbase.h
116
+ INFINITE = 0xFFFFFFFF
117
+
111
118
112
119
class _error (Exception ):
113
120
pass
@@ -409,12 +416,8 @@ def _getscrollbacksize(self) -> int:
409
416
return info .srWindow .Bottom # type: ignore[no-any-return]
410
417
411
418
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
418
421
419
422
rec = INPUT_RECORD ()
420
423
read = DWORD ()
@@ -522,14 +525,16 @@ def getpending(self) -> Event:
522
525
523
526
def wait (self , timeout : float | None ) -> bool :
524
527
"""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
533
538
534
539
def repaint (self ) -> None :
535
540
raise NotImplementedError ("No repaint support" )
@@ -649,14 +654,15 @@ class INPUT_RECORD(Structure):
649
654
ReadConsoleInput .argtypes = [HANDLE , POINTER (INPUT_RECORD ), DWORD , POINTER (DWORD )]
650
655
ReadConsoleInput .restype = BOOL
651
656
652
- GetNumberOfConsoleInputEvents = _KERNEL32 .GetNumberOfConsoleInputEvents
653
- GetNumberOfConsoleInputEvents .argtypes = [HANDLE , POINTER (DWORD )]
654
- GetNumberOfConsoleInputEvents .restype = BOOL
655
657
656
658
FlushConsoleInputBuffer = _KERNEL32 .FlushConsoleInputBuffer
657
659
FlushConsoleInputBuffer .argtypes = [HANDLE ]
658
660
FlushConsoleInputBuffer .restype = BOOL
659
661
662
+ WaitForSingleObject = _KERNEL32 .WaitForSingleObject
663
+ WaitForSingleObject .argtypes = [HANDLE , DWORD ]
664
+ WaitForSingleObject .restype = DWORD
665
+
660
666
OutHandle = GetStdHandle (STD_OUTPUT_HANDLE )
661
667
InHandle = GetStdHandle (STD_INPUT_HANDLE )
662
668
else :
@@ -670,7 +676,7 @@ def _win_only(*args, **kwargs):
670
676
GetConsoleMode = _win_only
671
677
SetConsoleMode = _win_only
672
678
ReadConsoleInput = _win_only
673
- GetNumberOfConsoleInputEvents = _win_only
674
679
FlushConsoleInputBuffer = _win_only
680
+ WaitForSingleObject = _win_only
675
681
OutHandle = 0
676
682
InHandle = 0
0 commit comments