Как с помощью Python и библиотеки pywin32 эмулировать движения курсора, клики мышью и нажатия клавиш в игре World of Tanks?

Всем привет! Возможно, мой вопрос покажется простым или даже глупым, но я занимаюсь этим уже четыре недели и пока не нашел удовлетворительных ответов. <br/> У меня есть игра WorldOfTanks (в СНГ известная как "Мир танков"), и мне нужно реализовать три метода: sendMove, sendClick и sendKey для управления движением курсора, кликами мыши и нажатиями клавиш клавиатуры внутри игрового окна, используя Python и pywin32, без взаимодействия с основным курсором. <br/> Я пробовал реализовать этот функционал с использованием win32gui и win32api, применяя методы SendMessage и PostMessage, предварительно активируя окно и настраивая фокус с помощью (SetForegroundWindow, SetFocus, SetCursor), но это не дало результатов. В то же время с другими программами данный подход работает отлично. <br/> Вот как выглядят мои методы: <br/> <pre><code class="python"># Подключение библиотек
import win32api
import win32gui
import win32con

# Эмуляция движения курсора
def sendMove(hwnd: int, pos: tuple) -&gt; None:
    # Преобразование к LONG
    lParam: int = win32api.MAKELONG(pos[0], pos[1])
    # Реализация движения курсора
    win32gui.PostMessage(hwnd, win32con.WM_MOUSEMOVE, 0, lParam)

# Эмуляция клика внутри указанного окна
def sendClick(hwnd: int, pos: tuple, button: int) -&gt; None:
    # Преобразование к LONG
    lParam: int = win32api.MAKELONG(pos[0], pos[1])
    # Реализация клика
    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, button, lParam)
    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, button, lParam)

# Эмуляция нажатия кнопки клавиатуры
def sendKey(hwnd: int, key: int) -&gt; None:
    # Реализация нажатия кн...
  • 29 января 2025 г. 15:14
Ответы на вопрос 2
Для управления мышью и клавиатурой в игре World of Tanks с использованием Python и библиотеки `pywin32`, важно понимать, что игры часто используют различные методы защиты от автоматизации, поэтому такие подходы могут не всегда работать. Однако, если игра не блокирует такие команды, вот пример, как можно реализовать функции для эмуляции движения курсора, кликов мышкой и нажатий клавиш.

1. **Движение курсора:** Ваша задача заключается в том, чтобы правильно переместить курсор в указанное место внутри игрового окна.

2. **Клики мышью:** Это включает в себя как нажатие, так и отпускание кнопки мыши.

3. **Нажатия клавиш:** Использование таких сообщений, как `WM_KEYDOWN` и `WM_KEYUP`, может быть необходимо для имитации ввода с клавиатуры.

Вот пример кода, который показывает, как это можно реализовать:

```python
import win32api
import win32gui
import win32con
import time

# Эмуляция движения курсора
def sendMove(hwnd: int, pos: tuple) -> None:
    # Установка курсора в нужное положение
    win32gui.SetCursorPos(pos)
    # Создание сообщения WM_MOUSEMOVE
    win32gui.PostMessage(hwnd, win32con.WM_MOUSEMOVE, 0, win32api.MAKELONG(pos[0], pos[1]))

# Эмуляция клика внутри указанного окна
def sendClick(hwnd: int, pos: tuple, button: int = win32con.WM_LBUTTONDOWN) -> None:
    # Преобразование в LONG
    lParam = win32api.MAKELONG(pos[0], pos[1])
    # Отправка сообщений о нажатии и отпускании кнопки
    win32gui.PostMessage(hwnd, button, 0, lParam)
    time.sleep(0.05)  # Небольшая задержка для предотвращения слишком быстрого клика
    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, lParam)

# Эмуляция нажатия кнопки клавиатуры
def sendKey(hwnd: int, key: int) -> None:
    # Отправка сообщений о нажатии и отпускании клавиши
    win32gui.PostMessage(hwnd, win32con.WM_KEYDOWN, key, 0)
    time.sleep(0.05)  # Небольшая задержка
    win32gui.PostMessage(hwnd, win32con.WM_KEYUP, key, 0)

# Пример использования
if __name__ == '__main__':
    hwnd = win32gui.FindWindow(None, "World of Tanks")  # Найдите любые окна по заголовку
    if hwnd:
        # Пример движения курсора
        sendMove(hwnd, (500, 500))  # Установите курсор в координаты (500, 500)
        sendClick(hwnd, (500, 500))  # Клик в тех же координатах
        sendKey(hwnd, ord('W'))  # Нажмите клавишу 'W' (например, вперед)
    else:
        print("Игра не найдена.")
```

### Замечания:

1. **Задержки:** Задержки между нажатиями и отпусканиями клавиш/кликами могут быть важны для обеспечения корректного выполнения. Оптимальные значения зависят от вашей системы и игры.

2. **Фокус:** Убедитесь, что окно игры имеет фокус перед отправкой команд, поскольку некоторые игры могут игнорировать команды, если они не в фокусе.

3. **Защита:** Некоторые игры могут блокировать попытки автоматизации ввода. Необходимо ознакомиться с правилами игры и условиями использования, чтобы избежать блокировок ваших аккаунтов.

4. **Работа с координатами:** Убедитесь, что координаты для кликов актуальны для вашего экрана, возможно, придется учитывать разрешение и масштабирование.

5. **Использование других библиотек:** Если методы `pywin32` не работают должным образом, вы можете попробовать другие библиотеки, такие как `pynput` или `pyautogui`, но их совместимость с играми может различаться.

Используйте этот пример как основу и модифицируйте его в зависимости от ваших требований и ситуации.
Игры для работы с пользовательским вводом очень часто работают через графические API DirectX/OpenGL/Vulkan и прочее, при этом данные от системных вызовов типа оконного цикла, SendInput и прочее не используются. Сюрприз! В этом случае остаётся только три варианта: 
А вот эмуляция пользовательского ввода в нескольких окнах возможна только с помощью виртуализации. Ибо все современные ОС поддерживают только одну клавиатуру и мышку для одного пользователя (всякие специфические утилиты/случаи не рассматриваем). SendMessage/PostMessage работает только с приложениями, которые получают пользовательский ввод через оконный цикл.
Похожие вопросы