Simulate Python keypresses for controlling a game
Solution 1:
I just had the same problem trying to simulate keypresses in Half-Life 2. As Robin said, the solution is to use ScanCodes instead of VKs.
I edited your last code example such that it uses ScanCodes. I tried it with Half-Life 2 and it works just fine:
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)
Solution 2:
It's likely that the game is using DirectInput devices.
So, the game is expecting DirectInput key presses. According to the last post of this forum thread, DirectInput responds to ScanCodes, not VKs. You can try sending DirectInput key presses using this tool. The dev also supplies the source and a detailed explanation.
If this works, you could just try sending appropriate ScanCodes instead of VKs (list of scancodes).
There's also an older project called DirectPython that allows you to interface with DirectX/DirectInput.