C# 如何将任何应用程序的选定文本获取到windows窗体应用程序中

C# 如何将任何应用程序的选定文本获取到windows窗体应用程序中,c#,winforms,hook,clipboard,C#,Winforms,Hook,Clipboard,这就是我想做的 当用户通过双击鼠标选择任何正在运行的应用程序的任何单词(文本)时,应将特定突出显示的单词插入到已在运行的windows应用程序中 到目前为止,我已经使用全局击键实现了该逻辑,其中用户必须触发CRT+C键盘组合键才能将所选单词复制到win form应用程序中 我想知道的是,是否有任何方法可以在不按键盘任何按钮的情况下将这些选定的文本输入到应用程序中 经过一番阅读,我找到了方法: 使用类似的方法钩住双击事件 (可选)保存剪贴板的当前状态 从user32.dll 使用WindowFro

这就是我想做的

当用户通过双击鼠标选择任何正在运行的应用程序的任何单词(文本)时,应将特定突出显示的单词插入到已在运行的windows应用程序中

到目前为止,我已经使用
全局击键
实现了该逻辑,其中用户必须触发CRT+C键盘组合键才能将所选单词复制到win form应用程序中


我想知道的是,是否有任何方法可以在不按键盘任何按钮的情况下将这些选定的文本输入到应用程序中

经过一番阅读,我找到了方法:

  • 使用类似的方法钩住双击事件
  • (可选)保存剪贴板的当前状态
  • user32.dll
  • 使用
    WindowFromPoint
    from根据光标位置获取窗口
    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);
    }
    
  • 使用
    SendMessage
    表单
    user32.dll
    发送复制命令(请参阅 )

  • 你的代码
  • (可选)恢复步骤2中保存的剪贴板内容
  • 我实施了属于我的it项目。好吧,我该怎么办,让我解释一下

    应该考虑两个主要的问题:

    • 如何在任何窗口中获取文本
    • 我应该把它存放在哪里
    所以,@jcrada的答案包含了一个很好的观点,那就是选项1

    根据上述方法,步骤必须是:

    • 从Nuget添加globalmousekeyhook
    • 通过Usr32.dll注册ClipboardContainsText事件
    • 为鼠标注册正确的事件
    • 然后开始听

    首先,创建包含剪贴板事件的Win32 helper类

    /// <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);
    }
    
    鼠标事件

    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”)这样做。

    有一些程序可以记录鼠标移动,但这离发现任何给定应用程序的底层控件似乎还有很长的路要走。例如,如果您单击窗口标签、桌面图标标签或自定义应用程序,该怎么办?老实说,你似乎不太可能制作出一款能够找出所有双击控件的应用程序。我可能离这里很远,但我有一种预感,那是办不到的。如果可以的话,我很想知道是如何实现的。但我看到一些应用程序已经实现了这一点。当我们只需单击该单词,它就会在其应用程序中显示该单词的含义?是的,但每个可以这样做的应用程序都有处理捕获和处理这些单击事件的代码,以获取此类信息“字典“你谈论的行为。好了,没有操作系统范围的方法可以做到这一点,即使你可以让Windows以这种方式运行,每个应用程序也必须实现这一点。如果你仍然有带有组合键的代码,你可以发布它吗?这正是我想要的need@Djeroen:Sry我现在没有代码,但会尝试查找并与您共享。选项1很好。现在它很有用。选项1是什么?这是应该遵循的一系列步骤:P
    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;
    }