Trigger OS to copy (ctrl+c or Ctrl-x) programmatically - c#

I'm working on a program to trigger cut and pastes
Pastes I have no problem with (I just dump a string into the clipboard)
Cut and or Copys are proving to be a little more difficult
The program I have is out of focus and has several hot keys registered with the os CTRL+ALT+2 CTRL+ALT+3 etc)
That I want to use to trigger Windows to copy anything that is highlighted in the window that is focused
I tried doing a sendkeys
SendKeys.Send("^c");
but that seems to work once or twice if at all then stop working.
is there a better way to try to trigger windows into coping highlighted content on a different window

One way to do this is by using the Win32 SendInput function. With SendInput, you have to simulate both the key down and key up events in order for the full key press to register. To simulate CTRL+C, you'd have to do:
CTRL key down
C key down
C key up
CTRL key up
pinvoke.net has some examples of SendInput usage. One issue to be mindful of is if the key is already pressed. You can use GetAsyncKeyState to only simulate a key down event if the key is not already down.
Below is some example code of how you could simulate CTRL+C. With the code below, you can simply call Keyboard.SimulateKeyStroke('c', ctrl: true); Note that this works as if the user literally pressed CTRL+C, so the active application will behave as it always does when such an event happens (i.e. if nothing is normally copied, then nothing will be copied with this method, either).
Edit: See David's comment below about batching the sent input. The code below should be sending the entire sequence of input events through a single call to SendInput to avoid being interleaved (and misinterpreted) with real user input events.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace SimulateKeys
{
static class Keyboard
{
public static void SimulateKeyStroke(char key, bool ctrl = false, bool alt = false, bool shift = false)
{
List<ushort> keys = new List<ushort>();
if (ctrl)
keys.Add(VK_CONTROL);
if (alt)
keys.Add(VK_MENU);
if (shift)
keys.Add(VK_SHIFT);
keys.Add(char.ToUpper(key));
INPUT input = new INPUT();
input.type = INPUT_KEYBOARD;
int inputSize = Marshal.SizeOf(input);
for (int i = 0; i < keys.Count; ++i)
{
input.mkhi.ki.wVk = keys[i];
bool isKeyDown = (GetAsyncKeyState(keys[i]) & 0x10000) != 0;
if (!isKeyDown)
SendInput(1, ref input, inputSize);
}
input.mkhi.ki.dwFlags = KEYEVENTF_KEYUP;
for (int i = keys.Count - 1; i >= 0; --i)
{
input.mkhi.ki.wVk = keys[i];
SendInput(1, ref input, inputSize);
}
}
[DllImport("user32.dll")]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(ushort vKey);
struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Explicit)]
struct MOUSEKEYBDHARDWAREINPUT
{
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
struct INPUT
{
public int type;
public MOUSEKEYBDHARDWAREINPUT mkhi;
}
const int INPUT_KEYBOARD = 1;
const uint KEYEVENTF_KEYUP = 0x0002;
const ushort VK_SHIFT = 0x10;
const ushort VK_CONTROL = 0x11;
const ushort VK_MENU = 0x12;
}
class Program
{
static void Main(string[] args)
{
Thread.Sleep(3000);
Keyboard.SimulateKeyStroke('c', ctrl: true);
}
}
}

If you can get the selected text from the focused window (maybe an easier problem to solve) then you're better off using the SetText method of the System.Windows.Forms.Clipboard class.

Related

Windows SendInput (Keyboard) Not Working on Disconnect

