Principio y realización de todos los métodos de simulación de teclado y mouse

Prefacio:

Hay algunos programas de juegos que usan la interfaz DirectX, omiten el mecanismo de mensajes de Windows al leer las operaciones del teclado y usan DirectInput. Esto se debe a que algunos juegos tienen requisitos más altos para el control en tiempo real, como los juegos de carreras, que requieren la velocidad más rápida. grado de respuesta a la entrada del teclado. Sin embargo, debido a que los mensajes de Windows se encuentran en forma de colas, habrá muchos retrasos en la entrega de los mensajes y, a veces, se entregarán más de una docena de mensajes por segundo. Esta velocidad no cumple con los requisitos del juego. DirectInput pasa por alto el mensaje de Windows y se ocupa directamente del controlador del teclado. Por supuesto, la eficiencia se mejora mucho. Por lo tanto, no habrá respuesta a dicho programa si se usa PostMessage o keybd_event, porque estas funciones están en un nivel superior. Para tal programa, tuve que usar el método de leer y escribir directamente el puerto del teclado para simular el evento de hardware. Para utilizar este método para simular el teclado, debe comprender el conocimiento relevante de la programación del teclado.

 


Comencemos con la operación de simulación más simple. Hay muchas formas de simular el teclado y el mouse. Las divido aproximadamente en simulación de mensajes, simulación de API y simulación de controlador.
Para las páginas web, también puede usar la simulación de JavaScript, aunque esto no es en el alcance de este tutorial

Simulación de un mensaje

Todos los que aprenden a programar en Windows saben que los programas de Windows responderán a los mensajes de la ventana, por lo que enviamos un mensaje por nosotros mismos.En el pasado, el programa pensaba que era un humano operando y respondiendo.

Mira la API que se utilizará

// 发送消息到指定窗口,不用等待消息处理就返回,参数和窗口过程里的一样

BOOL WINAPI PostMessage(

  _In_opt_ HWND   hWnd,

  _In_     UINT   Msg,

  _In_     WPARAM wParam,

  _In_     LPARAM lParam

);

// 获取窗口句柄,参数是窗口类名和窗口标题,其中一个可以传入NULL表示通配

HWND FindWindow(

LPCTSTR lpClassName,

LPCTSTR lpWindowName

);

// 用来获取子窗口句柄

HWND WINAPI FindWindowEx(

_In_opt_ HWND hwndParent,

_In_opt_ HWND hwndChildAfter,

_In_opt_ LPCTSTR lpszClass,

_In_opt_ LPCTSTR lpszWindow

);

Tome el bloc de notas como ejemplo

En primer lugar, debemos saber el nombre de la clase de ventana del Bloc de notas.

Abra el Bloc de notas, abra VS2013, busque spy ++ en la herramienta

Busque la ventana de búsqueda en la barra de herramientas, arrastre la herramienta de búsqueda a la ventana del bloc de notas y obtenga el nombre de clase "Bloc de notas" de la ventana del bloc de notas.

De la misma manera, puede saber que el nombre de la clase del cuadro de edición es Editar

Escribimos un programa para simular presionar A en el cuadro de edición

HWND notepadWnd = FindWindow(_T("Notepad"), NULL); // 记事本窗口句柄

if (notepadWnd == NULL)

{

printf("没有找到记事本窗口\n");

return 0;

}

HWND editWnd = FindWindowEx(notepadWnd, NULL, _T("Edit"), NULL); // 编辑框窗口句柄


const BYTE vk = 'A'; // 虚拟键码

//UINT scanCode = MapVirtualKey(vk, MAPVK_VK_TO_VSC); // 扫描码

PostMessage(editWnd, WM_KEYDOWN, vk, 1 /*| scanCode << 16*/);

Sleep(100);

PostMessage(editWnd, WM_KEYUP, vk, 1 /*| scanCode << 16*/ | 1 << 30 | 1 << 31);

Ejecute el programa para ver si hay más en el bloc de notas

 

Escriba otro programa para simular hacer clic con el botón derecho del mouse

Nueva API utilizada


// 取坐标处窗口句柄

HWND WINAPI WindowFromPoint(

_In_ POINT Point

);

// 取鼠标坐标

BOOL WINAPI GetCursorPos(

_Out_ LPPOINT lpPoint

);

// 把屏幕坐标转为相对于窗口客户区的坐标

BOOL ScreenToClient(

_In_ HWND hWnd,

LPPOINT lpPoint

);

Programa que simula hacer clic con el botón derecho

 
Sleep(3000); // 等待3秒把鼠标移到指定窗口


POINT pos; // 鼠标坐标

GetCursorPos(&pos);

