winforms 如何将任何应用程序的选定文本放入windows窗体应用程序

kwvwclae  于 2023-03-19  发布在  Windows
关注(0)|答案(3)|浏览(164)

这就是我要做的,
当用户通过双击鼠标选择任何正在运行的应用程序的任何单词(文本)时,应将特定突出显示的单词插入到已经运行的Windows应用程序中。
到目前为止,我已经实现了使用Global Keystroke的逻辑,其中用户必须触发CRT+ C键盘组合键,将选定的单词复制到win表单应用程序中。
我想知道的是,有没有办法让这些选定的文本进入应用程序,而没有任何按钮按下键盘?

7fhtutme

7fhtutme1#

经过一番阅读,我已经找到了办法:
1.使用类似globalmousekeyhook.codeplex.com的代码挂钩双击事件
1.保存剪贴板的当前状态
1.使用GetCursorPosuser32.dll获取当前鼠标位置
1.使用WindowFromPointuser32.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);
}

1.使用SendMessage``user32.dll发送复制命令(参见Using User32.dll SendMessage To Send Keys With ALT Modifier
1.您的代码
1.恢复在步骤2中保存的剪贴板内容

hk8txs48

hk8txs482#

我实现了属于我的this项目。好的,我该怎么处理这个,让我解释一下。
应该考虑两件主要的事情。

  • 我怎样才能在任何窗口内得到文本?
  • 我应该把它存放在哪里?

所以,@jcrada的答案包含了一个很好的观点,那就是选项1。
根据上述方法,步骤必须是:

  • 从Nuget添加全局鼠标键钩。
  • 通过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);
}

注册鼠标和剪贴板事件,

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

诀窍是发送复制命令到窗口或操作系统另一方面控制+C命令,所以SendKeys.SendWait("^c");这样做。

zvokhttg

zvokhttg3#

前面的两个答案是有点难懂不详细。无论如何,非常感谢他们,因为它帮助我实现了这个功能,经过多次尝试。

现在是2021年!让我们深入了解我详细、简单且最新的方法

1.从Nuget安装鼠标键挂钩,它以前是全局鼠标键挂钩。
1.将鼠标事件(MouseDoubleClick事件和MouseDragFinished事件,在这种情况下,您可能选择了一些文本)注册到函数中。
1.保存剪贴板的当前内容以便以后恢复。(可选)
1.清除剪贴板以确定您是否已在以后选择了某些文本。
1.发送Ctrl+C命令简单通过System.Windows.Forms.SendKeys.SendWait("^c");
1.获取剪贴板的内容。
如果你已经选择了一些文本,通过System.Windows.Clipboard.GetText()简单地得到它,然后做任何你想做的事情。
如果没有,请恢复剪贴板。(可选)
这是我的代码

private IKeyboardMouseEvents globalMouseHook;

public MainWindow()
{
    // Note: for the application hook, use the Hook.AppEvents() instead.
    globalMouseHook = Hook.GlobalEvents();

    // Bind MouseDoubleClick event with a function named MouseDoubleClicked.
    globalMouseHook.MouseDoubleClick += MouseDoubleClicked;

    // Bind DragFinished event with a function.
    // Same as double click, so I didn't write here.
    globalMouseHook.MouseDragFinished += MouseDragFinished;
}

// I make the function async to avoid GUI lags.
private async void MouseDoubleClicked(object sender, System.Windows.Forms.MouseEventArgs e)
{
    // Save clipboard's current content to restore it later.
    IDataObject tmpClipboard = System.Windows.Clipboard.GetDataObject();

    System.Windows.Clipboard.Clear();

    // I think a small delay will be more safe.
    // You could remove it, but be careful.
    await Task.Delay(50);

    // Send Ctrl+C, which is "copy"
    System.Windows.Forms.SendKeys.SendWait("^c");

    // Same as above. But this is more important.
    // In some softwares like Word, the mouse double click will not select the word you clicked immediately.
    // If you remove it, you will not get the text you selected.
    await Task.Delay(50);

    if (System.Windows.Clipboard.ContainsText())
    {
        string text = System.Windows.Clipboard.GetText();
        
        // Your code

    }
    else
    {
        // Restore the Clipboard.
        System.Windows.Clipboard.SetDataObject(tmpClipboard);
    }
}

相关问题