SendInputについて云々
エミュレーションで文字列送信で全角が送信できない
文字列送信ノードも安定しない
LCtrlとRCtrlの区別が出来ない
このような問題に対応する方法がテーマです。
まずは文字列送信について
Param(
[Parameter(Mandatory=$true)]
[int]$hWnd,
[Parameter(Mandatory=$true)]
[string]$sendString
)
$source = @'
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class SendInputAPI
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[StructLayout(LayoutKind.Sequential)]
private struct Input
{
public int Type;
public InputUnion ui;
}
[StructLayout(LayoutKind.Explicit)]
private struct InputUnion
{
[FieldOffset(0)]
public MouseInput Mouse;
[FieldOffset(0)]
public KeyboardInput Keyboard;
[FieldOffset(0)]
public HardwareInput Hardware;
}
[StructLayout(LayoutKind.Sequential)]
private struct MouseInput
{
public int x;
public int y;
public int Data;
public int Flags;
public int Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct KeyboardInput
{
public ushort VirtualKey;
public ushort ScanCode;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct HardwareInput
{
public int uMsg;
public short wParamL;
public short wParamH;
}
private const int INPUT_KEYBOARD = 0x1;
private const int KEYEVENTF_KEYDOWN = 0x0;
private const int KEYEVENTF_KEYUP = 0x2;
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
private const int KEYEVENTF_UNICODE = 0x4;
[DllImport("user32.dll")]
private static extern uint SendInput(int nInputs, Input[] pInputs, int cbsize);
public static void SendString(int hWnd, string s){
SetForegroundWindow(new IntPtr(hWnd));
Input[] inputs = new Input[2 * (s.Length)];
for(int k=0; k < s.Length; k++)
{
ushort tk = s[k];
inputs[2 * k] = new Input()
{
Type = INPUT_KEYBOARD,
ui = new InputUnion() {
Keyboard = new KeyboardInput()
{
VirtualKey = 0,
ScanCode = tk,
Flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYDOWN,
Time = 0,
ExtraInfo = IntPtr.Zero
}
}
};
inputs[2 * k + 1] = new Input()
{
Type = INPUT_KEYBOARD,
ui = new InputUnion()
{
Keyboard = new KeyboardInput()
{
VirtualKey = 0,
ScanCode = tk,
Flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP,
Time = 0,
ExtraInfo = IntPtr.Zero
}
}
};
}
SendInput(inputs.Length, inputs, Marshal.SizeOf(inputs[0]));
}
}
'@
Add-Type -TypeDefinition $source -ReferencedAssemblies System.Windows.Forms,System.Drawing
[SendInputAPI]::SendString($hWnd,$sendString)
長いですがpowershellスクリプトです
ポイントはKEYEVENTF_UNICODEでこれを付与することによってunicode送信できます
WinActorから使用する場合SetForegroundWindowしないと安定しなかったので操作対象のhWndが必要です
WinActorから使用する場合は
ウインドウハンドル取得で hWnd を取得
文字列連結で -ExecutionPolicy RemoteSigned -File スクリプトのパス hWnd 送信文字列
を組み立て(ExecutionPolicyはお好みで)
コマンド実行でpowershell実行オプションに上記で連結した文字列
LCtrl送信
Param(
[Parameter(Mandatory=$true)]
[int]$hWnd
)
$source = @'
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class SendInputAPI
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[StructLayout(LayoutKind.Sequential)]
private struct Input
{
public int Type;
public InputUnion ui;
}
[StructLayout(LayoutKind.Explicit)]
private struct InputUnion
{
[FieldOffset(0)]
public MouseInput Mouse;
[FieldOffset(0)]
public KeyboardInput Keyboard;
[FieldOffset(0)]
public HardwareInput Hardware;
}
[StructLayout(LayoutKind.Sequential)]
private struct MouseInput
{
public int x;
public int y;
public int Data;
public int Flags;
public int Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct KeyboardInput
{
public ushort VirtualKey;
public ushort ScanCode;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct HardwareInput
{
public int uMsg;
public short wParamL;
public short wParamH;
}
private const int INPUT_KEYBOARD = 0x1;
private const int KEYEVENTF_KEYDOWN = 0x0;
private const int KEYEVENTF_KEYUP = 0x2;
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
[DllImport("user32.dll")]
private static extern uint SendInput(int nInputs, Input[] pInputs, int cbsize);
public static void SendLCtrlKey(int hWnd){
SetForegroundWindow(new IntPtr(hWnd));
Input[] inputs = new Input[2];
inputs[0] = new Input()
{
Type = INPUT_KEYBOARD,
ui = new InputUnion() {
Keyboard = new KeyboardInput()
{
VirtualKey = (ushort)Keys.LControlKey,
Flags = KEYEVENTF_KEYDOWN,
Time = 0,
ExtraInfo = IntPtr.Zero
}
}
};
inputs[1] = new Input()
{
Type = INPUT_KEYBOARD,
ui = new InputUnion()
{
Keyboard = new KeyboardInput()
{
VirtualKey = (ushort)Keys.LControlKey,
Flags = KEYEVENTF_KEYUP,
Time = 0,
ExtraInfo = IntPtr.Zero
}
}
};
SendInput(inputs.Length, inputs, Marshal.SizeOf(inputs[0]));
}
}
'@
Add-Type -TypeDefinition $source -ReferencedAssemblies System.Windows.Forms,System.Drawing
[SendInputAPI]::SendLCtrlKey($hWnd)
RCtrl送信
Param(
[Parameter(Mandatory=$true)]
[int]$hWnd
)
$source = @'
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class SendInputAPI
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[StructLayout(LayoutKind.Sequential)]
private struct Input
{
public int Type;
public InputUnion ui;
}
[StructLayout(LayoutKind.Explicit)]
private struct InputUnion
{
[FieldOffset(0)]
public MouseInput Mouse;
[FieldOffset(0)]
public KeyboardInput Keyboard;
[FieldOffset(0)]
public HardwareInput Hardware;
}
[StructLayout(LayoutKind.Sequential)]
private struct MouseInput
{
public int x;
public int y;
public int Data;
public int Flags;
public int Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct KeyboardInput
{
public ushort VirtualKey;
public ushort ScanCode;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct HardwareInput
{
public int uMsg;
public short wParamL;
public short wParamH;
}
private const int INPUT_KEYBOARD = 0x1;
private const int KEYEVENTF_KEYDOWN = 0x0;
private const int KEYEVENTF_KEYUP = 0x2;
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
[DllImport("user32.dll")]
private extern static uint SendInput(int nInputs, Input[] pInputs, int cbsize);
[DllImport("user32.dll", EntryPoint = "MapVirtualKeyA")]
private extern static uint MapVirtualKey(uint wCode, uint wMapType);
private const int MAPVK_VK_TO_VSC_EX = 4;
public static void SendRCtrlKey(int hWnd){
SetForegroundWindow(new IntPtr(hWnd));
Input[] inputs = new Input[2];
uint vsc = MapVirtualKey((uint)Keys.RControlKey, MAPVK_VK_TO_VSC_EX);
inputs[0] = new Input()
{
Type = INPUT_KEYBOARD,
ui = new InputUnion() {
Keyboard = new KeyboardInput()
{
VirtualKey = (ushort)Keys.RControlKey,
ScanCode = (ushort)vsc,
Flags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYDOWN,
Time = 0,
ExtraInfo = IntPtr.Zero
}
}
};
inputs[1] = new Input()
{
Type = INPUT_KEYBOARD,
ui = new InputUnion()
{
Keyboard = new KeyboardInput()
{
VirtualKey = (ushort)Keys.RControlKey,
ScanCode = (ushort)vsc,
Flags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
Time = 0,
ExtraInfo = IntPtr.Zero
}
}
};
SendInput(inputs.Length, inputs, Marshal.SizeOf(inputs[0]));
}
}
'@
Add-Type -TypeDefinition $source -ReferencedAssemblies System.Windows.Forms,System.Drawing
[SendInputAPI]::SendRCtrlKey($hWnd)
LCtrl と RCtrl の違いは KEYEVENTF_EXTENNDKEY 及び ScanCode の部分です
長くなりましたが、まあ興味があるひと向けです