使用Python向Windows中的游戏发送击键?

Dan*_*haw 11 python winapi ctypes keystrokes

我一直在Windows环境中使用Python,我编写了一个脚本来自动执行已知游戏中的某些任务.该任务涉及大量使用鼠标和键盘输入.

但是,所述脚本只有一个问题:它无法向应用程序发送击键.我尝试了至少3种不同的方法,我将在下面发布和一些变化(也读取类似问题/答案的十分之一,无济于事)

第一个,使用win32api模块:

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
Run Code Online (Sandbox Code Playgroud)

没有什么特别之处,在任何文本编辑器,浏览器中都可以完美地工作(键入"f")......但是,如果我打开像反恐精英这样的游戏,那么击键就会"丢失" - 就像在,什么都没发生 另一方面,如果我打开Counter-Strike的控制台,那么按键就会被注册(就像在记事本中一样).在另一款游戏"英雄联盟"中进行了测试,行为完全相同.在实际游戏中,没有检测到击键.但是,如果我打开聊天(仍然是游戏)并重新运行脚本,那么聊天就会注册.

在第二种方法上:

shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys("F")
Run Code Online (Sandbox Code Playgroud)

与上面的行为完全相同.除了游戏之外的所有东西都可以正常工作,并且它只适用于聊天.

第三种方法(功劳归于谁在另一个stackoverflow线程中发布),更高级(调用SendInput())与ctypes模块.理论上,在这三者中,这一个最接近于模拟实际的物理按键:

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
Run Code Online (Sandbox Code Playgroud)

......它也不起作用.奇怪的是,它显示的确切相同的行为前三个:作品在任何文本编辑器/简单的应用程序,得到由游戏忽略或者只在游戏中的聊天规定登记.

如果我猜测我会说这些游戏正在以其他方式获取键盘事件,而我没有用这3种方法中的任何一种,所以忽略了这些.

我很感激任何帮助.如果可能的话,使用CS,LoL或类似游戏中的代码的具体示例,以便我有一个起点.

小智 5

您的游戏可能使用 DirectInput。使用其中一种方法尝试 DirectInput 扫描码。一个快速的谷歌搜索给出了这个网站:http : //www.gamespp.com/directx/directInputKeyboardScanCodes.html


sho*_*osh 1

您可以尝试使用枚举应用程序的窗口EnumWindows()SendMessage()直接调用游戏的主窗口。