Запуск ОС для программного копирования (ctrl + c или Ctrl-x)

Я работаю над программой для запуска вырезания и вставки

Вставить у меня нет проблем (я просто выгружаю строку в буфер обмена)

Cut and / Copys оказывается немного сложнее

Программа, которая у меня есть, не в фокусе и имеет несколько горячих клавиш, зарегистрированных с помощью os CTRL + ALT + 2 CTRL + ALT + 3 и т. д.)

То, что я хочу использовать, чтобы запустить Windows для копирования всего, что выделено в окне, которое сфокусировано.

Я пробовал отправлять ключи

SendKeys.Send("^c");

но это, кажется, сработает один или два раза, если вообще перестанет работать.

есть ли лучший способ попытаться запустить окна для копирования выделенного содержимого в другое окно


person Crash893    schedule 22.05.2010    source источник


Ответы (2)


Один из способов сделать это - использовать Win32 _1 _ функция. С SendInput вы должны имитировать события нажатия и нажатия клавиши, чтобы зарегистрировать полное нажатие клавиши. Чтобы смоделировать CTRL + C, вам нужно будет сделать:

  • CTRL вниз
  • C клавиша вниз
  • C ключ вверх
  • Клавиша CTRL вверх

На pinvoke.net есть несколько примеров SendInput использования. Следует помнить о том, что клавиша уже нажата. Вы можете использовать GetAsyncKeyState только для имитации ключа событие вниз, если клавиша еще не нажата.

Ниже приведен пример кода того, как вы можете имитировать CTRL + C. С помощью приведенного ниже кода вы можете просто вызвать Keyboard.SimulateKeyStroke('c', ctrl: true);. Обратите внимание, что это работает так, как если бы пользователь буквально нажал CTRL + C, поэтому активное приложение будет вести себя так, как всегда, когда такое происходит событие (т.е. если обычно ничего не копируется, то и с помощью этого метода ничего не копируется).

Изменить. См. комментарий Дэвида ниже о пакетировании отправленных входных данных. Приведенный ниже код должен отправлять всю последовательность событий ввода через один вызов 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);
        }
    }
}
person Chris Schmich    schedule 27.05.2010
comment
ding ding ding похоже, что у нас может быть победитель! Сегодня вечером протестирую и отметлю, работает ли - person Crash893; 27.05.2010
comment
Я получаю сообщение об ошибке в строке 10, в котором говорится, что я не могу установить параметр по умолчанию, где bool shift = false. Это вещь .net3.5 (я использую экспресс 2008) - person Crash893; 27.05.2010
comment
Фактически, это вещь .NET 4.0 (параметры по умолчанию). Если вы хотите использовать необязательные параметры в .NET 3.5, вам потребуется выполнить несколько перегрузок. - person CMerat; 27.05.2010
comment
@ Crash893: да, извините, .NET 4, вы можете изменить подпись на public static void SimulateKeyStroke(char key, bool ctrl, bool alt, bool shift) и просто явно указать каждый параметр. - person Chris Schmich; 28.05.2010
comment
похоже было хорошо. Я думаю, что плохо, просто переместите остальную часть программы до 4.0, а не пытайтесь преобразовать это обратно в 3.5, спасибо, это действительно круто - person Crash893; 28.05.2010
comment
Что здесь слабое, так это то, что вы полностью упускаете суть SendInput. Он предназначен для передачи массива структур. Если вы хотите, чтобы ключевые события приходили в правильном порядке и не чередовались с реальными событиями, вам нужно сделать один вызов SendInput, передав все структуры. - person David Heffernan; 12.07.2013
comment
@DavidHeffernan: Вы правы, это вполне реальная возможность. Я не обновлял код, но, по крайней мере, добавил правку, объясняющую ситуацию. Спасибо. - person Chris Schmich; 12.07.2013

Если вы можете получить выделенный текст из сфокусированного окна (может быть, проблема проще для решения), тогда вам лучше использовать метод SetText класса System.Windows.Forms.Clipboard.

person philiphobgen    schedule 22.05.2010
comment
Я не уверен, что кто-то из пользователей следит за мной (это мог быть я), но как мне получить текст для установки? вот в чем проблема. не могли бы вы опубликовать код, так как ваш ответ, возможно, только что пролетел над моей головой - person Crash893; 24.05.2010
comment
Из вашего редактирования это звучит немного сложнее ;-) Я не делал этого в .Net, но я, кажется, помню из моих дней Delphi, что если вы знаете дескриптор элемента управления, который имеет выбранный текст, вы можете опубликовать сообщение в это окно и вернуть выбранный текст. Я также слышал упоминания об использовании для этого MS UI Automation, но никогда не пробовал. Вы можете прочитать здесь: msdn.microsoft. com / en-us / library / ms747327 (v = VS.100) .aspx. - person philiphobgen; 24.05.2010