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:
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:
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
Post a Comment