2013-01-23 19 views
17

Sto provando a controllare un gioco (i miei due giochi di prova sono Half Life 2 e Minecraft) usando il mio Kinect e Python. Tutto funziona tranne una cosa. Il gioco risponderà agli eventi simulati del mouse e al movimento del mouse simulato (gli eventi del mouse vengono eseguiti tramite ctypes e il movimento del mouse viene eseguito utilizzando pywin32). Il problema è che i giochi ignorano i tasti simulati. Entrambi selezioneranno i tasti simulati nella finestra di chat (Minecraft) o nella console di sviluppo (Half Life 2) ma non durante il gioco.Simula pressioni dei tasti Python per controllare un gioco

Ho provato diversi modi per l'invio dei tasti premuti:

import win32com.client as client 
wsh = client.Dispatch('WScript.Shell') 
wsh.AppActivate(gameName) 
wsh.SendKeys(key) 

e:

import win32api 
win32api.keybd_event(keyHexCode, 0, 0) 

e:

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)) 

Vorrei sottolineare il codice durante lo scorso un non è mio, è un'altra domanda qui su Stack Overflow.

Qualcuno sa perché nessuno di questi lavori e qual è il modo corretto per farlo?

+1

Al posto di una risposta adeguata, potrei suggerire controllare la fonte di Minecraft per vedere se c'è una differenza nel modo in cui gli eventi della tastiera vengono raccolti e trattati tra la chat e il gameplay? Vado a dare un'occhiata a me stesso quando torno a casa. – Logan

+0

Devo ritirare la mia precedente affermazione sul fatto che non funziona su Minecraft in realtà, con il sistema ctypes che fa. Doppio controllo di Half Life 2 ora ... – user573949

+0

Sì, non funziona ancora. – user573949

risposta

3

È probabile che il gioco utilizzi dispositivi DirectInput.

Quindi, il gioco è in attesa di pressione di tasto DirectInput. Secondo l'ultimo post di this forum thread, DirectInput risponde a ScanCodes, non ai VK. È possibile provare a inviare le pressioni dei tasti DirectInput utilizzando this tool. Il dev fornisce anche la fonte e una spiegazione dettagliata.

Se funziona, è possibile provare a inviare ScanCodes appropriati anziché VK (list of scancodes).

C'è anche un vecchio progetto chiamato DirectPython che consente di interfacciarsi con DirectX/DirectInput.

+0

Il link per il download per quello strumento è morto, sai come inviare effettivamente pressioni dei tasti DirectInput con DirectPython? Sembra solo essere impostato per ascoltarli, non per spedirli. – user573949

19

Ho appena avuto lo stesso problema cercando di simulare pressioni dei tasti in Half-Life 2. Come ha detto Robin, la soluzione è utilizzare ScanCodes anziché VK.

Ho modificato l'ultimo esempio di codice in modo che utilizzi ScanCodes. Ho provato con Half-Life 2 e funziona bene:

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)