Commits

anatoly techtonik  committed ca95a15

asynchronous input from windows console - working proof-of-concept
input buffer processing is tbd

  • Participants

Comments (0)

Files changed (1)

File asyncinput.py

+"""
+Example of non-blocking asyncronous console input using
+Windows API calls in Python.  This can become handy for
+async console tools such as IRC client.
+
+Public domain or MIT license
+by anatoly techtonik <techtonik@gmail.com>
+
+
+Notes:
+  1. WaitForMultipleObjects is used to listen for the
+     signals from process and stdin handles
+  2. When handle is signalled it remains in this state
+     until reset
+  3. msvcrt.* keyboard functions don't clear signalled
+     state from stdin handle, that's why console API
+     functions are used to clear the input buffer
+     instead of kbhit()/getch() loop
+"""
+
+
+import ctypes
+import ctypes.wintypes
+import subprocess
+
+# open notepad in separate process and monitor its execution
+# at the same time asyncronously processing events from
+# standard input without wasting 100% CPU on looping
+
+# OpenProcess desired access flag
+#   "the right to use the object for synchronization. This
+#    enables a thread to wait until the object is in the
+#    signaled state"
+SYNCHRONIZE=0x00100000L
+# Constant to get stdin handle with GetStdHandle() call
+STD_INPUT_HANDLE = -10
+# Constant for infinite timeout in WaitForMultipleObjects()
+INFINITE = -1
+
+
+np = subprocess.Popen([r"notepad"],
+       stdin=subprocess.PIPE,
+       stdout=subprocess.PIPE,
+       stderr=subprocess.PIPE,
+       shell=True)
+# OpenProcess returns handle that can be used in wait functions
+# params: desiredAccess, inheritHandle, processId
+nph = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, np.pid)
+print("Started Notepad with pid=%s, handle=%s" % (np.pid, nph))
+
+ch = ctypes.windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)
+
+handles = [ch, nph]
+while nph in handles:
+    print "Waiting for handles %s.." % handles
+    print "[q]uit, [s]top keyboard processing, launch bro[w]ser"
+
+    HandleArrayType = ctypes.wintypes.HANDLE * len(handles)
+    handle_array = HandleArrayType(*handles)
+    # params: count, handles, waitAll, milliseconds
+    ret = ctypes.windll.kernel32.WaitForMultipleObjects(
+            len(handle_array), handle_array, False, INFINITE)
+
+    if handles[ret] == ch:
+        """
+        # msvcrt won't work, because it doesn't reset
+        # signalled state of stdin handle
+        import msvcrt
+        while msvcrt.kbhit():
+            print "key!"
+            print msvcrt.getch()
+        continue
+        """
+
+    elif handles[ret] == nph:
+        print("Notepad is closed. Exiting..")
+        handles.remove(nph)
+    else:
+        print("Warning: Unknown return value '%s'" % ret)
+
+ctypes.windll.kernel32.CloseHandle(nph)
+print "Done."
+