在C#中,有没有办法能够始终如一地获取当前焦点窗口的选定文本内容?

时间:2009-03-17 04:10:04

标签: c# .net winforms winapi

在我的c#.Net应用程序中,我一直试图能够在当前关注的窗口中检索当前选定的文本。 (请注意,它可以是在窗口中打开的任何窗口,例如word或safari)。

我能够检索当前聚焦控件的句柄。 (使用对user32.dll和kernel32.dll的几个互操作调用)。

但是,我无法始终能够取回所选文字。

我尝试过使用SENDMESSAGE和GET_TEXT。然而,这似乎只适用于某些应用程序(适用于像wordpad这样的简单应用程序,不适用于更复杂的应用程序,如firefox或word)。

我尝试过使用SENDMESSAGE和WM_COPY。但是,这似乎只适用于某些控件。 (我认为WM_COPY会导致与手动按CTRL-C完全相同的行为,但事实并非如此)。

我尝试过使用SENDMESSAGE和WM_KEYUP + WM_KEYDOWN手动激发复制命令。这不是经常工作。 (可能与用户按下的实际热键重叠以调用我的应用程序)。

有关始终能够检索当前所选文本的任何想法吗? (在任何申请中)。

7 个答案:

答案 0 :(得分:4)

我通过几个方面的组合来完成这项工作。所以:

  1. 等待当前按下的任何修饰符被释放。
  2. 发送控件+ c(使用此回答Trigger OS to copy (ctrl+c or Ctrl-x) programmatically

            bool stillHeld = true;
            int timeSlept = 0;
    
            do
            {
                // wait until our hotkey is released
                if ((Keyboard.Modifiers & ModifierKeys.Control) > 0 ||
                    (Keyboard.Modifiers & ModifierKeys.Alt) > 0 ||
                    (Keyboard.Modifiers & ModifierKeys.Shift) > 0)
                {
                    timeSlept += 50;
                    System.Threading.Thread.Sleep(timeSlept);
                }
                else
                {
                    stillHeld = false;
                }
            } while (stillHeld && timeSlept < 1000);
    
            Keyboard.SimulateKeyStroke('c', ctrl: true);
    
  3. 我正在使用WPF,因此Keyboard.Modifiers是System.Windows.Input.Keyboard,而Keyboard.SimulateKeyStroke来自Chris Schmick的答案。

    注意,timeSlept是我继续快乐之前等待用户放开密钥的最长时间。

答案 1 :(得分:2)

我设法获得了wordpad / notepad以及任何支持UI自动化的文本。

以下代码在某些情况下可能适合您。我将开始使用Reflector来查看Windows如何为TextBoxBase.SelectedText属性中的文本框。

public static string SelectedText
{
    get
    {
        AutomationElement focusedElement = AutomationElement.FocusedElement;

        object currentPattern = null;

        if (focusedElement.TryGetCurrentPattern(TextPattern.Pattern, out currentPattern))
        {
            TextPattern textPattern = (TextPattern)currentPattern;
            TextPatternRange[] textPatternRanges = textPattern.GetSelection();
            if (textPatternRanges.Length > 0)
            {
                string textSelection = textPatternRanges[0].GetText(-1);
                return textSelection;
            }
        }
        return string.Empty;
    }
    set
    {
        AutomationElement focusedElement = AutomationElement.FocusedElement;
        IntPtr windowHandle = new IntPtr(focusedElement.Current.NativeWindowHandle);
        NativeMethods.SendMessage(windowHandle, NativeMethods.EM_REPLACESEL, true, value);
    }
}

答案 2 :(得分:1)

我不相信这是可能的,当前重点可能不包含任何选定的文本。 (它甚至可能根本不包含任何文本)。或者当前选择可以是图标或图像。

或许要求用户首先将所选文本复制到剪贴板可能是一种解决方案。

答案 3 :(得分:1)

我可能误解了这个问题,但你能不能发送Ctrl + c?如果您知道窗口总是最重要的并且选择了要复制的文本?

SendKeys.SendWait("^c");

复制到剪贴板后,it's not tricky以编程方式检索内容(您甚至可以检查它实际上是文本)。

答案 4 :(得分:0)

我认为创建剪贴板监视器是一个不错的选择。我建议您查看Klipper(KDE剪贴板模块),它会复制您在剪贴板列表中选择的所有内容,无论是内容是文件,文件夹还是某些文本。

可以找到更多详细信息here

答案 5 :(得分:0)

嗯......你觉得它很容易吗?怎么样?

SendKeys.SendWait(“^ c”)的最佳替代方案;我找到了这个:

http://www.c-sharpcorner.com/Forums/ShowMessages.aspx?ThreadID=46203

但是,它仅适用于少数应用,例如记事本。对于Web浏览器,它只会崩溃。

谁有更好的东西?

答案 6 :(得分:0)

尝试使用其他方法不起作用的控件上的GetWindowText() API。