Hướng dẫn python send keystrokes to window - python gửi tổ hợp phím tới cửa sổ

Đây là một bài viết thực sự cũ nhưng chưa có câu trả lời nào ở đây, tôi đang tìm kiếm một cái gì đó giống hệt như thế này, và tôi đã dành 6 giờ để trải qua StackOverflow, và cuối cùng chỉ đọc tất cả các tài liệu C vì nó hữu ích hơn.

#you will need the win32 libraries for this snippet of code to work, Links below
import win32gui
import win32con
import win32api
from time import sleep

#[hwnd] No matter what people tell you, this is the handle meaning unique ID, 
#["Notepad"] This is the application main/parent name, an easy way to check for examples is in Task Manager
#["test - Notepad"] This is the application sub/child name, an easy way to check for examples is in Task Manager clicking dropdown arrow
#hwndMain = win32gui.FindWindow("Notepad", "test - Notepad") this returns the main/parent Unique ID
hwndMain = win32gui.FindWindow("Notepad", "test - Notepad")

#["hwndMain"] this is the main/parent Unique ID used to get the sub/child Unique ID
#[win32con.GW_CHILD] I havent tested it full, but this DOES get a sub/child Unique ID, if there are multiple you'd have too loop through it, or look for other documention, or i may edit this at some point ;)
#hwndChild = win32gui.GetWindow(hwndMain, win32con.GW_CHILD) this returns the sub/child Unique ID
hwndChild = win32gui.GetWindow(hwndMain, win32con.GW_CHILD)

#print(hwndMain) #you can use this to see main/parent Unique ID
#print(hwndChild)  #you can use this to see sub/child Unique ID

#While(True) Will always run and continue to run indefinitely
while(True):
    #[hwndChild] this is the Unique ID of the sub/child application/proccess
    #[win32con.WM_CHAR] This sets what PostMessage Expects for input theres KeyDown and KeyUp as well
    #[0x44] hex code for D
    #[0]No clue, good luck!
    #temp = win32api.PostMessage(hwndChild, win32con.WM_CHAR, 0x44, 0) returns key sent
    temp = win32api.PostMessage(hwndChild, win32con.WM_CHAR, 0x44, 0)

    #print(temp) prints the returned value of temp, into the console
    print(temp)
    #sleep(1) this waits 1 second before looping through again
    sleep(1)

Tôi đã thấy tất cả các bài đăng trên tất cả để sử dụng

hwndEdit = win32gui.FindWindowEx(hwndMain, hwndChild, "Edit", "test - Notepad");

Nhưng tôi không bao giờ có thể tìm ra nó. Ngoài ra, tất cả các tài liệu trên trang web của Microsoft đều khác nhau, vì vậy tôi đã thêm của riêng mình về cách tôi hiểu nó.

Điều đó sẽ giúp bạn bắt đầu và sẽ hữu ích cho người khác. Nếu có ai khác đã sửa đổi cho tôi biết.

Thư viện Win32 Python

Nhìn dưới đây cho giải pháp cuối cùng!

Được sao chép từ chủ đề StackoverFlow của tôi, xin lỗi nếu nó quá dài và cụ thể:

Tôi đã làm việc với Python trong môi trường Windows và tôi đã viết một kịch bản để tự động hóa một số tác vụ trong một trò chơi đã biết. Nhiệm vụ liên quan đến việc sử dụng nặng cả đầu vào chuột và bàn phím.

Tuy nhiên, tập lệnh cho biết chỉ có một vấn đề: nó không thể gửi tổ hợp phím đến ứng dụng. Tôi đã thử ít nhất 3 phương pháp khác nhau mà tôi sẽ đăng bên dưới và một số biến thể (cũng đọc một phần mười của các câu hỏi/câu trả lời tương tự, nhưng không có kết quả)

Đầu tiên, sử dụng mô -đun 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

Không có gì đặc biệt về nó, hoạt động hoàn hảo (A "F" được gõ) trong bất kỳ trình soạn thảo văn bản nào, trình duyệt ... Tuy nhiên, nếu tôi mở một trò chơi như, nói, Counter -Strike, sau đó KeyStroke bị "mất" - như trong, Không có gì xảy ra. Mặt khác, nếu tôi mở bảng điều khiển của Counter-Strike, thì phím kỹ thuật sẽ được đăng ký (như trong Notepad). Được thử nghiệm trong một trò chơi khác, Liên minh huyền thoại, chính xác là hành vi tương tự. Trong trò chơi thực tế, không có tổ hợp phím được phát hiện. Tuy nhiên, nếu tôi mở cuộc trò chuyện (vẫn còn ingame) và chạy lại kịch bản thì nó sẽ được đăng ký bởi trò chuyện.

Trên phương pháp thứ hai:

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

Chính xác hành vi tương tự như trên. Hoạt động tốt trong mọi thứ trừ trò chơi, và trong đó chỉ hoạt động trong các cuộc trò chuyện.

Phương thức thứ ba (tín dụng thuộc về bất cứ ai đã đăng nó trong một luồng StackOverflow khác), nâng cao hơn (Gọi SendInput ()) với mô -đun CTYPES. Về lý thuyết, trong ba, cái này là gần nhất để mô phỏng một máy ép khóa thực tế, thực tế:

SendInput = ctypes.windll.user32.SendInput

# C struct redefinitions 
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):

... (some classes are defined here)

# 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

... nó cũng không hoạt động. Thật kỳ lạ, nó hiển thị chính xác hành vi giống như ba lần trước: hoạt động trong bất kỳ trình soạn thảo văn bản/ứng dụng đơn giản nào, bị bỏ qua bởi các trò chơi hoặc chỉ được đăng ký trong phần trò chuyện trò chơi.

