Introducción
Este artículo explica cómo utilizar la función SendInput de Windows API para simular la entrada de texto Unicode y pulsaciones de teclas en aplicaciones. Aunque fue desarrollado inicialmente para permitir el ingreso de caracteres chinos en un videojuego, su funcionalidad es general y puede adaptarse a múltiples escenarios donde se requiera inyección de entrada a nivel del sistema.
Espacios de nombres requeridos
using static System.Threading.Thread;
using System.Runtime.InteropServices;
Estructuras y declaración de API
Para interactuar con la API de Windows, se definen estructuras que representan los tipos de eventos de entrada: teclado, ratón e hardware. Aquí solo nos enfocamso en entradas de teclado y caracteres Unicode.
[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
[FieldOffset(0)] public uint type;
[FieldOffset(4)] public KEYBDINPUT keyboard;
[FieldOffset(4)] public MOUSEINPUT mouse;
[FieldOffset(4)] public HARDWAREINPUT hardware;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr extraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr extraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public uint uMsg;
public ushort wParamL;
public ushort wParamH;
}
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
Funciones de utilidad
A continuación se implementan métodos para enviar caracteres Unicode y simular pulsaciones completas de teclas (presión y liberación).
Enviar un carácter Unicode
Este método utiliza el flag KEYEVENTF_UNICODE (valor 4) para insertar un carácter directamente mediante su valor escaneado (scan code), útil para textos no ASCII como chino, japonés o árabe.
public void InyectarCaracter(char caracter)
{
var entrada = new INPUT[2];
// Pulsación (key down)
entrada[0].type = 1; // Tipo: teclado
entrada[0].keyboard.wVk = 0; // wVk debe ser 0 cuando se usa Unicode
entrada[0].keyboard.wScan = (ushort)caracter;
entrada[0].keyboard.dwFlags = 0x0004; // KEYEVENTF_UNICODE
entrada[0].keyboard.time = 0;
entrada[0].keyboard.extraInfo = IntPtr.Zero;
// Liberación (key up)
entrada[1].type = 1;
entrada[1].keyboard.wVk = 0;
entrada[1].keyboard.wScan = (ushort)caracter;
entrada[1].keyboard.dwFlags = 0x0006; // KEYEVENTF_UNICODE | KEYEVENTF_KEYUP
entrada[1].keyboard.time = 0;
entrada[1].keyboard.extraInfo = IntPtr.Zero;
SendInput(2, entrada, Marshal.SizeOf<INPUT>());
}
Simular pulsación de una tecla virtual
Este método envía una tecla por su código virtual (por ejemplo, VK_RETURN, VK_ESCAPE), simulando primero la pulsación y luego la liberación con un breve retraso.
public void SimularTecla(int codigoVirtual)
{
var evento = new INPUT();
// Pulsar tecla
evento.type = 1;
evento.keyboard.wVk = (ushort)codigoVirtual;
evento.keyboard.dwFlags = 0; // Key down
SendInput(1, new[] { evento }, Marshal.SizeOf<INPUT>());
Sleep(30);
// Soltar tecla
evento.keyboard.dwFlags = 2; // KEYEVENTF_KEYUP
SendInput(1, new[] { evento }, Marshal.SizeOf<INPUT>());
Sleep(30);
}
Uso y consideraciones
- InyectarCaracter('文') permite introducir caracteres Unicode directamente en juegos o aplicaciones que no soportan IME.
- SimularTecla(0x0D) presiona y libera la tecla Enter (código virtual 0x0D).
- Los códigos de teclas virtuales están documentados en la documentación oficial de Microsoft.
Este enfoque funciona a nivel del sistema operativo y puede fallar si la aplicación objeitvo tiene medidas anti-trampa o ejecuta privilegios elevados.