pynput - Simular pulsaciones de teclas de Python para controlar un juego
pynput enter key (2)
Estoy tratando de controlar un juego (mis dos juegos de prueba son Half Life 2 y Minecraft) usando mi Kinect y Python. Todo funciona excepto por una cosa. El juego responderá a los eventos simulados del mouse y al movimiento simulado del mouse (los eventos del mouse se realizan a través de ctypes y el movimiento del mouse se realiza mediante pywin32). Sin embargo, el problema es que los juegos ignoran las pulsaciones de teclas simuladas. Ambos tomarán las pulsaciones de tecla simuladas en la ventana de chat (Minecraft) o en la consola del desarrollador (Half Life 2), pero no mientras se juega el juego real.
He intentado varias formas de enviar las pulsaciones de teclas:
import win32com.client as client
wsh = client.Dispatch(''WScript.Shell'')
wsh.AppActivate(gameName)
wsh.SendKeys(key)
y:
import win32api
win32api.keybd_event(keyHexCode, 0, 0)
y:
import ctypes
import time
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))
Debo señalar que el código en la última no es mío, está fuera de otra pregunta aquí en Stack Overflow.
¿Alguien sabe por qué ninguno de estos trabajos y cuál es la forma correcta de hacerlo?
Acabo de tener el mismo problema al intentar simular las pulsaciones de tecla en Half-Life 2. Como dijo Robin, la solución es usar ScanCodes en lugar de VK.
Edité su último ejemplo de código de modo que use ScanCodes. Lo probé con Half-Life 2 y funciona bien:
import ctypes
import time
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( 0, hexKeyCode, 0x0008, 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( 0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.pointer(extra) )
x = Input( ctypes.c_ulong(1), ii_ )
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
# directx scan codes http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
while (True):
PressKey(0x11)
time.sleep(1)
ReleaseKey(0x11)
time.sleep(1)
Es probable que el juego esté utilizando dispositivos DirectInput.
Por lo tanto, el juego está esperando presionar la tecla DirectInput. De acuerdo con la última publicación de este hilo del foro , DirectInput responde a los códigos de exploración, no a los VK. Puede intentar enviar pulsaciones de tecla DirectInput utilizando esta herramienta . El desarrollador también proporciona la fuente y una explicación detallada.
Si esto funciona, puedes intentar enviar códigos de escaneo apropiados en lugar de VK (lista de scancodes) .
También hay un proyecto anterior llamado DirectPython que te permite interactuar con DirectX / DirectInput.