How to override PASTE operations in ScintillaNet? - c#

I am using the Scintilla control from ScintillaNet, and I need to have some control over the paste operations (in order to be able to check some things and/or update the text to be pasted).
I've tried to create a subclass of the Scintilla control and override the WndProc method.
Then, I intercept the WM_PASTE message (0x0302), no luck. I never catch it.
Here is the code I use:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE)
{
MessageBox.Show("Paste");
}
base.WndProc(ref m);
}
Any idea?

You could remove ScintillaNET's built in CTRL+V handler with:
scintilla.Commands.RemoveBinding(Keys.V, Keys.Control, ScintillaNet.BindableCommand.Paste);
And add your own CTRL+V handler (menu item?) to do a:
ScintillaNet.Selection.Text = your_processed_clipboard_data;
That would insert at the current cursor position, or replace the current selection.

Related

Disable image paste in RichTextBox in Winforms

We have an UserControls which herits from the RichTextBox. We would like to forbid the user to enter any image(with copy paste) in this user control.
I found several places where speaking of this:
This doesn't work with Winforms
This will not work when doing a right-click -> Paste
Currently I've this solution:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys)Shortcut.CtrlV || keyData == (Keys)Shortcut.ShiftIns)
{
if (Clipboard.ContainsImage())
{
return false;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
Which works for copy paste with CTRL+C-CTRL+V, but not with the contextual menu.
EDIT
I tried the given proposition:
public class CustomRichBox : RichTextBox
{
private const int WM_PASTE = 0x0302;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE )
{
if (Clipboard.ContainsImage())
{
return;
}
}
base.WndProc(ref m);
}
}
But when I do the CTRL+V, I don't receive this message
Sadly there is no global Paste-Event, on which you can subscribe like in WPF. But maybe this is a solution for you:
hook on default "Paste" event of WinForms TextBox control
This worked for me.
You could try to override the WndProc method to filter the WM_PASTE message:
protected override void WndProc(ref Message m)
{
// Trap WM_PASTE with image:
if (m.Msg == 0x302 && Clipboard.ContainsImage())
{
return;
}
base.WndProc(ref m);
}
EDIT
Unfortunatly, this approach won't work because the RichTextBox control doesn't send the WM_PAINT message to itself. See also: Detecting if paste event occurred inside a rich text box.
As a quick workaround, I tried to copy only the Text (using RichTextBox.Text) in another RichTextBox, then copy the Rtf string in the first RichTextBox, all of that in the "TextChanged" event. However there are a lot of downsides for this workaround. First: is not optimized, second and most important: you lose all text formatting, which might be the reason you chose RichTextBox in the first place, and third: you can still see the image for one or two frames in the RTB until it disappears, and if the user is writing a large text it isn't working very smoothly (but fortunately you can fix this if you copy-paste the code in paste events). However, it turned out to be very useful in my app, which is the reason I posted this answer here.
So here is all the code (assuming you have a RichTextBox named RTB and an auxiliary RichTextBox named auxRTB):
private void RTB_TextChanged(object sender, EventArgs e)
{
int selStart = RTB.SelectionStart;
int selLenght = RTB.SelectionLength;
auxRTB.Text = RTB.Text;
RTB.TextChanged -= RTB_TextChanged;
RTB.Rtf = string.Copy(auxRTB.Rtf);
RTB.TextChanged += RTB_TextChanged;
try
{
RTB.SelectionStart = selStart;
RTB.SelectionLength = selLenght;
}
catch (Exception) { }
}
Now, if you are interested, here I'm going to explain how is that useful in my app. So I built a command system, and the only reason I chose RichTextBox insted of normal TextBox is because I wanted to give different colors to each type of thing from a command. The commands are not meant to be long so I don't have any optimiziation problems, and I don't care about losing formatting, since I always change the colors automatically.
Edit: by the way, here are some links to the same problem on other sites, which might actually help you:
Link 1: https://social.msdn.microsoft.com/Forums/en-US/0f762cb8-7383-4937-8ee8-f8df5d3a9852/disable-image-paste-in-richtextbox?forum=wpf
Link 2: C# / WPF: Richtextbox: Find all Images
Link 3: https://thomaslevesque.com/2015/09/05/wpf-prevent-the-user-from-pasting-an-image-in-a-richtextbox/

C# Detecting a Click in WndProc and calling a function after click happened

