Use o Python para enviar pressionamentos de teclas para jogos no Windows?

Eu tenho trabalhado com Python em um ambiente Windows e escrevi um script para automatizar algumas tarefas em um jogo conhecido. A tarefa envolve o uso intenso de entradas de mouse e teclado.

O referido script, no entanto, tem apenas um problema: não pode enviar pressionamentos de tecla para o aplicativo. Eu tentei pelo menos três métodos diferentes que postarei abaixo e algumas variações (leia também décimos de perguntas / respostas semelhantes, sem sucesso)

Primeiro, usando owin32api módulo:

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

Nada de especial nisso funciona perfeitamente (um "f" é digitado) em qualquer editor de texto, navegador ... No entanto, se eu abrir um jogo como, por exemplo, Counter-Strike, o pressionamento de tecla será "perdido" - como em nada ocorre. Por outro lado, se eu abrir o console do Counter-Strike, o pressionamento de teclafica registrado (como no bloco de notas). Testado em outro jogo, League of Legends, exatamente o mesmo comportamento. No jogo atual, nenhuma combinação de teclas é detectada. Se, no entanto, eu abrir o chat (aindano jogo) e execute novamente o script, depois ele será registrado pelo bate-papo.

No segundo método:

shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys("F")

Exatamente o mesmo comportamento acima. Funciona bem em tudo, menos no jogo, e só funciona em chats.

Terceiro método (o crédito é destinado a quem o postou em outro encadeamento de fluxo de pilha), mais avançado (chamandoSendInput()) com octypes módulo. Em teoria, dos três, este é o mais próximo a simular um pressionamento físico real da tecla:

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

... também não funciona. Curiosamente, ele exibe oexato mesmo comportamento dos três anteriores: funciona em qualquer editor de texto / aplicativo simples, é ignorado pelos jogos ou é registrado apenas na seção de bate-papo do jogo.

Se eu fosse adivinhar, diria que esses jogos estão recebendo seus eventos de teclado de alguma outra maneira que não cobri com nenhum desses três métodos, ignorando-os.

Eu apreciaria qualquer ajuda. Se possível, com exemplos concretos de código trabalhando em CS, LoL ou jogos semelhantes, para que eu tenha um ponto de partida.

questionAnswers(2)

yourAnswerToTheQuestion