You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/prompt_toolkit/eventloop/win32.py

219 lines
6.5 KiB

"""
Win32 event loop.
"""
from __future__ import unicode_literals
from ..win32_types import SECURITY_ATTRIBUTES
from .base import EventLoop
from .context import wrap_in_current_context
from .future import Future
from .inputhook import InputHookContext
from .utils import ThreadWithFuture
from ctypes import windll, pointer
from ctypes.wintypes import DWORD, BOOL, HANDLE
import msvcrt
__all__ = [
'Win32EventLoop',
'wait_for_handles',
'create_win32_event',
]
WAIT_TIMEOUT = 0x00000102
INFINITE = -1
class Win32EventLoop(EventLoop):
"""
Event loop for Windows systems.
:param recognize_paste: When True, try to discover paste actions and turn
the event into a BracketedPaste.
"""
def __init__(self, recognize_paste=True):
super(Win32EventLoop, self).__init__()
self._event = create_win32_event()
self._calls_from_executor = []
self.closed = False
self._running = False
# Additional readers.
self._read_fds = {} # Maps fd to handler.
# Create inputhook context.
self._inputhook_context = None
def run_until_complete(self, future, inputhook=None):
"""
Keep running the event loop until `future` has been set.
:param future: :class:`prompt_toolkit.eventloop.future.Future` object.
"""
assert isinstance(future, Future)
assert inputhook is None or callable(inputhook)
if self._running:
raise Exception('Event loop is already running')
if self.closed:
raise Exception('Event loop already closed.')
try:
self._running = True
while not future.done():
self._run_once(inputhook)
# Run one last time, to flush the pending `_calls_from_executor`s.
if self._calls_from_executor:
self._run_once(inputhook)
finally:
self._running = False
def _run_once(self, inputhook):
# Call inputhook.
if inputhook:
# Create input hook context.
if self._inputhook_context is None:
self._inputhook_context = InputHookContext()
def ready(wait):
" True when there is input ready. The inputhook should return control. "
return bool(self._ready_for_reading(INFINITE if wait else 0))
self._inputhook_context.call_inputhook(ready, inputhook)
# Wait for the next event.
handle = self._ready_for_reading(INFINITE)
if handle == self._event:
# When the Windows Event has been trigger, process the messages in the queue.
windll.kernel32.ResetEvent(self._event)
self._process_queued_calls_from_executor()
elif handle in self._read_fds:
callback = self._read_fds[handle]
self._run_task(callback)
def _run_task(self, t):
try:
t()
except BaseException as e:
self.call_exception_handler({
'exception': e
})
def _ready_for_reading(self, timeout=INFINITE):
"""
Return the handle that is ready for reading or `None` on timeout.
"""
handles = [self._event]
handles.extend(self._read_fds.keys())
return wait_for_handles(handles, timeout)
def close(self):
self.closed = True
# Clean up Event object.
windll.kernel32.CloseHandle(self._event)
if self._inputhook_context:
self._inputhook_context.close()
def run_in_executor(self, callback, _daemon=False):
"""
Run a long running function in a background thread.
(This is recommended for code that could block the event loop.)
Similar to Twisted's ``deferToThread``.
"""
th = ThreadWithFuture(callback, daemon=_daemon)
# Wait until the main thread is idle for an instant before starting the
# executor. (Like in eventloop/posix.py, we start the executor using
# `call_from_executor`.)
self.call_from_executor(th.start)
return th.future
def call_from_executor(self, callback, _max_postpone_until=None):
"""
Call this function in the main event loop.
Similar to Twisted's ``callFromThread``.
"""
callback = wrap_in_current_context(callback)
# Append to list of pending callbacks.
self._calls_from_executor.append(callback)
# Set Windows event.
windll.kernel32.SetEvent(self._event)
def _process_queued_calls_from_executor(self):
# Process calls from executor.
calls_from_executor = self._calls_from_executor[:]
del self._calls_from_executor[:]
for c in calls_from_executor:
self._run_task(c)
def add_reader(self, fd, callback):
" Start watching the file descriptor for read availability. "
callback = wrap_in_current_context(callback)
h = msvcrt.get_osfhandle(fd)
self.add_win32_handle(h, callback)
def remove_reader(self, fd):
" Stop watching the file descriptor for read availability. "
h = msvcrt.get_osfhandle(fd)
self.remove_win32_handle(h)
def add_win32_handle(self, handle, callback):
" Add a Win32 handle to the event loop. "
callback = wrap_in_current_context(callback)
self._read_fds[handle] = callback
def remove_win32_handle(self, handle):
" Remove a Win32 handle from the event loop. "
if handle in self._read_fds:
del self._read_fds[handle]
def wait_for_handles(handles, timeout=INFINITE):
"""
Waits for multiple handles. (Similar to 'select') Returns the handle which is ready.
Returns `None` on timeout.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx
"""
assert isinstance(handles, list)
assert isinstance(timeout, int)
arrtype = HANDLE * len(handles)
handle_array = arrtype(*handles)
ret = windll.kernel32.WaitForMultipleObjects(
len(handle_array), handle_array, BOOL(False), DWORD(timeout))
if ret == WAIT_TIMEOUT:
return None
else:
h = handle_array[ret]
return h
def create_win32_event():
"""
Creates a Win32 unnamed Event .
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx
"""
return windll.kernel32.CreateEventA(
pointer(SECURITY_ATTRIBUTES()),
BOOL(True), # Manual reset event.
BOOL(False), # Initial state.
None # Unnamed event object.
)