2013-01-23 236 views
17

我想用我的Kinect和Python來控制遊戲(我的兩個測試遊戲是Half Life 2和Minecraft)。除了一件事以外,一切都有效。遊戲將響應模擬的鼠標事件和模擬的鼠標移動(鼠標事件通過ctypes完成,鼠標移動使用pywin32完成)。但問題在於遊戲忽略了模擬按鍵。他們兩個都會在聊天窗口(Minecraft)或開發者控制檯(Half Life 2)中選擇模擬按鍵,但不會在玩實際遊戲時使用。模擬Python按鍵控制遊戲

我試着發送按鍵的幾種方法:

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

和:

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

和:

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

我應該在最後一個點出碼不是我的,這裏關於Stack Overflow的另一個問題。

有誰知道爲什麼這些工作都沒有,以及正確的方法是什麼?

+1

代替適當的反應,可能我建議檢查的Minecraft的來源,看是否存在鍵盤事件是如何收集和處理的區別在聊天和遊戲之間?當我回家時,我會自己看看它。 – Logan

+0

我將不得不撤回我早期的聲明,其實它並不適用於Minecraft,它使用ctypes系統。我現在仔細檢查半條命2 ... – user573949

+0

是的,它仍然沒有工作。 – user573949

回答

3

這很可能是遊戲使用DirectInput設備。

所以,遊戲期待DirectInput按鍵。根據this forum thread的最後一篇文章,DirectInput響應ScanCodes,而不是VK。您可以嘗試使用this tool發送DirectInput按鍵。開發者還提供了源和詳細的解釋。

如果這樣做,你可以嘗試發送適當的掃描碼而不是VK (list of scancodes)

還有一個較舊的項目叫做DirectPython,它允許你與DirectX/DirectInput進行接口。

+0

該工具的下載鏈接是死了,你知道如何用DirectPython實際發送DirectInput按鍵嗎?它似乎只是爲了傾聽他們,而不是派遣他們。 – user573949

19

我剛剛嘗試模擬Half-Life 2中的按鍵時遇到了同樣的問題。正如Robin所說,解決方案是使用ScanCodes代替VK。

我編輯了您的上一個代碼示例,以便它使用ScanCodes。我半條命2嘗試過了,它工作得很好:

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)