C # p / Invoke Как имитировать событие keyPRESS с помощью SendInput для игр DirectX

Я часто боролся с имитацией событий нажатия клавиатуры для различных ботов или других программ автоматизации GUI.

Мне удалось смоделировать события нажатия клавиш, используя:

INPUT[] kInput = new INPUT[1];
kInput[j].type = SendInputEventType.InputKeyboard;
kInput[j].mkhi.ki.wVk = 0;
kInput[j].mkhi.ki.wScan = (ushort) MapVirtualKey((uint) Keys.D5, 0);
kInput[j].mkhi.ki.dwFlags = KeyboardEventFlags.SCANCODE;
kInput[j].mkhi.ki.time = 0;
kInput[j].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

OR

INPUT[] kInput = new INPUT[1];
kInput[1].type = SendInputEventType.InputKeyboard;
kInput[1].mkhi.ki.wVk = '5';
kInput[1].mkhi.ki.wScan = 0;
kInput[1].mkhi.ki.dwFlags = 0;
kInput[1].mkhi.ki.time = 0;
kInput[1].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

и события клавиатуры, используя:

kInput[1].type = SendInputEventType.InputKeyboard;
kInput[1].mkhi.ki.wVk = 0;
kInput[1].mkhi.ki.wScan = (ushort)MapVirtualKey((uint)Keys.D5, 0);
kInput[1].mkhi.ki.dwFlags = KeyboardEventFlags.KEYUP;
kInput[1].mkhi.ki.time = 0;
kInput[1].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

OR

kInput[1].type = SendInputEventType.InputKeyboard;
kInput[1].mkhi.ki.wVk = '5';
kInput[1].mkhi.ki.wScan = 0;
kInput[1].mkhi.ki.dwFlags = KeyboardEventFlags.KEYUP;
kInput[1].mkhi.ki.time = 0;
kInput[1].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

И пока мои попытки совместить их как:

//key down
INPUT kInput = new INPUT[2];
kInput[0].type = SendInputEventType.InputKeyboard;
kInput[0].mkhi.ki.wVk = 0;
kInput[0].mkhi.ki.wScan = (ushort) MapVirtualKey((uint) Keys.D5, 0);
kInput[0].mkhi.ki.dwFlags = KeyboardEventFlags.SCANCODE;
kInput[0].mkhi.ki.time = 0;
kInput[0].mkhi.ki.dwExtraInfo = IntPtr.Zero;

//Key Up
kInput[1].type = SendInputEventType.InputKeyboard;
kInput[1].mkhi.ki.wVk = 0;
kInput[1].mkhi.ki.wScan = (ushort)MapVirtualKey((uint)Keys.D5, 0);
kInput[1].mkhi.ki.dwFlags = KeyboardEventFlags.KEYUP;
kInput[1].mkhi.ki.time = 0;
kInput[1].mkhi.ki.dwExtraInfo = IntPtr.Zero;

//sendinput
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

У меня была разная степень успеха, у меня никогда не было возможности имитировать событие удержания / нажатия клавиши, когда игра DirectX (или другая трехмерная) воспринимала бы мой ввод так же, как человек с физической клавиатурой ...

Как можно, используя SendInput, имитировать событие нажатия / удержания клавиши, видимое в игре DirectX?


person TheeRFG    schedule 22.07.2013    source источник


Ответы (2)


Чтобы имитировать события клавиатуры в играх DirectX, вам понадобится оболочка для драйвера клавиатуры. У меня была такая же проблема, и ни один из этих методов (SendInput, SendKeys class) мне не помог. Попробуйте использовать эту оболочку, мне это удалось.

person Cherkasov Kirill    schedule 19.03.2014

Теперь я думаю, что многое из этого на самом деле зависит от специфики игры / 3D-приложения, которое вы пытаетесь «обмануть».

В каком-то странном случае в моей первой попытке обмануть конкретную игру, над которой я работал, она принимала всего один SCANCODE как достаточное нажатие клавиши для переключения навыка, пока само игровое окно восстанавливало фокус. (Т.е. у вас открыт веб-браузер, ваше приложение переключается в окно игры, а затем запускает событие SCANCODE).

Однако по какой-то странной причине, хотя я смог заставить это работать в первый раз после того, как окно восстановило фокус, я не мог заставить событие повторно запускаться после этого.

Это озадачило меня, пока в конце концов я не наткнулся на сообщение здесь, в котором говорилось: «Повторение нажатия клавиш - это функция контроллера клавиатуры, а не Windows или SendInput. Вы, конечно, можете эмулировать это с помощью таймера, многократно вызывая SendInput () ".

Это натолкнуло меня на мысль, что вместо того, чтобы отправлять только одно нажатие клавиши или два ввода (одна расширенная клавиша вниз, другая - вверх), почему бы не попытаться отправить поток входных данных так, как МОЖЕТ быть аппаратное устройство (что я не на самом деле знаю наверняка, есть ли это, но в то время все это казалось хорошей идеей)

Итак, в конце концов, и произошли сбои (в основном, попытка отправить X количество одного INPUT 1), что я придумал, было это:

INPUT[] kInput = new INPUT[30];
for (int j = 0; j < kInput.Length - 1; j++)
{
    //activate skill
    //INPUT[] kInput = new INPUT[2];
    kInput[j].type = SendInputEventType.InputKeyboard;
    kInput[j].mkhi.ki.wVk = 0;
    kInput[j].mkhi.ki.wScan = (ushort) MapVirtualKey((uint) Keys.D5, 0);
    kInput[j].mkhi.ki.dwFlags = KeyboardEventFlags.SCANCODE;
    kInput[j].mkhi.ki.time = 0;
    kInput[j].mkhi.ki.dwExtraInfo = IntPtr.Zero;
}
kInput[kInput.Length - 1].type = SendInputEventType.InputKeyboard;
kInput[kInput.Length - 1].mkhi.ki.wVk = 0;
kInput[kInput.Length - 1].mkhi.ki.wScan = (ushort)MapVirtualKey((uint)Keys.D5, 0);
kInput[kInput.Length - 1].mkhi.ki.dwFlags = KeyboardEventFlags.KEYUP;
kInput[kInput.Length - 1].mkhi.ki.time = 0;
kInput[kInput.Length - 1].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput((uint)kInput.Length, kInput, Marshal.SizeOf(typeof(INPUT)));

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

Теперь обратите внимание, что в моем примере мой входной массив имеет размер 30. Это не 30, потому что 30 - это какое-то магическое значение, это 30, потому что 30 было первым и единственным числом, которое мне пришлось выбрать для достижения желаемого результата.

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

person TheeRFG    schedule 22.07.2013