Pracowałem z Pythonem w środowisku Windows i napisałem skrypt, aby zautomatyzować niektóre zadania w znanej grze. Zadanie polega na intensywnym korzystaniu z wejść myszy i klawiatury.Używaj Pythona do wysyłania naciśnięć klawiszy do gier w systemie Windows?
Ten skrypt ma jednak tylko jeden problem: nie może wysłać naciśnięć klawiszy do aplikacji. Próbowałem co najmniej 3 różne metody, które powinny zamieścić poniżej i niektóre odmiany (czytaj także dziesiątych podobne pytania/odpowiedzi, bezskutecznie)
Pierwszy z nich, za pomocą modułu 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
Nic specjalnego w tym, działa perfekcyjnie (piszemy "f") w dowolnym edytorze tekstu, przeglądarce ... Jednak jeśli otworzę grę podobną do, powiedzmy, Counter-Strike, wtedy klawisz zostanie "zagubiony" - jak w nic nie występuje. Z drugiej strony, jeśli otworzę konsolę Counter-Strike, naciśnięcie klawisza spowoduje zarejestrowanie (jak w notatniku). Testowany w innej grze, League of Legends, dokładnie to samo zachowanie. W grze nie wykryto żadnego klawisza. Jeśli jednak otworzę czat (nadal w grze) i ponownie uruchomę skrypt, zostanie on zarejestrowany przez czat.
na drugim sposobem:
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys("F")
dokładnie takie samo zachowanie jak wyżej. Działa dobrze we wszystkim oprócz gry, a działa tylko w czatach.
Trzecia metoda (kredyt trafia do osoby, która opublikowała go w innym wątku stackoverflow), bardziej zaawansowana (wywołanie SendInput()
) z modułem ctypes
. W teorii, z trzech, ten znajduje się najbliżej symulować rzeczywiste, fizyczne nacisnąć klawisz:
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
... to nie działa albo. Co dziwne, wyświetla ono dokładnie takie samo zachowanie, jak poprzednie trzy: działa w dowolnym edytorze tekstu/prostej aplikacji, zostaje zignorowane przez gry lub jest zarejestrowane tylko w sekcji czatu w grze.
Gdybym miał zgadywać, powiedziałbym, że te gry pobierają swoje zdarzenia na klawiaturze w inny sposób, który nie obejmował żadnej z tych 3 metod, ignorując w ten sposób te.
Byłbym wdzięczny za każdą pomoc. Jeśli to możliwe, z konkretnymi przykładami kodu działającego w CS, LoL lub podobnych grach, tak, że mam punkt wyjścia.
W przypadku gier opartych na przeglądarkach, znalazłem podstawowe naciśnięcie klawisza, jak opisano powyżej, działa w przeglądarce Firefox, ale nie działało na chrome. – Oleksiy