如何用pywinauto在游戏中模拟按键
我已经尝试了各种方法整整一年了。我在Python方面还是个初学者,刚完成了Project Euler的前两个题目。
我试过几种方法,想在我玩的游戏中模拟按键。我可以很轻松地用autohotkey和宏键盘/鼠标来做到这一点。不过,我想通过Python或C语言来实现这个功能。
我猜测win32 API在视频游戏中可能被忽略,所以我需要通过Direct X来模拟按键。
谢谢大家的帮助。这是我最近的尝试……结果失败了。
每次我运行新的游戏实例时,都需要重新获取或更改句柄。
我模拟的按键在浏览器和记事本中可以正常工作,但在游戏中却不行。这里的“不行”是指没有用户输入。
下面的代码可以切换到游戏窗口,但无法模拟用户的输入。
import pywinauto
import time
from pywinauto import application
app = application.Application()
app.connect_(handle = 0x14002a)
dialogs = app.windows_(handle = 0x14002a)
dlg = app.top_window_()
time.sleep(1)
app.MapleStory.TypeKeys("%A")
time.sleep(1)
app.MapleStory.TypeKeys("%A")
time.sleep(1)
app.MapleStory.TypeKeys("%A")
time.sleep(1)
app.MapleStory.TypeKeys("%A")
time.sleep(1)
app.MapleStory.TypeKeys("%A")
time.sleep(1)
app.MapleStory.TypeKeys("%A")
2 个回答
我不知道这是不是太晚了,但有些游戏确实可以通过使用扫描码来模拟鼠标和键盘事件,而不是用虚拟键,方法是用SendInput。
不过,具体到《冒险岛》这款游戏,它对虚拟键和扫描码都没有反应。
我知道的在这个游戏里模拟键盘事件的唯一方法是使用内核驱动。一个例子是使用WinIo直接写入i8042和i8048控制器。8042上的命令0xD2专门用来模拟硬件级别的输入。不过,WinIo会打开一个很大的安全漏洞,因为它直接把硬件端口暴露给用户空间的程序,所以我不能说我推荐这个方法。
我过去的自己,我们经历了很长的旅程。虽然我们还有很多要学习的,但这是我们发现的:
如果游戏是在DirectX上运行的,发送虚拟按键会被忽略。你应该使用sendinput,并发送扫描码。
# http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
import ctypes
import time
SendInput = ctypes.windll.user32.SendInput
W = 0x11
A = 0x1E
S = 0x1F
D = 0x20
Z = 0x2C
UP = 0xC8
DOWN = 0xD0
LEFT = 0xCB
RIGHT = 0xCD
ENTER = 0x1C
# 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))
if __name__ == '__main__':
pressKey(0x11)
time.sleep(1)
releaseKey(0x11)
time.sleep(1)
来源: 模拟Python按键以控制游戏 http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
感谢Sentdex提供的精彩机器学习教程。 我一直想对我喜欢的一些游戏做这个,但由于DirectX的原因,无法发送按键。
下一步: 使用Windows驱动程序工具包来模拟按键...