HWND wnd = WindowFromPoint(pos); // 鼠标指向的窗口的句柄

ScreenToClient(wnd, &pos); // 把pos转成相对于窗口客户区的坐标

LPARAM lParam = MAKELPARAM(pos.x, pos.y);


PostMessage(wnd, WM_RBUTTONDOWN, 0, lParam);

Sleep(100);

PostMessage(wnd, WM_RBUTTONUP, 0, lParam);

Después de ejecutar, mueva el mouse al Bloc de notas, aparecerá un menú

 

La ventaja del método de enviar un mensaje para simular la entrada es que se puede simular incluso si la ventana está minimizada, pero la desventaja es que no todos los programas procesarán los mensajes de la ventana, por ejemplo, la mayoría de los juegos usan DInput para ingresar

Simulación de dos API (referencia uno y dos )

La simulación de API es usar la API proporcionada por Windows para simular la entrada, como keybd_event, mouse_event, SendInput, pero Microsoft recomienda usar SendInput en lugar de los otros dos. Luego, solo hablaré sobre cómo usar SendInput.

API utilizada

UINT WINAPI SendInput(

_In_ UINT nInputs,

_In_ LPINPUT pInputs,

_In_ int cbSize

);


typedef struct tagINPUT {

  DWORD type;

  union {

    MOUSEINPUT    mi;

    KEYBDINPUT    ki;

    HARDWAREINPUT hi;

  };

} INPUT, *PINPUT;
Esta API puede simular eventos como presionar el teclado, movimiento del mouse, clic del mouse, etc. Los parámetros son el número de estructuras INPUT, el puntero de la matriz INPUT y el tamaño de la estructura INPUT

El valor de tipo en INPUT es INPUT_MOUSE, INPUT_KEYBOARD, INPUT_HARDWARE, que indican respectivamente el uso de estructuras mi, ki y hi

Para obtener instrucciones detalladas, consulte MSDN:
MOUSEINPUT
KEYBDINPUT

Simule el movimiento del mouse hacia el centro de la pantalla y haga clic con el botón derecho

INPUT input[3];

ZeroMemory(&input, sizeof(input));

// 鼠标移动到屏幕中间,也可以用SetCursorPos(x, y)

input[0].type = INPUT_MOUSE;

input[0].mi.dx = 65535 / 2; // 坐标取值范围是0-65535

input[0].mi.dy = 65535 / 2;

