简体   繁体   English

触发操作系统以编程方式复制(ctrl + c或Ctrl-x)

[英]Trigger OS to copy (ctrl+c or Ctrl-x) programmatically

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) 我有的程序是焦点,并有几个热键注册与OS CTRL + ALT + 2 CTRL + ALT + 3等)

That I want to use to trigger Windows to copy anything that is highlighted in the window that is focused 我想用它来触发Windows复制在焦点窗口中突出显示的任何内容

I tried doing a sendkeys 我试过做一个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. 一种方法是使用Win32 SendInput函数。 With SendInput , you have to simulate both the key down and key up events in order for the full key press to register. 使用SendInput ,您必须模拟按键事件和按键事件,以便按下完整按键进行注册。 To simulate CTRL + C , you'd have to do: 要模拟CTRL + C ,你必须这样做:

  • CTRL key down 按住CTRL
  • C key down C键向下
  • C key up C键起来
  • CTRL key up 按住CTRL

pinvoke.net has some examples of SendInput usage. pinvoke.net有一些SendInput用法的例子。 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. 如果密钥尚未关闭,您可以使用GetAsyncKeyState仅模拟按键事件。

Below is some example code of how you could simulate CTRL + C . 下面是一些如何模拟CTRL + C的示例代码。 With the code below, you can simply call Keyboard.SimulateKeyStroke('c', ctrl: true); 使用下面的代码,您只需调用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 (ie if nothing is normally copied, then nothing will be copied with this method, either). 请注意,这就好像用户按字母CTRL + C一样 ,因此活动应用程序将像这样的事件发生时一样(即如果没有任何东西正常复制,那么也不会使用此方法复制任何内容)。

Edit: See David's comment below about batching the sent input. 编辑:请参阅下面关于批量发送输入的David的评论。 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. 下面的代码应该通过对SendInput的单个调用发送整个输入事件序列,以避免与真实用户输入事件交错(和误解释)。

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

如果您可以从焦点窗口中获取所选文本(可能是一个更容易解决的问题),那么最好使用System.Windows.Forms.Clipboard类的SetText方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM