Как получить выделенный текст любого приложения в приложение windows form

Это то, что я пытаюсь сделать,

когда пользователь выбирает любое слово (текст) любого запущенного приложения, дважды щелкнув мышью, конкретное выделенное слово должно быть вставлено в приложение windows, которое уже запущено.

до сих пор я реализовал логику, используя Global Keystroke где пользователь должен вызвать CRT+ C комбинация клавиш клавиатуры для копирования выбранного слова в приложение win form.

что я хочу знать есть ли способ получить этот выбранный текст в приложение без нажатия кнопки клавиатуры?

2 ответов


после некоторого чтения я нашел способ:

  1. закрепите событие двойного щелчка, используя что-то вроде globalmousekeyhook.codeplex.com
  2. (необязательно) сохранить текущее состояние буфера обмена
  3. получить текущее положение мыши с GetCursorPos С user32.dll
  4. сделать окна на основе позиции курсора с WindowFromPoint от user32.dll

    [DllImport("user32.dll")]
    public static extern IntPtr WindowFromPoint(Point lpPoint);
    
    [DllImport("user32.dll")]
    public static extern bool GetCursorPos(out Point lpPoint);
    
    public static IntPtr GetWindowUnderCursor()
    {
       Point ptCursor = new Point();
    
       if (!(PInvoke.GetCursorPos(out ptCursor)))
          return IntPtr.Zero;
    
       return WindowFromPoint(ptCursor);
    }
    
  5. отправить команду копирования с SendMessage форма user32.dll (см. Используя Библиотека User32.dll SendMessage для отправки Ключей с модификатором ALT)

  6. Код
  7. (необязательно) восстановить содержимое буфера обмена, сохраненное на Шаге 2

я реализовал его этой проект, который принадлежит мне. ОК, как я могу справиться с этим, позвольте мне объяснить.

следует учитывать две основные вещи.

  • как я могу получить текст внутри окна ?
  • где я должен хранить его ?

Итак, ответ @jcrada содержит один хороший момент, который является вариантом 1.

шаги должны быть, под светом вышеуказанных подходов:

  • добавить globalmousekeyhook из NuGet.
  • зарегистрировать событие ClipboardContainsText через Usr32.dll файлы
  • Регистрация правых событий для мыши
  • и начать слушать

во-первых, создайте вспомогательный класс Win32, содержащий событие буфера обмена.

/// <summary>
///     This static class holds the Win32 function declarations and constants needed by
///     this sample application.
/// </summary>
internal static class Win32
{
    /// <summary>
    ///     The WM_DRAWCLIPBOARD message notifies a clipboard viewer window that
    ///     the content of the clipboard has changed.
    /// </summary>
    internal const int WmDrawclipboard = 0x0308;

    /// <summary>
    ///     A clipboard viewer window receives the WM_CHANGECBCHAIN message when
    ///     another window is removing itself from the clipboard viewer chain.
    /// </summary>
    internal const int WmChangecbchain = 0x030D;

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
}

Seconly, Регистрация событий мыши и буфера обмена,

public void Initialize()
{
        var wih = new WindowInteropHelper(this.mainWindow);
        this.hWndSource = HwndSource.FromHwnd(wih.Handle);
        this.globalMouseHook = Hook.GlobalEvents();
        this.mainWindow.CancellationTokenSource = new CancellationTokenSource();
        var source = this.hWndSource;
        if (source != null)
        {
            source.AddHook(this.WinProc); // start processing window messages
            this.hWndNextViewer = Win32.SetClipboardViewer(source.Handle); // set this window as a viewer
        }
        this.SubscribeLocalevents();
        this.growlNotifications.Top = SystemParameters.WorkArea.Top + this.startupConfiguration.TopOffset;
        this.growlNotifications.Left = SystemParameters.WorkArea.Left + SystemParameters.WorkArea.Width - this.startupConfiguration.LeftOffset;
        this.IsInitialized = true;
}

Событий Мыши;

private void SubscribeLocalevents()
{
        this.globalMouseHook.MouseDoubleClick += async (o, args) => await this.MouseDoubleClicked(o, args);
        this.globalMouseHook.MouseDown += async (o, args) => await this.MouseDown(o, args);
        this.globalMouseHook.MouseUp += async (o, args) => await this.MouseUp(o, args);
}


private async Task MouseUp(object sender, MouseEventArgs e)
{
        this.mouseSecondPoint = e.Location;

        if (this.isMouseDown && !this.mouseSecondPoint.Equals(this.mouseFirstPoint))
        {
            await Task.Run(() =>
            {
                if (this.mainWindow.CancellationTokenSource.Token.IsCancellationRequested)
                    return;

                SendKeys.SendWait("^c");
            });
            this.isMouseDown = false;
        }
        this.isMouseDown = false;
}

private async Task MouseDown(object sender, MouseEventArgs e)
{
        await Task.Run(() =>
        {
            if (this.mainWindow.CancellationTokenSource.Token.IsCancellationRequested)
                return;

            this.mouseFirstPoint = e.Location;
            this.isMouseDown = true;
        });
}

private async Task MouseDoubleClicked(object sender, MouseEventArgs e)
{
        this.isMouseDown = false;
        await Task.Run(() =>
        {
            if (this.mainWindow.CancellationTokenSource.Token.IsCancellationRequested)
                return;

            SendKeys.SendWait("^c");
        });
}

и последняя часть, что мы будем делать, когда поймаем,

private IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
        switch (msg)
        {
            case Win32.WmChangecbchain:
                if (wParam == this.hWndNextViewer)
                    this.hWndNextViewer = lParam; //clipboard viewer chain changed, need to fix it.
                else if (this.hWndNextViewer != IntPtr.Zero)
                    Win32.SendMessage(this.hWndNextViewer, msg, wParam, lParam); //pass the message to the next viewer.

                break;
            case Win32.WmDrawclipboard:
                Win32.SendMessage(this.hWndNextViewer, msg, wParam, lParam); //pass the message to the next viewer //clipboard content changed
                if (Clipboard.ContainsText() && !string.IsNullOrEmpty(Clipboard.GetText().Trim()))
                {
                    Application.Current.Dispatcher.Invoke(
                        DispatcherPriority.Background,
                        (Action)
                            delegate
                            {
                                var currentText = Clipboard.GetText().RemoveSpecialCharacters();

                                if (!string.IsNullOrEmpty(currentText))
                                {
                                    //In this section, we are doing something, because TEXT IS CAPTURED.
                                    Task.Run(
                                        async () =>
                                        {
                                            if (this.mainWindow.CancellationTokenSource.Token.IsCancellationRequested)
                                                return;

                                            await
                                                this.WhenClipboardContainsTextEventHandler.InvokeSafelyAsync(this,
                                                    new WhenClipboardContainsTextEventArgs { CurrentString = currentText });
                                        });
                                }
                            });
                }
                break;
        }

        return IntPtr.Zero;
}

трюк отправляет команду копирования в окно или операционную систему с другой стороны Control+C command, so SendKeys.SendWait("^c"); это делаешь.