C # –Send a multibyte string with SendInput
Background
I didn’t like the behavior of the unformatted copy of MS Word (it takes a lot of extra care peculiar to MS Office), so let’s create a program material that allows you to enter plain text by simulating keystrokes. I thought.
capture
When you press the Send text button, the countdown starts, and after 6 seconds, the character string in the text box directly below is sent by Send Input. (During the countdown, focus on the window or control you want SendInput to flow into.)
- Depending on the recipient, it may not be supported.
By the way, in Word, the behavior seems to change depending on the state of IME. (In the “A” (full-width) state, the conversion candidate is selected after SendInput is performed.)
Source code
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
class MainForm : Form
{
TextBox txt;
Button btn;
System.Windows.Forms.Timer tmr;
int _counter;
MainForm()
{
_counter = 0;
tmr = new System.Windows.Forms.Timer();
tmr.Interval = 200;
tmr.Tick += (s,e)=>{
if ( _counter > 0 ) {
_counter--;
int inMsec = _counter * tmr.Interval;
Text = (inMsec/1000).ToString() + "." + ((inMsec%1000)/100).ToString();
}
else{
tmr.Stop();
txt.ReadOnly = false;
btn.Enabled = true;
SendKeyInput(txt.Text);
}
};
btn = new Button(){
Size = new Size(100,30),
Text = "Test",
};
btn.Click += (s,e)=>{
txt.ReadOnly = true;
btn.Enabled = false;
if ( !tmr.Enabled ) {
_counter = 30;
tmr.Start();
}
};
Controls.Add(btn);
txt = new TextBox(){
Location = new Point(0, 30),
Size = new Size(100,30),
Text = "Test",
};
Controls.Add(txt);
}
private static class NativeMethods
{
[DllImport("user32.dll", SetLastError = true)]
public extern static void SendInput(int nInputs, Input[] pInputs, int cbsize);
//[DllImport("user32.dll", EntryPoint = "MapVirtualKeyA")]
//public extern static int MapVirtualKey(int wCode, int wMapType);
//[DllImport("user32.dll", SetLastError = true)]
//public extern static IntPtr GetMessageExtraInfo();
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
struct MouseInput
{
public int X;
public int Y;
public int Data;
public int Flags;
public int Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct KeyboardInput
{
public short VirtualKey;
public short ScanCode;
public int Flags;
public int Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HardwareInput
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Sequential)]
struct Input
{
public int Type;
public InputUnion ui;
}
[StructLayout(LayoutKind.Explicit)]
struct InputUnion
{
[FieldOffset(0)]
public MouseInput Mouse;
[FieldOffset(0)]
public KeyboardInput Keyboard;
[FieldOffset(0)]
public HardwareInput Hardware;
}
private const int KEYEVENTF_EXTENDEDKEY = 0x0001;
private const int KEYEVENTF_KEYUP = 0x0002;
private const int KEYEVENTF_SCANCODE = 0x0008;
private const int KEYEVENTF_UNICODE = 0x0004;
private const int MAPVK_VK_TO_VSC = 0;
// private const int MAPVK_VSC_TO_VK = 1;
void SendKeyInput(string s)
{
BeginInvoke(
(MethodInvoker)delegate(){
SendInputKeyPressAndRelease(s);
}
);
}
private static void SendInputKeyPressAndRelease(string s)
{
Input[] inputs = new Input[2*s.Length];
for(int k=0; k<s.Length; k++) {
int tk = s[k];
//int vsc = NativeMethods.MapVirtualKey(tk, MAPVK_VK_TO_VSC);
inputs[2*k] = new Input();
inputs[2*k].Type = 1; // KeyBoard = 1
inputs[2*k].ui.Keyboard.VirtualKey = 0;
inputs[2*k].ui.Keyboard.ScanCode = (short)tk;
inputs[2*k].ui.Keyboard.Flags = KEYEVENTF_UNICODE;
inputs[2*k].ui.Keyboard.Time = 0;
inputs[2*k].ui.Keyboard.ExtraInfo = IntPtr.Zero;
inputs[2*k+1] = new Input();
inputs[2*k+1].Type = 1; // KeyBoard = 1
inputs[2*k+1].ui.Keyboard.VirtualKey = 0;
inputs[2*k+1].ui.Keyboard.ScanCode = (short)tk;
inputs[2*k+1].ui.Keyboard.Flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
inputs[2*k+1].ui.Keyboard.Time = 0;
inputs[2*k+1].ui.Keyboard.ExtraInfo = IntPtr.Zero;
}
NativeMethods.SendInput(inputs.Length, inputs, Marshal.SizeOf(inputs[0]));
}
[STAThread]
static void Main(string[] args)
{
Application.Run(new MainForm());
}
}
Reference site
https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-keybdinput