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)
Cu开发者_StackOverflow社区t 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.
精彩评论