def __init__(self): # Event (handle) for registering this input in the event loop. # This event is set when there is data available to read from the pipe. # Note: We use this approach instead of using a regular pipe, like # returned from `os.pipe()`, because making such a regular pipe # non-blocking is tricky and this works really well. self._event = create_win32_event() self._closed = False # Parser for incoming keys. self._buffer = [] # Buffer to collect the Key objects. self.vt100_parser = Vt100Parser(lambda key: self._buffer.append(key)) # Identifier for every PipeInput for the hash. self.__class__._id += 1 self._id = self.__class__._id
def __init__(self): # Event (handle) for registering this input in the event loop. # This event is set when there is data available to read from the pipe. # Note: We use this approach instead of using a regular pipe, like # returned from `os.pipe()`, because making such a regular pipe # non-blocking is tricky and this works really well. self._event = create_win32_event() self._closed = False # Parser for incoming keys. self._buffer = [] # Buffer to collect the Key objects. self.vt100_parser = Vt100Parser( lambda key: self._buffer.append(key)) # Identifier for every PipeInput for the hash. self.__class__._id += 1 self._id = self.__class__._id
def add_win32_handle(self, handle: HANDLE, callback: Callable[[], None]) -> None: """ Add a Win32 handle to the event loop. """ handle_value = handle.value if handle_value is None: raise ValueError("Invalid handle.") # Make sure to remove a previous registered handler first. self.remove_win32_handle(handle) loop = get_event_loop() self._handle_callbacks[handle_value] = callback # Create remove event. remove_event = create_win32_event() self._remove_events[handle_value] = remove_event # Add reader. def ready() -> None: # Tell the callback that input's ready. try: callback() finally: run_in_executor_with_context(wait, loop=loop) # Wait for the input to become ready. # (Use an executor for this, the Windows asyncio event loop doesn't # allow us to wait for handles like stdin.) def wait() -> None: # Wait until either the handle becomes ready, or the remove event # has been set. result = wait_for_handles([remove_event, handle]) if result is remove_event: windll.kernel32.CloseHandle(remove_event) return else: loop.call_soon_threadsafe(ready) run_in_executor_with_context(wait, loop=loop)
def create(cls) -> Iterator["Win32PipeInput"]: event = create_win32_event() try: yield Win32PipeInput(_event=event) finally: windll.kernel32.CloseHandle(event)