Nếu tôi đoán tôi sẽ nói những trò chơi này đang nhận được các sự kiện bàn phím của họ theo một cách khác mà tôi không bao gồm bất kỳ phương pháp nào trong số 3 phương pháp này, do đó bỏ qua các phương pháp này.

Tôi đánh giá cao bất kỳ sự giúp đỡ nào. Nếu có thể, với các ví dụ cụ thể về mã hoạt động trong CS, LOL hoặc các trò chơi tương tự để tôi có điểm xuất phát.

Chỉnh sửa: Tôi "bán giải quyết" vấn đề. Cuối cùng, không sử dụng Python để gửi tổ hợp phím mà chỉ sử dụng nó để gọi một tập lệnh Autohotkey thực hiện công việc nặng nhọc cho tôi. Kiểm tra bình luận của tôi dưới đây để biết thêm chi tiết.

EDIT2: Rất nhiều người đã tìm thấy chủ đề này, và nhiều người tò mò về cách tôi giải quyết vấn đề. Vì rất nhiều người đã giúp đỡ, tôi sẽ chia sẻ với bạn một giải pháp mà tôi đã thấy rằng không liên quan đến AHK (Hurray!), Cùng với thông tin của một số phương pháp. Ở đây chúng tôi đi:

Đúng là tôi đã "khắc phục" vấn đề bằng cách sử dụng Autohotkey và nhìn lại nó là một mớ hỗn độn nóng bỏng. Lúc đầu, những gì tôi đã làm là tôi thực sự đã tải xuống AHK và viết một kịch bản cho nó chạy song song với kịch bản Python (phải tìm hiểu những điều cơ bản về AHK, vì tôi chưa bao giờ sử dụng nó trước đây). Đúng vậy, tôi đã phải chạy hai đoạn mã riêng biệt cùng một lúc, được viết bằng các ngôn ngữ khác nhau để gửi một bàn phím đơn giản cho một trò chơi.

Cách nó hoạt động là tập lệnh AHK sẽ phát hiện các nét bàn phím cấp cao mà tập lệnh Python được tạo ra (cùng một đầu vào mà tôi đã giải thích các ứng dụng "bình thường" có thể phát hiện nhưng các trò chơi của tôi không) và tái tạo điều kiện đó ở cấp độ thấp hơn, Đủ để trò chơi phát hiện (mức thấp hơn là trực tiếp là trực tiếp và rất cần thiết để làm cho nó hoạt động). Điều này rõ ràng là rất khó chịu, mã lộn xộn, sử dụng hai ngôn ngữ kịch bản để thực hiện một nhiệm vụ mà một mình Python nên có khả năng làm nhiều hơn.

Vì vậy, thử thách tiếp theo của tôi là hợp nhất sạch sẽ hơn AHK và kịch bản Python gốc, và vì vậy tôi đã làm khi tôi phát hiện ra Pyahk, một mô -đun bao quanh chính AHK và có thể được nhập vào tập lệnh Python gốc như bất kỳ mô -đun nào khác.

Đó là những năm ánh sáng trước giải pháp ban đầu: Tôi chỉ cần chạy kịch bản Python gốc và bản thân kịch bản sẽ xử lý AHK từ đó, nhưng vẫn còn xa hoàn hảo. Một trong những khuyết điểm rõ ràng nhất là bạn dựa vào mô -đun của bên thứ ba rất nhạy cảm với phiên bản Python của bạn, ví dụ như nó chỉ hoạt động trên Python 2.7 (thật tệ vì hầu hết các dự án của tôi đang sử dụng> 3 và kịch bản ngớ ngẩn này cần được cài đặt Python 2 chỉ danh cho no thôi). Một người khác là một mô -đun khác, vì tất cả những điều tốt đẹp của nó, cần phải được nhập và xử lý cho một cái gì đó mà bạn chỉ cảm thấy Python có thể làm, chắc chắn nếu không có những mánh lới quảng cáo này!

Nhưng thời gian là điều cốt yếu, đặc biệt là vì tôi có các vấn đề khác với mã của mình, vì vậy tôi đã thực dụng về nó và nó hoạt động theo cách đó trong một thời gian dài.

Cuối cùng, một ngày nào đó tôi quyết định tìm một giải pháp quyết định, một điều mà ít nhất sẽ cho phép tôi làm việc với các phiên bản Python mới hơn, và vì vậy tôi đã tìm kiếm như trước đây, và vì vậy nó đã xảy ra! Tôi tình cờ thấy một giải pháp thanh lịch hoạt động chỉ với mô -đun CTYPES và tôi đã sử dụng nó kể từ đó!

import ctypes, time
# Bunch of stuff so that the script can send keystrokes to game #

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( 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))

def KeyPress():
    time.sleep(3)
    PressKey(0x10) # press Q
    time.sleep(.05)
    ReleaseKey(0x10) #release Q

Mã này sẽ hoạt động tốt, hãy thử nó. Không cần Autohotkey hoặc bất kỳ mô -đun nào khác. Tôi không biết Python của bạn tiến bộ như thế nào nhưng nó không phức tạp, hoạt động như sau:

Khi bạn gọi hàm keypress (), tập lệnh sẽ, sau 3 giây, sẽ gửi "Q" nhấn đến bất cứ điều gì được lấy nét. Tôi đã sử dụng "Q" vì mã ban đầu của tôi sử dụng nó, nhưng bạn có thể tìm thấy danh sách đầy đủ các mã cho bất kỳ khoản phím nào bạn cần ở đây: http://www.flint.jp/misc/?q=dik&lang=en

Tôi mong rằng nó giúp ích được cho bạn :)