Use Python to send keystrokes to games in Windows?

╄→гoц情女王★ 提交于 2020-01-31 03:34:48

问题


I've been working with Python in a Windows environment and I wrote a script to automate some tasks in a known game. The task involves heavy use of both mouse and keyboard inputs.

Said script, however, has only one issue: it cannot send keystrokes to the application. I've tried at least 3 different methods that I shall post below and some variations (also read tenths of similar questions/answers, to no avail)

First one, using the win32api module:

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

Nothing special about it, works perfectly (a "f" is typed) in any text editor, browser... However, if I open a game like, say, Counter-Strike, then the keystroke gets "lost" - as in, nothing occurs. On the other hand, if I open Counter-Strike's console, then the keystroke gets registered (like in notepad). Tested in another game, League of Legends, exactly the same behaviour. In the actual game, no keystroke is detected. If, however, I open the chat (still ingame) and re-run the script then it gets registered by the chat.

Onto the second method:

shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys("F")

Exactly the same behaviour as above. Works fine in everything but the game, and in it only works in chats.

Third method (credit goes to whoever posted it in another stackoverflow thread), more advanced (calling SendInput()) with the ctypes module. In theory, of the three, this one is the closest to simulate an actual, physical key press:

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

... it does not work either. Oddly enough, it displays the exact same behaviour as the previous three: works in any text editor/simple application, gets ignored by games or is only registered in the game chat section.

If I were to guess I'd say these games are getting their keyboard events in some other way that I've not covered with any of these 3 methods, thus ignoring these ones.

I'd appreciate any help. If possible, with concrete examples of code working in either CS, LoL or similar games so that I have a starting point.


回答1:


Your games probably use DirectInput. Try DirectInput scancodes with either of those methods. A quick googling gives this website: http://www.gamespp.com/directx/directInputKeyboardScanCodes.html




回答2:


You could try enumerating the application's windows using EnumWindows() and call SendMessage() to the main windows of the game directly.



来源:https://stackoverflow.com/questions/23024525/use-python-to-send-keystrokes-to-games-in-windows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!