You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

技术求助:如何通过Python实现后台窗口的鼠标/键盘模拟点击,搭建Metin2多开Farming Bot

Hey there! Let's work through this Metin2 bot challenge you're dealing with—background window automation for games can be finicky, especially since many older games (like Metin2) don't play nice with standard Windows input messages out of the box. Let's break down why your current code isn't working and share some practical fixes.

First, why your pywin32 code failed

There are two common culprits here:

  • Wrong window handle: The main "Client" window is often just a border container—actual game input is handled by a child window (the DirectX/OpenGL render surface). Sending messages to the parent window won't trigger any in-game actions.
  • Coordinate mismatch: SendMessage expects coordinates relative to the window's client area, not absolute screen coordinates. If you're passing screen positions directly, the game won't register the click in the right spot.
  • Input handling bypass: Many games use DirectInput instead of processing standard WM_* messages, so sending WM_LBUTTONDOWN might be ignored entirely.

Solution 1: Use pywinauto (easiest for beginners)

Pywinauto is built specifically for Windows GUI automation and handles a lot of the low-level window logic for you. It works with background windows and doesn't hijack your real mouse/keyboard.

First, install it:

pip install pywinauto

Then try this code to interact with your Metin2 windows:

from pywinauto import Application
import time

# Connect to all Metin2 windows (matches any window with "Client" in the title)
apps = Application().connect(title_re="Client.*", backend="win32")

# Iterate over each connected window (for multi-client support)
for window in apps.windows():
    print(f"Interacting with window: {window.window_text()}")
    
    # Simulate a left click at (100, 100) in the window's client area
    window.click_input(coords=(100, 100), button="left")
    
    # Simulate holding SPACE for 2 seconds (for riding/attacking)
    window.type_keys("{SPACE down}")
    time.sleep(2)
    window.type_keys("{SPACE up}")

Notes for pywinauto:

  • Use the win32 backend (default is uia, which works better for modern apps but not always for games).
  • If your windows have exact titles (like "Client 1", "Client 2"), use title="Client 1" instead of title_re.
  • Run your script as administrator to avoid permission issues with the game window.

Solution 2: Fix your pywin32 code (more manual, but gives you control)

If you want to stick with pywin32, you need to target the correct child window and fix your coordinates. Here's how:

  1. Use Spy++ to find the right child window:

    • Open Spy++ (included with Windows SDK, or download it separately)
    • Use the "Find Window" tool to pick your Metin2 window, then look at the child windows—you'll see one that's labeled something like "DirectX Window" or has no visible text. That's the one you need to send messages to.
  2. Updated pywin32 code:

import win32gui
import win32api
import win32con
import time

def get_game_window_handle(main_window_title="Client"):
    # Get the main window handle
    main_hwnd = win32gui.FindWindow(None, main_window_title)
    if not main_hwnd:
        return None
    
    # Enumerate child windows to find the game render surface
    child_hwnds = []
    def enum_child_callback(hwnd, extra):
        # Filter out invisible windows (adjust this based on your Spy++ findings)
        if win32gui.IsWindowVisible(hwnd):
            extra.append(hwnd)
    
    win32gui.EnumChildWindows(main_hwnd, enum_child_callback, child_hwnds)
    # Return the first visible child window (adjust index if needed)
    return child_hwnds[0] if child_hwnds else main_hwnd

def send_background_click(hwnd, client_x, client_y):
    # Send left mouse down/up messages to the target window
    l_param = win32api.MAKELONG(client_x, client_y)
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, l_param)
    time.sleep(0.05)  # Small delay to simulate real click
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONUP, 0, l_param)

def send_background_key(hwnd, key_code, hold_duration=1):
    # Send key down/up messages
    win32api.SendMessage(hwnd, win32con.WM_KEYDOWN, key_code, 0)
    time.sleep(hold_duration)
    win32api.SendMessage(hwnd, win32con.WM_KEYUP, key_code, 0)

# Usage example
game_hwnd = get_game_window_handle()
if game_hwnd:
    print(f"Found game window: {game_hwnd}")
    # Click at (100, 100) in the game's client area
    send_background_click(game_hwnd, 100, 100)
    # Hold SPACE for 2 seconds
    send_background_key(game_hwnd, win32con.VK_SPACE, 2)
else:
    print("Could not find Metin2 window!")

Bonus: Alternative tools/languages

If Python still gives you trouble, consider these options:

  • AutoHotkey: Great for game automation, has built-in support for sending messages to background windows and handling multi-client setups. It's easier for simple scripts than Python in some cases.
  • C# with Windows Forms/Win32 API: More powerful for low-level input, but steeper learning curve. Libraries like InputSimulator can help with background input.

Important Notes

  • Anti-cheat: Even though Metin2 is older, some servers have anti-bot measures. Be careful to avoid triggering bans—don't make your bot's actions too repetitive or human-impossible.
  • Admin rights: Always run your script with the same privilege level as the game (if the game runs as admin, your script should too).

内容的提问来源于stack exchange,提问作者NewInProgramming

火山引擎 最新活动