windows - Key echo in Python in separate thread doesn't display first key stroke -


i try post minimal working example, unfortunately problem requires lot of pieces have stripped down best can.

first of all, i'm using simple script simulates pressing keys through function call. tweaked here.

import ctypes  sendinput = ctypes.windll.user32.sendinput  pul = ctypes.pointer(ctypes.c_ulong)  class keybdinput(ctypes.structure):     _fields_ = [("wvk", ctypes.c_ushort),                 ("wscan", ctypes.c_ushort),                 ("dwflags", ctypes.c_ulong),                 ("time", ctypes.c_ulong),                 ("dwextrainfo", pul)]  class hardwareinput(ctypes.structure):     _fields_ = [("umsg", ctypes.c_ulong),                 ("wparaml", ctypes.c_short),                 ("wparamh", ctypes.c_ushort)]  class mouseinput(ctypes.structure):     _fields_ = [("dx", ctypes.c_long),                 ("dy", ctypes.c_long),                 ("mousedata", ctypes.c_ulong),                 ("dwflags", ctypes.c_ulong),                 ("time",ctypes.c_ulong),                 ("dwextrainfo", pul)]  class input_i(ctypes.union):     _fields_ = [("ki", keybdinput),                  ("mi", mouseinput),                  ("hi", hardwareinput)]  class input(ctypes.structure):     _fields_ = [("type", ctypes.c_ulong),                 ("ii", input_i)]  def getkeycode(unicodekey):     k = unicodekey     curkeycode = 0     if k == "up": curkeycode = 0x26     elif k == "down": curkeycode = 0x28     elif k == "left": curkeycode = 0x25     elif k == "right": curkeycode = 0x27     elif k == "home": curkeycode = 0x24     elif k == "end": curkeycode = 0x23     elif k == "insert": curkeycode = 0x2d     elif k == "pgup": curkeycode = 0x21     elif k == "pgdn": curkeycode = 0x22     elif k == "delete": curkeycode = 0x2e     elif k == "\n": curkeycode = 0x0d      if curkeycode == 0:         return 0, int(unicodekey.encode("hex"), 16), 0x0004     else:         return curkeycode, 0, 0  def presskey(unicodekey):     key, unikey, uniflag = getkeycode(unicodekey)      = ctypes.c_ulong(0)     ii_ = input_i()     ii_.ki = keybdinput( key, unikey, uniflag, 0, ctypes.pointer(extra) )     x = input( ctypes.c_ulong(1), ii_ )     ctypes.windll.user32.sendinput(1, ctypes.pointer(x), ctypes.sizeof(x))  def releasekey(unicodekey):     key, unikey, uniflag = getkeycode(unicodekey)     = ctypes.c_ulong(0)     ii_ = input_i()     ii_.ki = keybdinput( key, unikey, uniflag + 0x0002, 0, ctypes.pointer(extra) )     x = input( ctypes.c_ulong(1), ii_ )     ctypes.windll.user32.sendinput(1, ctypes.pointer(x), ctypes.sizeof(x)) 

i stored in file named keypress.py.

