Используйте Python для отправки нажатий клавиш в играх в Windows?
Я работал с Python в среде Windows и написал скрипт для автоматизации некоторых задач в известной игре. Задача предполагает интенсивное использование как мыши, так и клавиатуры.
Однако указанный сценарий имеет только одну проблему: он не может отправлять нажатия клавиш в приложение. Я попробовал по крайней мере 3 различных метода, которые я опубликую ниже, и некоторые варианты (также прочитайте десятые подобные вопросы / ответы, но безрезультатно)
Первый, используяwin32api
модуль:
f = 0x46 # VirtualKey Code of the letter "F", see http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
win32api.keybd_event(f,0,0,0) # holds the "F" key down
time.sleep(2) # waits 2 seconds
win32api.keybd_event(f,0,win32con.KEYEVENTF_KEYUP,0) # releases the key
Ничего особенного в этом нет, прекрасно работает (набирается «f») в любом текстовом редакторе, браузере ... Однако, если я открою игру, например, Counter-Strike, то нажатие клавиши будет «потеряно» - как в ничего не происходит С другой стороны, если я открою консоль Counter-Strike, то нажатие клавишиполучает зарегистрирован (как в блокноте). Протестировано в другой игре, League of Legends, точно такое же поведение. В реальной игре нажатие клавиш не обнаружено. Если, однако, я открываю чат (все ещев игре) и повторно запустите скрипт, после чего он будет зарегистрирован в чате.
На второй метод:
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys("F")
Точно такое же поведение, как указано выше. Отлично работает во всем, кроме игры, и в ней работает только в чатах.
Третий метод (кредит идет тому, кто разместил его в другом потоке stackoverflow), более продвинутый (вызовSendInput()
) сctypes
модуль. Теоретически, из трех, этот наиболее близок к моделированию реального физического нажатия клавиш:
SendInput = ctypes.windll.user32.SendInput
# C struct redefinitions
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)]
# Actuals Functions
def PressKey(hexKeyCode):
extra = ctypes.c_ulong(0)
ii_ = Input_I()
ii_.ki = KeyBdInput( hexKeyCode, 0x48, 0, 0, ctypes.pointer(extra) )
x = Input( ctypes.c_ulong(1), ii_ )
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
def ReleaseKey(hexKeyCode):
extra = ctypes.c_ulong(0)
ii_ = Input_I()
ii_.ki = KeyBdInput( hexKeyCode, 0x48, 0x0002, 0, ctypes.pointer(extra) )
x = Input( ctypes.c_ulong(1), ii_ )
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
def KeyPress():
PressKey(0x46) # press F
time.sleep(.5)
ReleaseKey(0x46) #release F
... это тоже не работает. Как ни странно, он отображаетточный такое же поведение, как и у предыдущих трех: работает в любом текстовом редакторе / простом приложении, игнорируется играми или регистрируется только в разделе игрового чата.
Если бы я предположил, я бы сказал, что эти игры получают свои события клавиатуры каким-то другим способом, который я не покрывал ни одним из этих трех методов, игнорируя их.
Буду признателен за любую помощь. Если возможно, с конкретными примерами кода, работающего в CS, LoL или подобных играх, чтобы у меня была отправная точка.