How can I simulate a button press in .NET?
I can do it with AutoHotKey with ease:
#Persistent
SetTimer,PressTheKey,1000
Return
PressTheKey:
Send, {F5}
Return
Any application will know that the button was pressed (just like it was pressed by me). I tried doing the same with:
[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
or:
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
or using Windows Input Simulator (https://inputsimulator.codeplex.com/):
inputSimulator.Keyboard.KeyDown(VirtualKeyCode.VK_H)
They all worked in Notepad or some other apps, but they never worked in my full screen game. Any idea how I can achieve it? I would like a solution which simulates a click globally on the system level.
There is a lib out there called Interceptor that is a wrapper for the windows keyboard driver, however there are limitations - namely win8 or above are not supported - and it seems that work on it has ceased (11 months ago now). Have a look into that if it suits your needs.
I've read somewhere that there are ways to do this via the DirectInput API - as to whether this is the case I'm unsure. I've used Interceptor a few times and it worked for my needs at the time.
Hope this helps
Also
Link
Edit: Fixed links
I learned that my application is using DirectInput (thanks Gabe). This made me focus more on SendInput and I managed to send an "A" key to my application like this:
// A = 30
keyboardDirectInput.Press(30);
All key codes are available here: https://msdn.microsoft.com/en-us/library/windows/desktop/bb321074%28v=vs.85%29.aspx
The KeyboardDirectInput class:
public class KeyboardDirectInput
{
[DllImport("user32.dll")]
static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);
public void Press(VirtualKeys key)
{
INPUT[] InputData = new INPUT[2];
InputData[0].type = (int)InputType.INPUT_KEYBOARD;
InputData[0].ki.wScan = (short)key;
InputData[0].ki.dwFlags = (int)KEYEVENTF.SCANCODE;
InputData[1].type = (int)InputType.INPUT_KEYBOARD;
InputData[1].ki.wScan = (short)key;
InputData[1].ki.dwFlags = (int)(KEYEVENTF.KEYUP | KEYEVENTF.SCANCODE);
if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
{
Logger.GetInstance().Warn("SendInput failed (CODE {0})", Marshal.GetLastWin32Error());
}
}
[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
[FieldOffset(4)]
public HARDWAREINPUT hi;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public int type;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[Flags]
public enum KEYEVENTF
{
KEYDOWN = 0,
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
UNICODE = 0x0004,
SCANCODE = 0x0008,
}
[Flags]
public enum InputType
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2
}
}
Related
I'd like to click in a game's button. I've tried with several ways, SendInput, and MouseEvent are some of them. Nevertheless I always got the same result, it doesn't work.
This is the original button.
And this is the button once I click on it with SendInput or MouseEvent
The color changes, but it doesn't work at all. (I also tried with leftClick, double LeftClick, and leftClickUp/Down.) My guess is that it is just supposed to work if the click isn't virtual? I'm not sure at all, since I don't have much idea about it.
Any idea?
Little update: As I've mentioned I have tried with SendInput, MouseEvent, InputSimulator and so on, the problem is always the same, while it works out of that game, it doesn't with that button. I'm pretty sure it could be because the game detect it's a virtual click simulation.
Since some fellas asked for code. (I'll repeat, this doesn't look a problem in the code tho...)
This one is for InputSimulator.
InputSimulator sim = new InputSimulator();
sim.Mouse.LeftButtonDoubleClick();
This one is using MouseEvent
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
private const int MOUSEEVENT_LEFTDOWN = 0x02;
private const int MOUSEEVENT_LEFTUP = 0x04;
private const int MOUSEEVENT_MIDDLEDOWN = 0x20;
private const int MOUSEEVENT_MIDDLEUP = 0x40;
private const int MOUSEEVENT_RIGHTDOWN = 0x08;
private const int MOUSEEVENT_RIGHTUP = 0x10;
static void Click(){
mouse_event(MOUSEEVENT_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENT_LEFTUP, 0, 0, 0, 0);
}
private void timer1_Tick(object sender, EventArgs e) {
Click();
}
This one is using SendInput. (MouseSimulator is a static class using SendInput.)
MouseSimulator.ClickLeftMouseButton();
This is the class for the MouseSimulator.
using System;
using System.Runtime.InteropServices;
public class MouseSimulator
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
[StructLayout(LayoutKind.Sequential)]
struct INPUT
{
public SendInputEventType type;
public MouseKeybdhardwareInputUnion mkhi;
}
[StructLayout(LayoutKind.Explicit)]
struct MouseKeybdhardwareInputUnion
{
[FieldOffset(0)]
public MouseInputData mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
struct MouseInputData
{
public int dx;
public int dy;
public uint mouseData;
public MouseEventFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[Flags]
enum MouseEventFlags : uint
{
MOUSEEVENTF_MOVE = 0x0001,
MOUSEEVENTF_LEFTDOWN = 0x0002,
MOUSEEVENTF_LEFTUP = 0x0004,
MOUSEEVENTF_RIGHTDOWN = 0x0008,
MOUSEEVENTF_RIGHTUP = 0x0010,
MOUSEEVENTF_MIDDLEDOWN = 0x0020,
MOUSEEVENTF_MIDDLEUP = 0x0040,
MOUSEEVENTF_XDOWN = 0x0080,
MOUSEEVENTF_XUP = 0x0100,
MOUSEEVENTF_WHEEL = 0x0800,
MOUSEEVENTF_VIRTUALDESK = 0x4000,
MOUSEEVENTF_ABSOLUTE = 0x8000
}
enum SendInputEventType : int
{
InputMouse,
InputKeyboard,
InputHardware
}
public static void ClickLeftMouseButton()
{
INPUT mouseDownInput = new INPUT();
mouseDownInput.type = SendInputEventType.InputMouse;
mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT()));
INPUT mouseUpInput = new INPUT();
mouseUpInput.type = SendInputEventType.InputMouse;
mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT()));
}
public static void ClickRightMouseButton()
{
INPUT mouseDownInput = new INPUT();
mouseDownInput.type = SendInputEventType.InputMouse;
mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN;
SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT()));
INPUT mouseUpInput = new INPUT();
mouseUpInput.type = SendInputEventType.InputMouse;
mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTUP;
SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT()));
}
}
All of them work well out of the game, inside they just work as I described above.
Since this is happening with all buttons in the game, this is a gif showing what's happening versus what's is expecting.
This is the expected behavior.
https://gyazo.com/ffd6af281414c5b0b10e19cf7a27823d
Nevertheless this is what's happening. (You can see that the color change and it looks like if it was pressed but it clearly doesn't)
https://gyazo.com/20ebb3bc360a4a5bccbe3ea5207d201b
Your question has a really low quality. The design of the button is´t relevant, your code would be. But I´ll take a guess anyway.
Well. It looks like the click got registered. Could it be that your script presses the mousebutton and never releases it? Many UI´s wont trigger at the pressing but on the release of the button. I don´t know much about C# but in Powershell you need to tell the script to PRESS and to RELEASE the button seperatly.
In my application I'm catching keystrokes and when the keystrokes are not part of a barcode I want to send them to the application. The keystrokes need to be sent to the application itself.
I tried different methods but without success.
internal class InputSimulator
{
#pragma warning disable SA1305 // Field names should not use Hungarian notation
#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
#pragma warning disable SA1400 // Access modifier should be declared
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
[DllImport("user32.dll")]
internal static extern uint MapVirtualKey(uint uCode, uint uMapType);
struct INPUT
{
public INPUTType type;
public INPUTUnion Event;
}
[StructLayout(LayoutKind.Explicit)]
struct INPUTUnion
{
[FieldOffset(0)]
internal MOUSEINPUT mi;
[FieldOffset(0)]
internal KEYBDINPUT ki;
[FieldOffset(0)]
internal HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public KEYEVENTF dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
enum INPUTType : uint
{
INPUT_KEYBOARD = 1
}
[Flags]
enum KEYEVENTF : uint
{
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
SCANCODE = 0x0008,
UNICODE = 0x0004
}
public static void ProcessKeys(Key[] keys)
{
INPUT[] inputs = new INPUT[keys.Length + 1];
for (int i = 0; i < keys.Length; i++)
{
var virtualKey = KeyInterop.VirtualKeyFromKey(keys[i]);
uint skey = MapVirtualKey((uint)virtualKey, 0x0);
inputs[i].type = INPUTType.INPUT_KEYBOARD;
inputs[i].Event.ki.dwFlags = KEYEVENTF.SCANCODE;
inputs[i].Event.ki.wScan = (ushort)skey;
}
inputs[keys.Length].type = INPUTType.INPUT_KEYBOARD;
inputs[keys.Length].Event.ki.dwFlags = KEYEVENTF.UNICODE;
inputs[keys.Length].Event.ki.dwFlags |= KEYEVENTF.KEYUP;
uint cSuccess = SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
public static void Send(Key key)
{
if (Keyboard.PrimaryDevice != null)
{
if (Keyboard.PrimaryDevice.ActiveSource != null)
{
var e = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, key)
{
RoutedEvent = Keyboard.PreviewKeyDownEvent
};
InputManager.Current.ProcessInput(e);
}
}
}
#pragma warning restore SA1305 // Field names should not use Hungarian
notation
#pragma warning restore SA1307 // Accessible fields should begin with
upper-case letter
#pragma warning restore SA1400 // Access modifier should be declared
}
In the code below are two methods ProcessKeys and Send but they don't work. What am I doing wrong? Is there another way to achieve this? At the moment I use System.Windows.Forms.SendKeys.SendWait but I prefer a way without references to System.Windows.Forms
EDIT: My question has been tagged a a possible duplicate : SendKeys.Send Method in WPF application I tried both solutions but none of them works, maybe there's something wrong in my SendInput implementation, but I can't find out what's wrong
I'm trying to simulate keyboard input to a certain process using c#.
Inputting chars and numbers works fine, but when I try to simulate a "special character" (ENTER, TAB, etc.) key press, nothing happens.
What blows my mind is that simulating these special characters works fine on other processes such as Skype.
Any ideas of what might cause this weird interaction? I'm open to trying things in other languages as well since I haven't gotten that far in my project.
I have tried using SendInput() and PostMessage() and they both share the same result, inputing chars works, but not special keys.
I managed to solve it. I'll post my solution in case someone happens to stumble upon this post with the same problem I had.
The solution is actually rather simple. If you instead of sending virtual key codes send keyboard scan codes, everything works fine.
Here's a quick example.
using System.Runtime.InteropServices;
...
public static void PressEnter()
{
INPUT input = new INPUT();
input.type = (int)InputType.INPUT_KEYBOARD;
input.ki.wScan = 0x1C;
input.ki.dwFlags = (int)KEYEVENTF.SCANCODE;
input.ki.dwExtraInfo = GetMessageExtraInfo();
var arrayToSend = new INPUT[] { input };
SendInput(1, arrayToSend, Marshal.SizeOf(input)); //Send KeyDown
arrayToSend[0].ki.dwFlags = (int)KEYEVENTF.SCANCODE | (int)KEYEVENTF.KEYUP;
SendInput(1, arrayToSend, Marshal.SizeOf(input)); //Send KeyUp
}
Other necessary info:
[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
[FieldOffset(4)]
public HARDWAREINPUT hi;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public int type;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[Flags]
public enum InputType
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2
}
[Flags]
public enum KEYEVENTF
{
KEYDOWN = 0,
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
UNICODE = 0x0004,
SCANCODE = 0x0008,
}
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetMessageExtraInfo();
[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
I'm trying to run a program that sometimes will simulate clicks in GTA:SA. Problem is it doesn't do anything when running. I have tried this code so far:
IntPtr calculatorHandle = FindWindow(null, "GTA:SA:MP");
if (calculatorHandle == IntPtr.Zero)
{
MessageBox.Show("GTA:SA:MP isn't running");
return;
}
SetForegroundWindow(calculatorHandle);
SendKeys.SendWait("T123");
I'd be glad if you tell if something is wrong with my code. Thanks!
EDIT
This is my code after adding Neill's code:
IntPtr calculatorHandle = FindWindow(null, "GTA:SA:MP");
if (calculatorHandle == IntPtr.Zero)
{
MessageBox.Show("GTA:SA:MP isn't running");
return;
}
SetForegroundWindow(calculatorHandle);
short key = 0x14;
WindowsMessageService.SendKey(key, KeyFlag.KeyDown);
Thread.Sleep(10);
WindowsMessageService.SendKey(key, KeyFlag.KeyUp);
Your first problem is that most games make use of DirectX input. You will have to make use of the following to send keys to the game. Also, you would need to send up and down key to simulate the keypress for the game.
[StructLayout(LayoutKind.Sequential)]
struct MouseInput
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct KeyboardInput
{
public short wVk; //Virtual KeyCode (not needed here)
public short wScan; //Directx Keycode
public int dwFlags; //This tells you what is use (Keyup, Keydown..)
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HardwareInput
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Explicit)]
struct Input
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)]
public MouseInput mi;
[FieldOffset(4)]
public KeyboardInput ki;
[FieldOffset(4)]
public HardwareInput hi;
}
[Flags]
public enum KeyFlag
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
UniCode = 0x0004,
ScanCode = 0x0008
}
public static class WindowsMessageService
{
[DllImport("user32.dll")]
private static extern UInt32 SendInput(UInt32 nInputs,[MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] Input[] pInputs, Int32 cbSize);
public static void SendInput(short keycode, KeyFlag keyFlag)
{
var inputData = new Input[1];
inputData[0].type = 1;
inputData[0].ki.wScan = keycode;
inputData[0].ki.dwFlags = (int)keyFlag;
inputData[0].ki.time = 0;
inputData[0].ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, inputData, Marshal.SizeOf(typeof(Input)));
}
public static void SendKey(short keyCode, KeyFlag keyFlag)
{
SendInput(keyCode, keyFlag | KeyFlag.ScanCode);
}
}
Example of usage:
short key = 0x3B; // F1 key
WindowsMessageService.SendKey(key, KeyFlag.KeyDown);
Thread.Sleep(10);
WindowsMessageService.SendKey(key, KeyFlag.KeyUp);
I need some help about DirectInput, I'll tell what i am trying to do. I want to do my program sends key combinations to a game when i press only one key. Examp.: I'll press "r" and it will pres "1","3","2","4" keys. I found some codes from here. But they didn't worked exactly.
public static void Send_Key_Hold(short Keycode)
{
INPUT[] InputData = new INPUT[1];
InputData[0].type = 1;
InputData[0].ki.wScan = Keycode;
InputData[0].ki.dwFlags = (int)(KEYEVENTF_SCANCODE);
SendInput(1, InputData, Marshal.SizeOf(InputData[0]));
}
public static void Send_Key_Release(short Keycode)
{
INPUT[] InputData = new INPUT[1];
InputData[0].type = 1;
InputData[0].ki.wScan = Keycode;
InputData[0].ki.dwFlags = (int)(KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE);
SendInput(1, InputData, Marshal.SizeOf(InputData[0]));
}
Here is my code and my question: When I'm using Send_Key_Hold only it presses one key in the game and other combination keys not pressed because first key is holded i think. When I'm using Send_Key_Hold and Send_Key_Release together it doesn't press any buttons on game. But on desktop (i mean anyother application not game) it presses the key.
I've found this example on internet. Tested it on my own when I tried to do the same thing as you are trying now.
[Flags]
private enum InputType
{
Mouse = 0,
Keyboard = 1,
Hardware = 2
}
[Flags]
private enum KeyEventF
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
Unicode = 0x0004,
Scancode = 0x0008,
}
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, Input[] pInputs, int cbSize);
[DllImport("user32.dll")]
private static extern IntPtr GetMessageExtraInfo();
public static void SendKey(ushort key)
{
Input[] inputs =
{
new Input
{
type = (int) InputType.Keyboard,
u = new InputUnion
{
ki = new KeyboardInput
{
wVk = 0,
wScan = key,
dwFlags = (uint) (KeyEventF.KeyDown | KeyEventF.Scancode),
dwExtraInfo = GetMessageExtraInfo()
}
}
}
};
SendInput((uint) inputs.Length, inputs, Marshal.SizeOf(typeof (Input)));
}
private struct Input
{
public int type;
public InputUnion u;
}
[StructLayout(LayoutKind.Explicit)]
private struct InputUnion
{
[FieldOffset(0)] public readonly MouseInput mi;
[FieldOffset(0)] public KeyboardInput ki;
[FieldOffset(0)] public readonly HardwareInput hi;
}
[StructLayout(LayoutKind.Sequential)]
private struct MouseInput
{
public readonly int dx;
public readonly int dy;
public readonly uint mouseData;
public readonly uint dwFlags;
public readonly uint time;
public readonly IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct KeyboardInput
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public readonly uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct HardwareInput
{
public readonly uint uMsg;
public readonly ushort wParamL;
public readonly ushort wParamH;
}
Now use SendKey(0x14) to send your T key to the active window (or game).
Note: You need KeyEventF.Scancode as your flag or the wScan property will be ignored!