using this, wanted make simple program detect user typing while typing in python shell. idea use msvcrt.getch() key pressed, script above make seem still pressed (and "echo" key press in sense")

here code:

import keypress import msvcrt         import threading  def getkey():      k = msvcrt.getch()      # escaped key: 224 on keyboard, 0 on numpad     if int(k.encode("hex"), 16) == 224 or int(k.encode("hex"), 16) == 0:         k = msvcrt.getch()         if k == "h": k = "up"         elif k == "p": k = "down"         elif k == "k": k = "left"         elif k == "m": k = "right"         elif k == "g": k = "home"         elif k == "o": k = "end"         elif k == "r": k = "insert"         elif k == "i": k = "pgup"         elif k == "q": k = "pgdn"         elif k == "s": k = "delete"      # fix weird linebreak     if k == "\r":         k = "\n"      return k   def actualgetkeys():     while true:         k = getkey()         keypress.presskey(k)         keypress.releasekey(k)  def getkeys():     p = threading.thread(target=actualgetkeys)     p.daemon = true     p.start()    

i stored in file named keyget.py.

this working well, except whenever user presses enter, first key isn't displayed on screen. console still knows typed it, doesn't show there. this:

not displaying of input

what happening? i've tried many many things , can't seem behavior change.

i able working, in can capture key input asynchronously while script running, , execute text of each command type command prompt (so could, say, store these array). problem running this:

issue of reprint

i know due having have robot retype input after type it, i'm wondering if there way prevents input being displayed when robot types it, acts user expect.

here resulting code, written eryksun's comments because somehow knows all.

this called readcmd.py

# if http://nullege.com/codes/show/src@e@i@einstein-head@python25einstein@lib@subprocess.py/380/win32api.getstdhandle # , # http://nullege.com/codes/show/src@v@i@vista-head@python@pexpect@winpexpect.py/901/win32console.getstdhandle.peekconsoleinput  ctypes import * import time import threading  win32api import std_input_handle, std_output_handle  win32console import getstdhandle, key_event, enable_window_input, enable_mouse_input, enable_echo_input, enable_line_input, enable_processed_input  import keypress   class capturelines():     def __init__(self):         self.stoplock = threading.lock()          self.iscapturinginputlines = false          self.inputlineshookcallback = cfunctype(c_int)(self.inputlineshook)         self.pyosinputhookpointer = c_void_p.in_dll(pythonapi, "pyos_inputhook")         self.originalpyosinputhookpointervalue = self.pyosinputhookpointer.value          self.readhandle = getstdhandle(std_input_handle)         self.readhandle.setconsolemode(enable_line_input|enable_echo_input|enable_processed_input)      def inputlineshook(self):          self.readhandle.setconsolemode(enable_line_input|enable_echo_input|enable_processed_input)         inputchars = self.readhandle.readconsole(10000000)         self.readhandle.setconsolemode(enable_line_input|enable_processed_input)          if inputchars == "\r\n":             keypress.keypress("\n")             return 0          inputchars = inputchars[:-2]          inputchars += "\n"          c in inputchars:             keypress.keypress(c)          self.inputcallback(inputchars)          return 0       def startcapture(self, inputcallback):         self.stoplock.acquire()          try:             if self.iscapturinginputlines:                 raise exception("already capturing keystrokes")              self.iscapturinginputlines = true             self.inputcallback = inputcallback              self.pyosinputhookpointer.value = cast(self.inputlineshookcallback, c_void_p).value         except exception e:             self.stoplock.release()             raise          self.stoplock.release()      def stopcapture(self):         self.stoplock.acquire()          try:             if not self.iscapturinginputlines:                 raise exception("keystrokes aren't being captured")              self.readhandle.setconsolemode(enable_line_input|enable_echo_input|enable_processed_input)              self.iscapturinginputlines = false             self.pyosinputhookpointer.value = self.originalpyosinputhookpointervalue          except exception e:             self.stoplock.release()             raise          self.stoplock.release() 

and here keypress.py

# modified http://stackoverflow.com/a/13615802/2924421  import ctypes ctypes import wintypes import time  user32 = ctypes.windll('user32', use_last_error=true)  input_mouse    = 0 input_keyboard = 1 input_hardware = 2  keyeventf_extendedkey = 0x0001 keyeventf_keyup       = 0x0002 keyeventf_unicode     = 0x0004 keyeventf_scancode    = 0x0008  mapvk_vk_to_vsc = 0  # c struct definitions wintypes.ulong_ptr = wintypes.wparam  sendinput = ctypes.windll.user32.sendinput  pul = ctypes.pointer(ctypes.c_ulong)  class keybdinput(ctypes.structure):     _fields_ = (("wvk",         wintypes.word),                 ("wscan",       wintypes.word),                 ("dwflags",     wintypes.dword),                 ("time",        wintypes.dword),                 ("dwextrainfo", wintypes.ulong_ptr))  class mouseinput(ctypes.structure):     _fields_ = (("dx",          wintypes.long),                 ("dy",          wintypes.long),                 ("mousedata",   wintypes.dword),                 ("dwflags",     wintypes.dword),                 ("time",        wintypes.dword),                 ("dwextrainfo", wintypes.ulong_ptr))  class hardwareinput(ctypes.structure):     _fields_ = (("umsg",    wintypes.dword),                 ("wparaml", wintypes.word),                 ("wparamh", wintypes.word))  class input(ctypes.structure):     class _input(ctypes.union):         _fields_ = (("ki", keybdinput),                     ("mi", mouseinput),                     ("hi", hardwareinput))     _anonymous_ = ("_input",)     _fields_ = (("type",   wintypes.dword),                 ("_input", _input))  lpinput = ctypes.pointer(input)  def _check_count(result, func, args):     if result == 0:         raise ctypes.winerror(ctypes.get_last_error())     return args  user32.sendinput.errcheck = _check_count user32.sendinput.argtypes = (wintypes.uint, # ninputs                              lpinput,       # pinputs                              ctypes.c_int)  # cbsize  def keydown(unicodekey):     key, unikey, uniflag = getkeycode(unicodekey)     x = input( type=input_keyboard, ki= keybdinput( key, unikey, uniflag, 0))     user32.sendinput(1, ctypes.byref(x), ctypes.sizeof(x))  def keyup(unicodekey):     key, unikey, uniflag = getkeycode(unicodekey)     = ctypes.c_ulong(0)     x = input( type=input_keyboard, ki= keybdinput( key, unikey, uniflag | keyeventf_keyup, 0))     user32.sendinput(1, ctypes.byref(x), ctypes.sizeof(x))  def keypress(unicodekey):     time.sleep(0.0001)     keydown(unicodekey)     time.sleep(0.0001)     keyup(unicodekey)     time.sleep(0.0001)   def getkeycode(unicodekey):     k = unicodekey     curkeycode = 0     if k == "up": curkeycode = 0x26     elif k == "down": curkeycode = 0x28     elif k == "left": curkeycode = 0x25     elif k == "right": curkeycode = 0x27     elif k == "home": curkeycode = 0x24     elif k == "end": curkeycode = 0x23     elif k == "insert": curkeycode = 0x2d     elif k == "pgup": curkeycode = 0x21     elif k == "pgdn": curkeycode = 0x22     elif k == "delete": curkeycode = 0x2e     elif k == "\n": curkeycode = 0x0d      if curkeycode == 0:         return 0, int(unicodekey.encode("hex"), 16), keyeventf_unicode     else:         return curkeycode, 0, 0 

Comments

Popular posts from this blog

javascript - jQuery: Add class depending on URL in the best way -

caching - How to check if a url path exists in the service worker cache -

Redirect to a HTTPS version using .htaccess -