【问题标题】:In C#, is there a way to consistently be able to get the selected text contents of currently focused window?在 C# 中,有没有办法始终如一地获取当前聚焦窗口的选定文本内容?
【发布时间】:2009-03-17 04:10:04
【问题描述】:

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

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

但是,我无法始终如一地取回所选文本。

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

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

我尝试使用 SENDMESSAGE 和 WM_KEYUP+WM_KEYDOWN 来手动激发复制命令。但这也不是一直有效。 (可能与用户为调用我的应用程序而按下的实际热键重叠)。

关于始终能够检索当前选定文本的任何想法? (在任何应用程序上)。

【问题讨论】:

    标签: c# .net winforms winapi


    【解决方案1】:

    我通过结合几件事来完成这项工作。所以:

    1. 等待当前按下的任何修饰符被释放。
    2. 发送control+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);
      

    我正在使用 WPF,因此 Keyboard.Modifiers 是 System.Windows.Input.Keyboard,而 Keyboard.SimulateKeyStroke 来自 Chris Schmick 的回答。

    注意,timeSlept 是我等待用户放开钥匙然后继续其愉快的方式的最长时间。

    【讨论】:

      【解决方案2】:

      我设法为写字板/记事本和任何支持 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);
          }
      }
      

      【讨论】:

      • 好主意,虽然在我的机器上(Win 7).. 它不适用于 .Net 3.5 WPF 应用程序.. 返回的 windowHandle 始终为零。
      【解决方案3】:

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

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

      【讨论】:

      • 在我的例子中,我可以假设它总是选择文本。
      【解决方案4】:

      我可能误解了这个问题,但你可以发送 Ctrl+c 吗?如果您知道窗口始终位于最前面并选择要复制的文本?

      SendKeys.SendWait("^c");
      

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

      【讨论】:

      • 我试过这个和 SENDMESSAGE KEYUP/KEYDOWN。它也不总是有效。我认为它的键重叠。 (即用户按下某个组合键来激活我的程序,比如 ctrl-shift-p,ctrl-c 由程序调用,而 ctrl-shift-p 上的键向上,并且 ctrlc 不被理解)。
      【解决方案5】:

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

      更多详情请见here

      【讨论】:

        【解决方案6】:

        嗯...你觉得这很容易吗?怎么会?

        SendKeys.SendWait("^c"); 的最佳替代方案;我发现是这个:

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

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

        谁有更好的?

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-24
            • 1970-01-01
            • 2018-10-22
            相关资源
            最近更新 更多