Send keystrokes to WPF application itself - c#

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

Related

Trouble with simulating keyboard input to process

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);

How to programatically simulate a button press?

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
}
}

Simulate keyboard click in GTA:SA

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);

C# SendInput Alt/Ctrl/Shift Keys not getting Released

I am using the below code to pass special keys using SendInput. I am facing one strange issue. If user sends any of Alt/Ctrl/Shift, the key remains pressed e.g. if user passes Alt + F4, the code runs properly and action is completed successfully but Alt key remains pressed. I need to manually click Alt key after the operation is completed. Please let me know to handle the same in the code itself. Below is the code used to send special keys.
namespace RemoteDesktopSendKeys
{
class Program
{
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
}
[DllImport("user32.dll", SetLastError = true)]
static extern UInt32 SendInput(int numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);
[DllImport("user32.dll")]
public static extern IntPtr GetMessageExtraInfo();
[System.Runtime.InteropServices.DllImport("user32.dll")]
internal static extern uint MapVirtualKey(uint uCode, uint uMapType);
private const int KEYEVENTF_KEYUP1 = 0x0002;
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern int MapVirtualKey(int uCode, int uMapType);
static void Main(string[] args)
{
Thread.Sleep(3000);
int[] keyboardStrokes = { (int)Keys.LMenu,(int)Keys.F4 };
//int[] keyboardStrokes = { (int)Keys.ControlKey, (int)Keys.A };
SendSpecialKeys("test", keyboardStrokes);
//SendSpecialKeys("F5",keyboardStrokes);
}
private static void SendSpecialKeys(string text, int[] modifiers)
{
List<int> arrKeys = new List<int>();
Keys key;
if (modifiers != null && modifiers.Length > 0)
{
for (int i = 0; i < modifiers.Length; i++)
{
arrKeys.Add(modifiers[i]);
}
}
if (!string.IsNullOrEmpty(text))
{
if (Enum.TryParse(text, out key))
arrKeys.Add((int)key);
else
SendText(text);
}
System.Threading.Thread.Sleep(1000);
int[] arrKeyStrokes = arrKeys.ToArray();
INPUT[] inputs = new INPUT[arrKeyStrokes.Length + 1];
for (int i = 0; i < arrKeyStrokes.Length; i++)
{
uint skey = MapVirtualKey((uint)arrKeyStrokes[i], (uint)0x0);
inputs[i].type = INPUTType.INPUT_KEYBOARD;
inputs[i].Event.ki.dwFlags = KEYEVENTF.SCANCODE;
inputs[i].Event.ki.wScan = (ushort)skey;
}
inputs[arrKeyStrokes.Length].type = INPUTType.INPUT_KEYBOARD;
inputs[arrKeyStrokes.Length].Event.ki.dwFlags = KEYEVENTF.SCANCODE;
inputs[arrKeyStrokes.Length].Event.ki.dwFlags |= KEYEVENTF.KEYUP;
SendInput(inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
public static void SendText(string text)
{
List<INPUT> kbInput = new List<INPUT>();
foreach (char c in text)
{
// Send a key down followed by key up.
foreach (bool keyUp in new bool[] { false, true })
{
INPUT input = new INPUT
{
type = INPUTType.INPUT_KEYBOARD,
Event = new INPUTUnion
{
// This will contain keyboard event information
ki = new KEYBDINPUT
{
wVk = 0,
wScan = c,
dwFlags = KEYEVENTF.UNICODE | (keyUp ? KEYEVENTF.KEYUP : 0),
dwExtraInfo = GetMessageExtraInfo(),
}
}
};
kbInput.Add(input);
}
}
// Call SendInputWindows API to send input
SendInput((int)kbInput.Count, kbInput.ToArray(), Marshal.SizeOf(typeof(INPUT)));
}
}
}
The following code can be used to release particular key. Below is the sample code to release control key.
uint ctrlkey = MapVirtualKey((uint)Keys.ControlKey, (uint)0x0);
inputs[index].type = INPUTType.INPUT_KEYBOARD;
inputs[index].Event.ki.dwFlags = KEYEVENTF.SCANCODE;
inputs[index].Event.ki.dwFlags |= KEYEVENTF.KEYUP;
inputs[index].Event.ki.wScan = (ushort)ctrlkey;
Need to make sure that proper key is released by passing index properly.

C# DirectInput SendInput Doesn't affect to game

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!

Categories