我一直在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
没有什么特别之处,在任何文本编辑器、浏览器中都能完美工作(输入“f”)。。。但是,如果我打开一个类似于“反击”的游戏,那么击键就会“丢失”—就像在中一样,什么都不会发生。另一方面,如果我打开Counter Strike的控制台,则按键将注册(如在记事本中)。 在另一个游戏《传奇联盟》中测试,完全相同的行为。在实际的游戏中,没有检测到按键。但是,如果我打开聊天室(仍然ingame)并重新运行脚本,那么它将被聊天室注册。
关于第二种方法:
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys("F")
与上述行为完全相同。除了游戏之外,其他一切都很好,而且只在聊天中有效。
第三种方法(信任给在另一个stackoverflow线程中发布它的人),使用ctypes
模块更高级(调用SendInput()
)。理论上,在这三个按键中,这一个最接近模拟实际的物理按键:
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
。。。它也不起作用。奇怪的是,它显示了与前三个相同的行为:在任何文本编辑器/简单应用程序中工作、被游戏忽略或只在游戏聊天区中注册。
如果我猜我会说这些游戏是以另一种方式获得它们的键盘事件的,而这三种方法我都没有涉及到,因此忽略了这些方法。
我很感激你的帮助。如果可能的话,用在CS,LoL或类似游戏中的代码的具体例子,这样我就有了一个起点。
您可以尝试使用
EnumWindows()
枚举应用程序的窗口,并直接调用SendMessage()
到游戏的主窗口。你的游戏可能使用DirectInput。使用这些方法中的任何一种尝试DirectInput扫描代码。一个快速的谷歌搜索就可以得到这个网站:http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
相关问题 更多 >
编程相关推荐