15

Is there a way by which we can find out if a clip board paste event occurred in a rich text box? This event would be used in order to do certain stuff, with the pasted block of text.

thanks

Here is my code

 protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg == WM_PASTE)
        {
            OnPasteOccurred();
            MessageBox.Show("Pas");
        }
        if (m.Msg == 0x000F)
        {
            if (PaintControl)
            {
                base.WndProc(ref m);
            }
            else
            {
                m.Result = IntPtr.Zero;
            }
        }
        else
        {
            base.WndProc(ref m);
        }
    }

Edit

I wish to do some syntax highlighting or indentation based on paste events, something which this particular code editor seems to be doing very efficiently. I don't know how it is doing it. Would require help in this particular direction. I am pretty sure that there must some native Win32 code or something like that can be intercepted. I have tried tracking down keys, mouse events and it is not pretty.

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
redDragonzz
  • 1,543
  • 2
  • 15
  • 33
  • A quick web search reveals that RichTextBox doesn't handle paste events by sending WM_PASTE to itself. So I'm out of ideas. – David Heffernan Apr 11 '11 at 09:12
  • You may be able to wrap the control in your own custom class and override the [Paste](http://msdn.microsoft.com/en-us/library/system.windows.forms.richtextbox.paste.aspx) method. This is, of course, assuming that's the method being called on a paste. – Brad Christie Apr 14 '11 at 15:04
  • Hmm, in .NET 2.0, you cannot override the paste() method, and probably the reason is given by @David above. – redDragonzz Apr 15 '11 at 05:56
  • Can't you just check if your rich text control has focus and if it has, then paste was in it? – Pasi Savolainen Apr 12 '12 at 12:08

3 Answers3

19

It's a little bit tricky to detect a paste operation in the RichTextBox.

First solution may be to detect the WM_PASTE message overriding the WndProc but unfortunately the control doesn't send that message to itself when it performs a paste operation.

Naïve detection

To detect the keyboard events may work (you have to override the OnKeyDown function) then check if the key combinations (CTRL+V and SHIFT+INS). Something like this:

protected override OnKeyDown(KeyEventArgs e)
{
     bool ctrlV = e.Modifiers == Keys.Control && e.KeyCode == Keys.V;
     bool shiftIns = e.Modifiers == Keys.Shift && e.KeyCode == Keys.Insert;

     if (ctrlV || shiftIns)
         DoSomething();
}

It works well but you can't catch the paste operation made using the mouse (right click to open the context menu) and the paste operations made via drag & drop. If you do not need them you can use this solution (at least it's simply and straightforward).

Better detection

Assumption: when user types inside the RichTextBox he inserts one character per time. How can you use this? Well, when you detect a bigger change you detected a paste operation because user can't type more than once character per time (ok, you can argue that it's not always true because of Unicode surrogates). See also VB.NET version and more details about Unicode stuff.

private int _previousLength = 0;

private void richTextBox_TextChanged(object sender, EventArgs e)
{
   int currentLength = richTextBox.Text.Length;
   if (Math.Abs(currentLength - _previousLength) > 1)
      ProcessAllLines();

   _previousLength = currentLength;
}

Please note that you can't (because of how different IMEs work) use OnKeyDown (or similar). This works well only for western languages but it has problems with Unicode stuff (because, for example, String.Length property may be increased by two Char when user typed a single character. See also this post for much more details about this (well it's a strongly suggested reading even, even if - in this case - you don't care about it). In that post you'll also find code for a better algorithm to determine string length. In short you have to replace:

   int currentLength = richTextBox.Text.Length;

With this:

   int currentLength = StringInfo.GetTextElementEnumerator(richTextBox.Text)
       .Cast<string>()
       .Count();

After all this effort you may realize that...user can even paste a single character and it may go undetected. You're right, that's why this is a better detection instead of a perfect solution.

Perfect solution