I am running a c# application that makes use of the sendinputs method in windows to mimic keystrokes. It works fine when I am remoted into the instance, but as soon as I log out it throws an exception. Can anyone offer any thoughts on why this is happening, and how to avoid it?
UPDATE::
here is some sample code that can reproduce the issue.
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ConsoleApplication6
{
class Program
{
class SendKey
{
[StructLayout(LayoutKind.Sequential)]
private struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public int dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public int dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
private struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
};
[StructLayout(LayoutKind.Explicit)]
private struct INPUT
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)]
public MOUSEINPUT no;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
};
[DllImport("user32.dll")]
private extern static void SendInput(int nInputs, ref INPUT pInputs, int cbsize);
[DllImport("user32.dll", EntryPoint = "MapVirtualKeyA")]
private extern static int MapVirtualKey(int wCode, int wMapType);
private const int INPUT_KEYBOARD = 1;
private const int KEYEVENTF_KEYDOWN = 0x0;
private const int KEYEVENTF_KEYUP = 0x2;
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
private void Send(Keys key, bool isEXTEND)
{
INPUT inp = new INPUT();
inp.type = INPUT_KEYBOARD;
inp.ki.wVk = (short)key;
inp.ki.wScan = (short)MapVirtualKey(inp.ki.wVk, 0);
inp.ki.dwFlags = ((isEXTEND) ? (KEYEVENTF_EXTENDEDKEY) : 0x0) | KEYEVENTF_KEYDOWN;
inp.ki.time = 0;
inp.ki.dwExtraInfo = 0;
SendInput(1, ref inp, Marshal.SizeOf(inp));
System.Threading.Thread.Sleep(100);
inp.ki.dwFlags = ((isEXTEND) ? (KEYEVENTF_EXTENDEDKEY) : 0x0) | KEYEVENTF_KEYUP;
SendInput(1, ref inp, Marshal.SizeOf(inp));
}
static void Main()
{
while(true)
{
System.Threading.Thread.Sleep(2000);
SendKey s = new SendKey();
s.Send(Keys.Z, false);
s.Send(Keys.Left, true);
}
}
}
}
}
if you build this and just run it on a free windows server ec2 instance with notepad in focus it will print zzzzzz continuously while you are remoted into the instance, however, as soon as you remote out of the instance, it will stop printing until you log back in.

SendInput moves the cursor when I try to perform a mouse click

I'm trying to simulate a left mouse button click with SendInput, and it works but also moves the cursor to the upper left corner of the screen (0,0) and I can't figure it out why.
(I'm using the same structures to move the cursor (relatively and absolutely) and that's working.)
private static void Send(INPUT input)
{
SendInput(1, ref input, Marshal.SizeOf(new INPUT()));
}
private static void MouseAction(MouseFlags mf)
{
INPUT aInput = new INPUT();
aInput.type = InputType.INPUT_MOUSE;
aInput.mkhi.mi.dwFlags = mf;
Send(aInput);
}
// Performs a LeftClick but moves the cursor to (0.0)
public static void LeftClick()
{
MouseAction(MouseFlags.MOUSEEVENTF_LEFTDOWN | MouseFlags.MOUSEEVENTF_LEFTUP);
}
The result is the same when I fill out all of the structure members.
The full INPUT definition:
[StructLayout(LayoutKind.Sequential)]
struct INPUT
{
public InputType type;
public MouseKeyboardHardwareUnion mkhi;
}
[StructLayout(LayoutKind.Explicit)]
struct MouseKeyboardHardwareUnion
{
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
}
[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public MouseFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
// Not relevant
[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
public KeyboardVirtual wVk;
public ushort wScan;
public KeyboardFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
Filling out the MOUSEINPUT's dx and dy fields with the cursor's current position doesn't seem to solve the problem either.
First, it would really help if you would show the definition of your INPUT structure.
Second, in case your INPUT structure contains the X and Y coordinate, set them using:
aInput.somethingX = Cursor.Position.X;
aInput.somethingY = Cursor.Position.Y;
because otherwise it will of course reset your cursor position.
Third, just search on google and stackoverflow and you find plenty of people that already asked this and got helpful answers like this.
I figured it out, the problem wasn't with the INPUT structure, I called the LeftClick() function inside an EventArgs constructor. After I moved it outside it works just fine.

WPF Equivalent to SendInput?

Is there an equivalent to SendInput for WPF? I've looked into AutomationPeer classes but was not successfull.
I simply want to send a Keydown (the Enter Key). Simply raising the event (RaiseEvent) does not work in my scenario.
Here is what I have, which is working. I'd prefer to have a managed code alternative.
private void comboSelectionChanged(object sender, SelectionChangedEventArgs args)
{
((ComboBox)sender).Focus();
// send keydown
INPUT input = new INPUT();
input.type = INPUT_KEYBOARD;
input.union.keyboardInput.wVk = 0x0D;
input.union.keyboardInput.time = 0;
SendInput(1, ref input, Marshal.SizeOf(input));
}
[DllImport("user32.dll", SetLastError = true)]
private static extern int SendInput(int nInputs, ref INPUT mi, int cbSize);
[StructLayout(LayoutKind.Sequential)]
private struct INPUT
{
public int type;
public INPUTUNION union;
};
[StructLayout(LayoutKind.Explicit)]
private struct INPUTUNION
{
[FieldOffset(0)]
public MOUSEINPUT mouseInput;
[FieldOffset(0)]
public KEYBDINPUT keyboardInput;
};
[StructLayout(LayoutKind.Sequential)]
private struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
};
private const int INPUT_MOUSE = 0;
private const int INPUT_KEYBOARD = 1;
You can emulate a keystroke like this:
public void SendKey(UIElement sourceElement, Key keyToSend)
{
KeyEventArgs args = new KeyEventArgs(InputManager.Current.PrimaryKeyboardDevice, PresentationSource.FromVisual(sourceElement), 0, keyToSend);
args.RoutedEvent = Keyboard.KeyDownEvent;
InputManager.Current.ProcessInput(args);
}
You could then call it like this:
SendKey(myComboBox, Key.Enter);
I suppose you can put this in a static class somewhere, or even make an extension method out of it. However, I would argue that in most cases there is a more elegant way to accomplish this.
I hope this helps.

Why does pressing the key once act like it is repeatedly pressed?

I'm using a Winform to give Buttons in a DirectX Game. Therefore I'm using this class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace DirectInput
{
public class cDirectInput
{
[DllImport("user32.dll")]
static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);
[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 KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
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 KEYBDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
}
const int KEYEVENTF_EXTENDEDKEY = 0x0001;
const int KEYEVENTF_KEYUP = 0x0002;
const int KEYEVENTF_UNICODE = 0x0004;
const int KEYEVENTF_SCANCODE = 0x0008;
public void Send_Key(short Keycode, int KeyUporDown)
{
INPUT[] InputData = new INPUT[1];
InputData[0].type = 1;
InputData[0].ki.wScan = Keycode;
InputData[0].ki.dwFlags = KeyUporDown;
InputData[0].ki.time = 0;
InputData[0].ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
}
}
}
Then I'm sending Buttons with this:
DirectInput.cDirectInput d = new DirectInput.cDirectInput();
d.Send_Key(0x11, 0x0008);
But when I send it it is permanent. When I send w the player is moving forward forever. I can stop that by pressing w on the keyboard. Why isn't it stopping? When I send it to an editor it stops when I stop sending, ingame it doesn't stop. What is the problem?
Thank you in advance!
You're sending a key down message, but not sending a key up message following it. From the documentation:
KEYBDINPUT.dwFlags:
KEYEVENTF_KEYUP (0x0002)
If specified, the key is being released. If not specified, the key is being pressed.
To move forward for 1 second, try:
d.Send_Key(0x11, 0x0008);
Thread.Sleep(1000);
d.Send_Key(0x11, 0x000A);
Note that the reason pressing w fixes the problem is it sends a keydown event (which would be ignored) and then a keyup event, finally releasing the key.

