[DllImport("user32.dll")]
static extern uint SendInput(uint nInputs, INPUT [] pInputs, int cbSize);
Private Declare Function SendInput Lib "user32.dll" (ByVal cInputs As Integer, ByRef pInputs As INPUT, ByVal cbSize As Integer) As Integer
[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
int dx;
int dy;
int mouseData;
int dwFlags;
int time;
IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
short wVk;
short wScan;
int dwFlags;
int time;
IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
int uMsg;
short wParamL;
short wParamH;
}
[StructLayout(LayoutKind.Explicit)]
struct INPUT
{
[FieldOffset(0)]
int type;
[FieldOffset(4)]
MOUSEINPUT mi;
[FieldOffset(4)]
KEYBDINPUT ki;
[FieldOffset(4)]
HARDWAREINPUT hi;
}
[DllImport("user32.dll")]
static extern IntPtr GetMessageExtraInfo();
<StructLayout(LayoutKind.Explicit)> _
Private Structure INPUT
Dim dwType As Integer
Dim mouseInput As mouseInput
Dim keyboardInput As KEYBDINPUT
Dim hardwareInput As hardwareInput
End Structure
<StructLayout(LayoutKind.Explicit)> _
Private Structure KEYBDINPUT
<FieldOffset(0)> Public wVk As Short
<FieldOffset(2)> Public wScan As Short
<FieldOffset(4)> Public dwFlags As Integer
<FieldOffset(8)> Public time As Integer
<FieldOffset(12)> Public dwExtraInfo As IntPtr
End Structure
<StructLayout(LayoutKind.Explicit)> _
Private Structure HARDWAREINPUT
<FieldOffset(0)> Public uMsg As Integer
<FieldOffset(4)> Public wParamL As Short
<FieldOffset(6)> Public wParamH As Short
End Structure
<StructLayout(LayoutKind.Explicit)> _
Private Structure MOUSEINPUT
<FieldOffset(0)> Public dx As Integer
<FieldOffset(4)> Public dy As Integer
<FieldOffset(8)> Public mouseData As Integer
<FieldOffset(12)> Public dwFlags As Integer
<FieldOffset(16)> Public time As Integer
<FieldOffset(20)> Public dwExtraInfo As IntPtr
End Structure
You'll need 3 constants to use this function,.here they are.
[c#]
const int INPUT_MOUSE = 0;
const int INPUT_KEYBOARD = 1;
const int INPUT_HARDWARE = 2;
[/c#]
I don't know how these definitions would be written in VB.NET, sorry.
Please add some!
// It might be better to write this code as a single call to SendInput passing
// all the key downs and keys ups in one array. If you do this, SendInput
// guarantees that no other keys get inbetween the whole sequence. As is stands,
// a "real" key transition could in theory sneak in the middle - and if it did
// it would inherit the states of shift, control, etc this program had set up.
class Test
{
public enum VK : ushort
{
SHIFT = 0x10,
CONTROL = 0x11,
MENU = 0x12,
ESCAPE = 0x1B,
BACK = 0x08,
TAB = 0x09,
RETURN = 0x0D,
PRIOR = 0x21,
NEXT = 0x22,
END = 0x23,
HOME = 0x24,
LEFT = 0x25,
UP = 0x26,
RIGHT = 0x27,
DOWN = 0x28,
SELECT = 0x29,
PRINT = 0x2A,
EXECUTE = 0x2B,
SNAPSHOT = 0x2C,
INSERT = 0x2D,
DELETE = 0x2E,
HELP = 0x2F,
NUMPAD0 = 0x60,
NUMPAD1 = 0x61,
NUMPAD2 = 0x62,
NUMPAD3 = 0x63,
NUMPAD4 = 0x64,
NUMPAD5 = 0x65,
NUMPAD6 = 0x66,
NUMPAD7 = 0x67,
NUMPAD8 = 0x68,
NUMPAD9 = 0x69,
MULTIPLY = 0x6A,
ADD = 0x6B,
SEPARATOR = 0x6C,
SUBTRACT = 0x6D,
DECIMAL = 0x6E,
DIVIDE = 0x6F,
F1 = 0x70,
F2 = 0x71,
F3 = 0x72,
F4 = 0x73,
F5 = 0x74,
F6 = 0x75,
F7 = 0x76,
F8 = 0x77,
F9 = 0x78,
F10 = 0x79,
F11 = 0x7A,
F12 = 0x7B,
OEM_1 = 0xBA, // ',:' for US
OEM_PLUS = 0xBB, // '+' any country
OEM_COMMA = 0xBC, // ',' any country
OEM_MINUS = 0xBD, // '-' any country
OEM_PERIOD = 0xBE, // '.' any country
OEM_2 = 0xBF, // '/?' for US
OEM_3 = 0xC0, // '`~' for US
MEDIA_NEXT_TRACK = 0xB0,
MEDIA_PREV_TRACK = 0xB1,
MEDIA_STOP = 0xB2,
MEDIA_PLAY_PAUSE = 0xB3,
LWIN =0x5B,
RWIN =0x5C
}
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public long time;
public uint dwExtraInfo;
};
[StructLayout(LayoutKind.Explicit,Size=28)]
public struct INPUT
{
public uint type;
public KEYBDINPUT ki;
};
void Test()
{
INPUT structInput;
structInput = new INPUT();
structInput.type = Win32Consts.INPUT_KEYBOARD;
// Key down shift, ctrl, and/or alt
structInput.ki.wScan = 0;
structInput.ki.time = 0;
structInput.ki.dwFlags = 0;
structInput.ki.dwExtraInfo = Win32.GetMessageExtraInfo();
if (Shift)
{
structInput.ki.wVk = (ushort)VK.SHIFT;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
}
if (Ctrl)
{
structInput.ki.wVk = (ushort)VK.CONTROL;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
}
if (Alt)
{
structInput.ki.wVk = (ushort)VK.MENU;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
}
if (Win)
{
structInput.ki.wVk = (ushort)VK.LWIN;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
}
// Key down the actual key-code
structInput.ki.wVk = vk;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
// Key up the actual key-code
structInput.ki.dwFlags = Win32Consts.KEYEVENTF_KEYUP;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
// Key up shift, ctrl, and/or alt
if (Shift)
{
structInput.ki.wVk = (ushort)VK.SHIFT;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
}
if (Ctrl)
{
structInput.ki.wVk = (ushort)VK.CONTROL;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
}
if (Alt)
{
structInput.ki.wVk = (ushort)VK.MENU;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
}
if (Win)
{
structInput.ki.wVk = (ushort)VK.LWIN;
intReturn = Win32.SendInput(1, ref structInput, (UInt32)sizeof(INPUT));
}
}
}
Imports System.Runtime.InteropServices
Public Class Form1
Private tb As New TextBox
Private WithEvents but1 As New Button
Sub New()
InitializeComponent()
tb = New TextBox : tb.Location = New Point(10, 10)
but1 = New Button : but1.Location = New Point(10, 40)
but1.Text = "example"
Me.Controls.Add(but1) : Me.Controls.Add(tb)
End Sub
Private Sub DoMouse(ByVal flags As NativeMethods.MOUSEEVENTF, ByVal newPoint As Point)
Dim input As New NativeMethods.INPUT
Dim mi As New NativeMethods.MOUSEINPUT
input.dwType = NativeMethods.InputType.Mouse
input.mi = mi
input.mi.dwExtraInfo = IntPtr.Zero
' mouse co-ords: top left is (0,0), bottom right is (65535, 65535)
' convert screen co-ord to mouse co-ords...
input.mi.dx = newPoint.X * (65535 / Screen.PrimaryScreen.Bounds.Width)
input.mi.dy = newPoint.Y * (65535 / Screen.PrimaryScreen.Bounds.Height)
input.mi.time = 0
input.mi.mouseData = 0 ' can be used for WHEEL event see msdn
input.mi.dwFlags = flags
Dim cbSize As Integer = Marshal.SizeOf(GetType(NativeMethods.INPUT))
Dim result As Integer = NativeMethods.SendInput(1, input, cbSize)
If result = 0 Then Debug.WriteLine(Marshal.GetLastWin32Error)
End Sub
Private Sub DoKeyBoard(ByVal flags As NativeMethods.KEYEVENTF, ByVal key As Keys)
Dim input As New NativeMethods.INPUT
Dim ki As New NativeMethods.KEYBDINPUT
input.dwType = NativeMethods.InputType.Keyboard
input.ki = ki
input.ki.wVk = Convert.ToInt16(key)
input.ki.wScan = 0
input.ki.time = 0
input.ki.dwFlags = flags
input.ki.dwExtraInfo = IntPtr.Zero
Dim cbSize As Integer = Marshal.SizeOf(GetType(NativeMethods.INPUT))
Dim result As Integer = NativeMethods.SendInput(1, input, cbSize)
If result = 0 Then Debug.WriteLine(Marshal.GetLastWin32Error)
End Sub
Private Sub but1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles but1.Click
'move to the textbox, click it to focus, keydown some chars...
' get textbox location in screen co-ords
Dim tbLocation As Point = Me.PointToScreen(Me.tb.Location)
' nudge it into the tb
tbLocation.X += 5
tbLocation.Y += 5
' move to the TB. it is a MOVE event, and we use ABSOLUTE co-ordinates
DoMouse(NativeMethods.MOUSEEVENTF.MOVE Or NativeMethods.MOUSEEVENTF.ABSOLUTE, tbLocation)
' click the TB
DoMouse(NativeMethods.MOUSEEVENTF.LEFTDOWN, New Point(0, 0))
' release the mouse
DoMouse(NativeMethods.MOUSEEVENTF.LEFTUP, New Point(0, 0))
' the key codes are virtual keycodes (see mdsn)
' I'm using a shortcut to save space - casting chars to ints
' if you want to change case, you need to send a shift key with the letter...
Dim message As String = "HELLO WORLD"
For Each c As Char In message
Dim key As UInteger = Convert.ToInt16(c)
DoKeyBoard(0, key) ' key down is 0 - no flag...
DoKeyBoard(NativeMethods.KEYEVENTF.KEYUP, key)
Next
DoKeyBoard(0, Keys.Decimal) ' example using keys enum which I think matches the VKEY values
DoKeyBoard(NativeMethods.KEYEVENTF.KEYUP, Keys.Decimal)
End Sub
End Class
Public Class NativeMethods
<DllImport("user32.dll", SetLastError:=True)> _
Friend Shared Function SendInput(ByVal cInputs As Int32, ByRef pInputs As INPUT, ByVal cbSize As Int32) As Int32
End Function
<StructLayout(LayoutKind.Explicit, pack:=1, Size:=28)> _
Friend Structure INPUT
<FieldOffset(0)> Public dwType As InputType
<FieldOffset(4)> Public mi As MOUSEINPUT
<FieldOffset(4)> Public ki As KEYBDINPUT
<FieldOffset(4)> Public hi As HARDWAREINPUT
End Structure
<StructLayout(LayoutKind.Sequential, pack:=1)> _
Friend Structure MOUSEINPUT
Public dx As Int32
Public dy As Int32
Public mouseData As Int32
Public dwFlags As MOUSEEVENTF
Public time As Int32
Public dwExtraInfo As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, pack:=1)> _
Friend Structure KEYBDINPUT
Public wVk As Int16
Public wScan As Int16
Public dwFlags As KEYEVENTF
Public time As Int32
Public dwExtraInfo As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, pack:=1)> _
Friend Structure HARDWAREINPUT
Public uMsg As Int32
Public wParamL As Int16
Public wParamH As Int16
End Structure
Friend Enum InputType As Integer
Mouse = 0
Keyboard = 1
Hardware = 2
End Enum
<Flags()> _
Friend Enum MOUSEEVENTF As Integer
MOVE = &H1
LEFTDOWN = &H2
LEFTUP = &H4
RIGHTDOWN = &H8
RIGHTUP = &H10
MIDDLEDOWN = &H20
MIDDLEUP = &H40
XDOWN = &H80
XUP = &H100
VIRTUALDESK = &H400
WHEEL = &H800
ABSOLUTE = &H8000
End Enum
<Flags()> _
Friend Enum KEYEVENTF As Integer
EXTENDEDKEY = 1
KEYUP = 2
UNICODE = 4
SCANCODE = 8
End Enum
End Class
Here is a managed solution: I think it works only in 2.0. Someone please verify.
Please note that there is an unresolved issue using the SendKeys class in Windows Vista RC1.
More specifically you may encounter a "Hook cannot be created." exception.
Do you know one? Please contribute it!