The perfect solution (if you're running on Windows 8) of course exists, the native rich edit control sends an EN_CLIPFORMAT notification message. It's intended to notify a rich edit control's parent window that a paste occurred with a particular clipboard format. You can then override the WndProc of its parent to detect the WM_NOTIFY message for this notification. Anyway it's not few lines of code, check this MSDN article for details.

Community
  • 1
  • 1
Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
  • isn't the msdn one applying to windows 8 only? – redDragonzz May 18 '12 at 00:20
  • @redDragonzz sadly...yes, that's a notification message for Windows 8 only. I'll update my answer to make it clear! – Adriano Repetti May 18 '12 at 07:20
  • @redDragonzz update: I guess a "true" syntax highligh algorithm won't suffer for poor performance 'cause he won't work on the full text and it'll do it in background on another thread while you're typing. Did you take a look to the code of the (old) SharpDevelop IDE? They did provide both colors and intellisense. – Adriano Repetti May 20 '12 at 21:25
  • Context menus aren't standard on the rich text box, though, and neither is drag and drop. You can perfectly control any pasting done through that. As far as I know only the shortcuts really need checking. – Nyerguds Feb 17 '16 at 09:50
  • @Nyerguds yes, they're not enabled by default but they're _one property away_ and in many cases any non trivial use will have something more. Also keyhandling is all but not trivial for IME of east languages (I do not mention tools to help visually/motor impaired people). I don't mean that you always need extra complexity, of course! If you have a very controlled solution then even simpler approach may work (note that keyboard shortcut may be disabled an manually handled). – Adriano Repetti Feb 17 '16 at 14:29
  • @AdrianoRepetti Actually, RichTextBox doesn't have a built-in right-click menu like TextBox does; you can just specify a context menu object to use. So you'd have to program it yourself anyway. Same for drag & drop; you'd need to filter out the type and handle everything yourself. In fact, my project has a RTB that only accepts _file_ drops. – Nyerguds Feb 18 '16 at 08:47
  • @Nyerguds for _this_ question (syntax highlighting) context menu isn't built-in on RTF editor (code to do highlighting and code that adds UI would be pretty separate). Obviously yes, if you do everything by yourself (also disabling keyboard shortcuts) and you need this information on the same place then you don't need any notification from RichEdit itself! – Adriano Repetti Feb 18 '16 at 09:35
  • @AdrianoRepetti Given the fact `RichTextBox` has _really_ simple `Cut()`, `Copy()` and `Paste()` functions for handling clipboard stuff anyway, just catching and overriding the paste shortcut exactly as you showed and ending the code with `e.Handled=true;` does seems like the simplest solution here in my opinion. Then you can do whatever you want with the pasted content. – Nyerguds Feb 18 '16 at 10:29
  • Note that I somehow agree with you, here it's just for sake of discussion. I avoid whenever possible to do it for two reasons: IMEs and tools for tools for visual/motor impaired people. Handling keydown/up is a pain with many IMEs (especially in far-east) and there are endless combinations you should test (I'm still searching an answer for [this question](http://stackoverflow.com/q/27600031/1207195)). – Adriano Repetti Feb 18 '16 at 10:46
  • About other tools (also for voice dictation) I try to use _standard_ behavior/implementation whenever possible: I can assume they extensively tested their products with standard controls but with my implementation it's an incognita... – Adriano Repetti Feb 18 '16 at 10:46
  • @AdrianoRepetti Ah, IMEs. Seems like a real pain. The closest I ever got to that mess is localization-specific upper/lower case rules. Godspeed on that -_- – Nyerguds Feb 19 '16 at 07:50
  • 1
    @Nyerguds yes, it is! Actually I like that topic (self-advertising: http://stackoverflow.com/a/27229590/1207195) but yes it's a source of thousands issues and headaches! – Adriano Repetti Feb 19 '16 at 08:35
1

Starting from .Net 3.0, there is a built-in method to detect the paste event:

DataObject.AddPastingHandler(this, OnPaste);

Just call this method in the constructor. If you want for example handle the paste event yourself as if the user entered the text manually, you can use

private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
    if (e.DataObject.GetDataPresent(typeof(string)))
    {
        var text = (string)e.DataObject.GetData(typeof(string));
        var composition = new TextComposition(InputManager.Current, this, text);
        TextCompositionManager.StartComposition(composition);
    }

    e.CancelCommand();
}
LionAM
  • 1,271
  • 10
  • 28
0

I came across this old question and I would like to share my solution (it's VB but can it be easily converted). I use it to force paste as plain text when needed:

Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
    If ForcePasteAsPlainText And ((e.Control = True And e.KeyCode = Keys.V) Or (e.Shift = True And e.KeyCode = Keys.Insert)) Then
        MyBase.Paste(DataFormats.GetFormat(DataFormats.Text))
        e.Handled = True
        Return
    End If
    MyBase.OnKeyDown(e)
End Sub

Shadows Sub Paste()
    If ForcePasteAsPlainText Then
        MyBase.Paste(DataFormats.GetFormat(DataFormats.Text))
    Else
        MyBase.Paste()
    End If
End Sub

Shadows Sub Paste(clipFormat As DataFormats.Format)
    If ForcePasteAsPlainText Then
        MyBase.Paste(DataFormats.GetFormat(DataFormats.Text))
    Else
        MyBase.Paste(clipFormat)
    End If
End Sub
Disti
  • 1,228
  • 1
  • 13
  • 27