I'd like to send some keys by SendInput API

I want to send some keys to a game by SendInput API on C#. (My environment is Windows 7 64bit)
I wrote some codes as follows:
[DllImport("user32.dll")]
static extern int SendInput(int nInputs, INPUT[] pInputs, int cbSize);
[StructLayout(LayoutKind.Sequential)]
private struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct HARDWAREINPUT
{
public uint uMsg;
public ushort wParamL;
public ushort wParamH;
}
[StructLayout(LayoutKind.Explicit)]
private struct INPUT
{
[FieldOffset(0)]
public uint type;
[FieldOffset(4)]
public MOUSEINPUT mi;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
}
public static void WalkFront()
{
INPUT[] inputs = new INPUT[1];
Keys virtualKeycode = (Keys)0x15;
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = (short)virtualKeycode;
inputs[0].ki.wScan = (short)MapVirtualKey((int)virtualKeycode, 0);
inputs[0].ki.dwFlags = KEYEVENTF_SCANCODE;
inputs[0].ki.time = 0;
inputs[0].ki.dwExtraInfo = GetMessageExtraInfo();
SendInput(1, inputs, Marshal.SizeOf(inputs[0]));
}
However it does not work correctly.
Apparently, this code can send BackSpace to the game. In fact, this code can delete a character on Notepad.exe.
Bizarrely, this code only sends BackSpace to the applications. I changed the keycode (I tried 0x14, 0x13, 0x12...etc) in this code. However, this code only sends BackSpace
I want to send another key (J, K, L...etc) to applications but I could not.
Any advices?
Thanks
Remember that a keypress event consists of a key-down and after that a key-up event. That means to "send a backspace" you need to call SendInput twice, once with the key pressed, once with the key released.
If you fail to call SendInput with the key released, subsequent key presses will most likely be ignored by most apps.

Categories

Resources