Ключевое эхо в Python в отдельном потоке не отображает первый ход ключа

Я бы постарался опубликовать минимальный рабочий пример, но, к сожалению, эта проблема просто требует большого количества штук, поэтому я мог бы лишить ее наилучшего результата.

Прежде всего, я использую простой скрипт, который имитирует нажатие клавиш через вызов функции. Это изменено отсюда .

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) extra = 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) extra = 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)) 

Я сохранил это в файле с именем keyPress.py.

Используя это, я хотел создать простую программу, которая могла бы обнаружить, что пользователь вводил, когда они печатали ее в оболочке python. Идея заключалась в том, что я бы использовал msvcrt.getch (), чтобы нажать клавишу, а затем сценарий выше, чтобы он выглядел так, будто он все еще нажат (и «эхо» нажатие клавиши в некотором смысле »)

Вот код:

 import keyPress import msvcrt import threading def getKey(): k = msvcrt.getch() # Escaped Key: 224 is on the keyboard, 0 is on the 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() 

Я сохранил это в файле с именем keyGet.py.

Все это работает очень хорошо, за исключением того, что всякий раз, когда пользователь нажимает кнопку ввода, первый ключ не отображается на экране. Консоль все еще знает, что вы ее набрали, она просто не появляется там. Что-то вроде этого:

Не отображать все входные данные

Что происходит? Я пробовал много вещей, и я не могу заставить это изменить.

Теперь я могу получить эту работу по существу, так как она может захватывать ключевые входы асинхронно во время работы скрипта и выполнять с текстом каждой команды, которую вы вводите, в командную строку (чтобы вы могли, например, сохранить их в массив ). Единственная проблема, с которой я сталкиваюсь, – это что-то вроде этого:

Проблема перепечатки

Я знаю, что это связано с тем, что по существу нужно, чтобы робот повторно вводил свой ввод после того, как он набирал его, мне просто интересно, есть ли способ сделать это, чтобы этот вывод не отображался, когда робот его вводит, поэтому он действует как и ожидал пользователь.

One Solution collect form web for “Ключевое эхо в Python в отдельном потоке не отображает первый ход ключа”

Вот результирующий код, в основном написанный комментариями eryksun, потому что как-то он все знает.

Это называется readcmd.py

 # Some if this is from http://nullege.com/codes/show/src@e@i@einstein-HEAD@Python25Einstein@Lib@subprocess.py/380/win32api.GetStdHandle # and # http://nullege.com/codes/show/src@v@i@VistA-HEAD@Python@Pexpect@winpexpect.py/901/win32console.GetStdHandle.PeekConsoleInput from ctypes import * import time import threading from win32api import STD_INPUT_HANDLE, STD_OUTPUT_HANDLE from 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" for 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 as e: self.stopLock.release() raise self.stopLock.release() def stopCapture(self): self.stopLock.acquire() try: if not self.isCapturingInputLines: raise Exception("Keystrokes already 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 as e: self.stopLock.release() raise self.stopLock.release() 

И вот keyPress.py

 # Modified from http://stackoverflow.com/a/13615802/2924421 import ctypes from 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) extra = 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 
  • правильный способ запускать некоторый код с тайм-аутом в Python
  • Ошибка пульта управления принтером win32print на Python
  • Django 1.9a1 __init__.py отображается в eclipse / PyDev, хотя его необходимо удалить (Windows)
  • Ошибка в модуле с именем curses
  • Какая самая популярная библиотека GUI для Python в Windows?
  • передача дескриптора файла в функцию библиотеки C через ctypes на окнах
  • Tkinter в Python 3.4 в Windows не публикует данные буфера обмена в буфер обмена Windows при выходе
  • pyrouge: «pyrouge_set_rouge_path» не распознается как внутренняя или внешняя команда
  • Запустить скрипт Python без консоли Windows
  • Подпроцесс Python вводит пробелы
  • Python Windows CMD mklink, перестает работать без сообщения об ошибке
  • Python - лучший язык программирования в мире.