I am trying to detect a click and preform calling a function only after the click actually happened.
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m) {
//Detect a Click
if (m.Msg == 0x210 && m.WParam.ToInt32() == 513){
lastClick = DateTime.Now;
clickedHappened();
Debug.Print("Click Detected!");
}
base.WndProc(ref m);
}
private void clickedHappened(){
MessageBox.Show("Click Already Happened");
}
I think that WndProc happens way before the actual click takes place.
I was wondering if there was a way to solve this with out using a timer? or sleep(400);
The only solution I can come up with is using a timer, but I want to get rid of some of my existing timers. It seems that the click actually happens 200 - 350 ms after it was detected in WndProc.
WndProc is short for Window Procedure, its the procedure that handles everything for the window, drawing, mouse capture, keyboard capture, resizing...
There are also several ways you can capture the mouse for varying results
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
switch(m.Msg)
{
case 0x201:
//left button down
break;
case 0x202:
clickedHappened(); //left button up, ie. a click
break;
case 0x203:
//left button double click
break;
}
base.WndProc(ref m);
}
The thing is, windows forms in C# already handles all of these for you and from the WndProc, fires events there is no real need to handle WndProc yourself for this type of thing.
For a full list of mouse notification messages, see MSDN: Mouse Input Notifications and for a list of all wndproc messages, see MSDN System Defined Messages
Probably, you can handle WM_LBUTTONUP message that occured after click.
You can do it like this:
const int WM_LBUTTONUP = 0x202;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_LBUTTONUP)
{
clickedHappened();
}
base.WndProc(ref m);
}

Capturing a Click on a NativeWindow

I have a class based on the NativeWindow class and I want to be able to perform some action when the user clicks inside of it. Here is what I tried:
Code removed
However it doesn't work. Debugging suggests for some reason the message is never 0x0201 which is supposedly a left mouse button click. What's wrong with it?
I'm not sure tooltips can receive a WM_LBUTTONDOWN. You could try using the TTM_RELAYEVENT message that's meant for passing a mouse message to a tooltip control for processing, something like this:
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int TTM_RELAYEVENT = 0x407;
if (m.Msg == TTM_RELAYEVENT)
{
Message relayed = (Message)Marshal.PtrToStructure(m.LParam, typeof(Message));
if (related.Msg == WM_LBUTTONDOWN)
{
// Do something
}
}
base.WndProc(ref m);
}

How to move WinForm window without border but with a panel covering the whole area

I saw the code posted on this forum for moving the WinForm without borders but my dialog (C#) has a panel covering the whole area. I know I have to use WndProc to do this. I don't know what to do at this point. My window doesn't move unless I expose some of it by shrinking the size of the panel. Thank you.
The code I have:
protected override void WndPro(ref Message m)
{
switch(m.Msg)
{
case 0x84:m.Result = new intPtr(0x2);
return
}
base.wndProc(ref m);
}
You'll need to give the panel the same kind of treatment, except that you return HTTRANSPARENT. That makes it transparent to hit tests and the form will get the message. Now it works. Add a class to your project and paste the code shown below. Compile. Replace your existing panel with this one.
using System;
using System.Windows.Forms;
class BackPanel : Panel {
protected override void WndProc(ref Message m) {
if (m.Msg == 0x84) m.Result = (IntPtr)(-1);
else base.WndProc(ref m);
}
}

How to handle Form caption right click

I'd like a context menu on the caption bar right click
any tips/samples pref in c# ?
UPDATE - for various reasons, right click on the form won't work because the form is not empty and the form is composited dynamically so....
You can do this by trapping the WM_NCRBUTTONDOWN notification that Windows sends when the user right-clicks the title bar. The control class does not have an event for it, you'll need to override WndProc(). Here's an example form, you'll need to add a ContextMenuStrip:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected void OnTitlebarClick(Point pos) {
contextMenuStrip1.Show(pos);
}
protected override void WndProc(ref Message m) {
const int WM_NCRBUTTONDOWN = 0xa4;
if (m.Msg == WM_NCRBUTTONDOWN) {
var pos = new Point(m.LParam.ToInt32());
OnTitlebarClick(pos);
return;
}
base.WndProc(ref m);
}
}
MSDN explains how to handle right-clicks on Windows Forms controls. Controls, including Forms, inherit the MouseClick event.
MouseEventArgs will tell you what button was clicked through the Button property. Have a look at the MouseButtons Enumeration.
if you handle the form mouse-click, you can then use the following code:
private void Dialog_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.Text = "new caption text";
}
}
But you'll have to make sure that you generate this event for the top-level control on a form. For instance if you have a group box on the form, it will receive the mouse-click events rather than the form itself, for the areas of the form that are under the group box.
There is already a menu managed by Windows when you right-click the titlebar.
Do you want to replace it completely?
If you want to add to it you will have to use the Win32 API and interop and you will have to subclass the form.
See the AppendMenu() function.
Basically you need to use p-invoke to do this. There is a really great example at Here
You can see from the example you will need to manually mimic the event handlers, but this is pretty straight forward.
You can override WndProc of the form and capture the WM_NCRBUTTONDOWN message:
protected override void WndProc(ref Message m)
{
const int WM_NCRBUTTONDOWN = 0xA4;
if (m.Msg == WM_NCRBUTTONDOWN)
{
MessageBox.Show("Caption right clicked!");
}
else
{
base.WndProc(ref m);
}
}
This code will suppress the window's context menu, however. You may not wish this. The WM_NCRBUTTONDOWN message will also be sent if you right click the window borders as well. You may not desire this either.

Categories