input[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;

// 点击鼠标右键

input[1].type = INPUT_MOUSE;

input[1].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;

input[2].type = INPUT_MOUSE;

input[2].mi.dwFlags = MOUSEEVENTF_RIGHTUP;


SendInput(_countof(input), input, sizeof(INPUT));

Simule presionar la tecla A:

INPUT input[2];

ZeroMemory(&input, sizeof(input));

input[0].type = INPUT_KEYBOARD;

input[0].ki.wVk = 'A';

// 也可以不加这句但是对DInput输入的程序会没用

input[0].ki.wScan = MapVirtualKey(input[0].ki.wVk, MAPVK_VK_TO_VSC);

input[1].type = INPUT_KEYBOARD;

input[1].ki.wVk = input[0].ki.wVk;

input[1].ki.wScan = input[0].ki.wScan;

input[1].ki.dwFlags = KEYEVENTF_KEYUP;


SendInput(_countof(input), input, sizeof(INPUT));

Tomemos un ejemplo avanzado: la pulsación de la tecla Z de Dongfang Huayingzuka

Si desea enviar una película en el Oriental Huaying Mound, debe seguir presionando el botón Z, que es muy laborioso, así que quiero darme cuenta de la función de enviar automáticamente películas manteniendo presionado el botón C (al igual que la guerra de hadas )

Este programa usa MFC, si no lo entiende, le sugiero que aprenda a programar MFC

// 开启

void CC2ZDlg::OnBnClickedButton1()

{

m_enableButton.EnableWindow(FALSE);

m_disableButton.EnableWindow(TRUE);

SetTimer(1, 200, timerProc); // 每0.2s检测C键是否按下,并模拟Z键

}


// 关闭

void CC2ZDlg::OnBnClickedButton2()

{

m_enableButton.EnableWindow(TRUE);

m_disableButton.EnableWindow(FALSE);

KillTimer(1);

}


//定时模拟按下Z

void CALLBACK CC2ZDlg::timerProc(HWND hWnd, UINT nMsg, UINT nTimerid, DWORD dwTime)

{

if ((GetKeyState('C') & (1 << 15)) != 0) // C键按下

{

INPUT input;

ZeroMemory(&input, sizeof(input));

input.type = INPUT_KEYBOARD;

input.ki.wVk = 'Z';

input.ki.wScan = MapVirtualKey(input.ki.wVk, MAPVK_VK_TO_VSC);

SendInput(1, &input, sizeof(INPUT)); // 按下Z键

Sleep(100); // 可能东方是在处理逻辑时检测一下Z键是否按下才发弹幕,如果这时Z键刚好弹起就没有反应,所以要延迟一下

input.ki.dwFlags = KEYEVENTF_KEYUP;

SendInput(1, &input, sizeof(INPUT)); // 弹起Z键

}

}

Código fuente completo

De esta manera, la entrada de la mayoría de los juegos se puede simular, pero algunos juegos estarán protegidos, por lo que se usa la simulación de manejo.

Simulación de tres unidades

La simulación de unidad consiste en escribir su propio controlador, operar el puerto de E / S en el kernel del sistema y enviar instrucciones al circuito integrado conectado al teclado (generalmente el chip 8042) para que genere un mensaje de pulsación de botón, de modo que su analógico La entrada es para todos El programa se envía desde un dispositivo real y puede omitir muchas protecciones
(puede aprender la biblioteca WinIo si necesita operar el puerto de E / S ),
pero no escribo este tipo de controlador _ ( : з 」∠) _, Y cargar el controlador en el sistema x64 debe tener una firma digital confiable, de lo contrario será más problemático, y también conocerá el conocimiento subyacente del chip 8042 ...
Así que encontré una biblioteca escrita por algunas personas para conducir Git que simula la API de Interception en el
sitio web oficial de
Interception. Biblioteca

Su controlador tiene firma digital y ha sido probado en plataformas desde XP hasta win10.
También puede interceptar y modificar entradas (incluyendo CTRL + ALT + DELETE), pero aquí solo hablo de entrada analógica, así que estudiémoslo yo mismo ...
(¿Parece que su entrada analógica no es el puerto de operación sino la versión del kernel de SendInput?)

metodo de instalacion:

(Puede ir a mi disco de red ) Descargue Interception.zip, descomprímalo y ejecute install-interception.exe

Configuración del entorno: si el sistema de destino es de 64 bits, primero debe agregar la configuración x64 en el administrador de configuración

Busque el directorio VC ++ en las propiedades de su proyecto, incluido el directorio más Interception \ library, el directorio de la biblioteca se basa en si el sistema de destino es de 64 bits o 32 bits más biblioteca \ x64 o biblioteca \ x86 para
encontrar la entrada del vinculador, dependencias adicionales más intercepción .lib
Luego coloque interception.dll en la biblioteca \ x64 o biblioteca \ x86 en el mismo directorio de su programa y
finalmente #incluya <interception.h> en su código fuente

Simule el movimiento del mouse hacia el centro de la pantalla y haga clic con el botón derecho:

 
InterceptionContext context = interception_create_context();


InterceptionMouseStroke mouseStroke[3];

ZeroMemory(mouseStroke, sizeof(mouseStroke));

// 鼠标移动到屏幕中间

mouseStroke[0].flags = INTERCEPTION_MOUSE_MOVE_ABSOLUTE;

mouseStroke[0].x = 65535 / 2; // 坐标取值范围是0-65535

mouseStroke[0].y = 65535 / 2;

// 点击鼠标右键

mouseStroke[1].state = INTERCEPTION_MOUSE_RIGHT_BUTTON_DOWN;

mouseStroke[2].state = INTERCEPTION_MOUSE_RIGHT_BUTTON_UP;

interception_send(context, INTERCEPTION_MOUSE(0), (InterceptionStroke*)mouseStroke, _countof(mouseStroke));


interception_destroy_context(context);

Simule presionar la tecla A:

InterceptionContext context = interception_create_context();


InterceptionKeyStroke keyStroke[2];

ZeroMemory(keyStroke, sizeof(keyStroke));

keyStroke[0].code = MapVirtualKey('A', MAPVK_VK_TO_VSC);

keyStroke[0].state = INTERCEPTION_KEY_DOWN;

keyStroke[1].code = keyStroke[0].code;

keyStroke[1].state = INTERCEPTION_KEY_UP;

interception_send(context, INTERCEPTION_KEYBOARD(0), (InterceptionStroke*)keyStroke, _countof(keyStroke));


interception_destroy_context(context);

 

La simulación de manejo es muy poderosa, pero es más problemática y generalmente no se usa _ (: з 」∠) _

 

 

Referencia: https://www.cnblogs.com/Jnshushi99/archive/2011/09/03/2164617.html

Supongo que te gusta

Origin blog.csdn.net/THMAIL/article/details/113812698
Recomendado
Clasificación