SendKeys с играми: с некоторыми персонажами это работает, а с некоторыми - нет - PullRequest
4 голосов
/ 07 марта 2020

Я хочу смоделировать ввод в играх с помощью SendKeys , но мне трудно.

Если я использую его с т. Е. Буквой T , в то время как Курсор в Minecraft находится в текстовом поле (в главном меню), работает, буква Т написана в текстовом поле.

Но с {ESC} это не работает. Ничего не произошло. Если я нажму его вручную, он вернется в предыдущее меню. (как и должно быть)

С некоторыми приложениями ES C работает:

  • Работает с Discord, Sourcetree, Slack, Chrome , CS2D,

  • , но по некоторым причинам он не работает с Minecraft, Spelunky, Half-Life.

Все упомянутые приложения выше были в оконном режиме .

Другая проблема:

  • Если я отправлю 2 в Minecraft, находясь в текстовом поле, работает правильно, записано 2.

  • Но если я отправлю его во время игры, эффекта не будет. (Персонаж должен переключиться на Слот # 2)

  • То же самое с "" (пробел) . В текстовых полях это работает, но персонаж не прыгает в игре.

Код:

    [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("USER32.DLL")]
    public static extern bool SetForegroundWindow(IntPtr hWnd);

    public Form1()
    {
        InitializeComponent();
        IntPtr minecraftHandle = FindWindow("GLFW30", "Minecraft* 1.15.2");

        if (minecraftHandle == IntPtr.Zero)
        {
            MessageBox.Show("Minecraft is not running.");
            return;
        }

        SetForegroundWindow(minecraftHandle);
        SendKeys.SendWait("{ESC}");
    }

Я пробовал без переключение фокуса: назначая вызовы SendKey горячей клавише , чтобы целевое приложение могло быть в фокусе при вызове SendKeys.

Результаты одинаковы: \

1 Ответ

2 голосов
/ 12 марта 2020

Не используйте SendKeys.Send для обмена сообщениями между процессами, работающими в разных средах выполнения

SendKeys.Send метод из System.Windows.Forms пространства имен.

Это означает, что это не Windows Симулятор ввода , а просто маленький помощник для Windows приложений Forms. Нет гарантии, что этот метод будет работать с другим процессом в другой (не NET) системе времени выполнения.

Несмотря на то, что метод SendKeys.Send использует native Windows API , он отправьте сообщение о нажатии клавиши только фиксированный период времени , поэтому при обработке игрового фрейма может не хватить времени перехватить это сообщение для управления им. Поэтому вам могут потребоваться отдельные команды для отправки сообщений о событиях нажатия и нажатия клавиш.

Не используйте SendKeys API для обмена сообщениями с другими процессами, , особенно с играми .
Кроме того, игры могут использовать систему защиты, чтобы избавиться от автоматов c ботов, которые могут блокировать любые сообщения от входа программирования операционной системы

Итак, что вы можете использовать?

Во-первых, вы можете попробовать использовать PostMessage из user32.dll системной библиотеки:

const uint WM_KEYDOWN = 0x0100;
const uint WM_KEYUP = 0x0101;

[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

// hWnd - Window handler (can be getted by using GetForegroundWindow/FindWindow methods)
// msg - Key up/down message (WM_KEYUP / WM_KEYDOWN)
// wParam - Virual key code you need to pass to the window
// lParam - Additional parameter for set up key message behaviour.

Все коды виртуальных ключей можно найти на веб-сайте Microsoft docs:
https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes

Не забывайте, что вам нужно немного подождать, прежде чем отпустить ключ. Это необходимо, потому что игры кэшируют входные данные между фреймами, а фрейм имеет фиксированное время для захвата входных данных. Просто запишите некоторую задержку между сообщениями нажатия клавиш вниз и вверх.

Также вы можете настроить поведение сообщений клавиш с помощью lParam . См. WM_KEYDOWN и WM_KEYUP параметры. Особенность сообщения WM_KEYDOWN заключается в том, что если вы долго нажимаете клавишу на реальной клавиатуре, операционная система, соответственно, повторяет сообщение WM_KEYDOWN. Количество повторов можно настроить через lParam. Используйте его, если окно, которым вы отправляете сообщения, не реагирует на одно сообщение о нажатии клавиши.

PostMessage - это низкоуровневая системная команда, которую можно использовать для обмена сообщениями между процессами. Эта команда имеет низкую вероятность быть заблокированной системой защиты (но не нулевой) и высокую вероятность быть принятой игрой / процессом, с которым вы работаете. Кроме того, он предоставляет возможность разделять сообщения «вверх» и «вниз».

Что, если PostMessage не работает?

Попробуйте использовать аппаратный код сканирования вместо код виртуального ключа . Подробное объяснение того, как вы можете это сделать, описано в этом ответе .

Если система защиты действительно хороша и PostMessage блокируется, даже если вы используете код сканирования оборудования, можно попробовать одну вещь: используйте другой драйвер ввода с клавиатуры или напишите его самостоятельно. Этот драйвер должен заменить драйвер системной клавиатуры по умолчанию. И вы можете отправить сообщение для взаимодействия с игрой. Это 100% гарантия способ взаимодействия с другими процессами через клавиатуру. Но если вы используете собственные драйверы клавиатуры publi c, есть вероятность, что система защиты заблокирует их. Поэтому вам нужно написать свой собственный драйвер для сообщения между процессами.

...