2014-04-12 27 views
10

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.

+0

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

Odpowiedz

1

Możesz spróbować wyliczyć okna aplikacji za pomocą EnumWindows() i wywołać SendMessage() bezpośrednio w głównych oknach gry.

+0

Nie działa. PostMessage() również nie działa. –