Я бы постарался опубликовать минимальный рабочий пример, но, к сожалению, эта проблема просто требует большого количества штук, поэтому я смог ее максимально сократить.
Прежде всего, я использую простой script, который имитирует нажатие клавиш через вызов функции. Это изменено из здесь.
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(), чтобы нажать клавишу, а затем script, чтобы было похоже, что она все еще нажата (и "эхо" нажатие клавиши в некотором смысле ")
Вот код:
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.
Все это работает очень хорошо, за исключением того, что всякий раз, когда пользователь нажимает кнопку ввода, первый ключ не отображается на экране. Консоль все еще знает, что вы ее набрали, она просто не появляется там. Что-то вроде этого:
Что происходит? Я пробовал много вещей, и я не могу заставить это поведение меняться.
Теперь я могу получить эту работу по существу, так как в ней можно асинхронно захватывать ввод ключей, а script выполняется и выполнять с текстом каждой команды, которую вы вводите в командной строке (так что вы могли бы, скажем, сохраните их в массиве). Единственная проблема, с которой я сталкиваюсь, - это что-то вроде этого:
Я знаю, что это связано с тем, что, по сути, необходимо, чтобы робот повторно вводил свой ввод после того, как он набирал его, мне просто интересно, есть ли способ сделать это, который предотвращает фактическое отображение этого ввода, когда робот его вводит, поэтому он действует так же, как ожидал пользователь.