I have a textview and when something is pasted into it from the clipboard I need to intercept that text and do some preprocessing on it before it ends up in the textview.
I've tried listening to the "PasteClipboard" event which doesn't give me a way to modify the incoming text. and the "textview.Buffer.Changed" event which fires after the pasted text makes it into the textview.
Thanks in advance.
AFAIK your best option is to postprocess the text after it's been inserted - the InsertText event on the TextBuffer has arguments that tell you the position and size of the inserted text, so you can remove, process and re-insert it. You would of course want to avoid catching 1-char insertions (keystrokes) and your own re-insertions, but that's trivial.
The only other option I can think of is to re-implement paste support, by catching the paste key command, middle-click, etc. - but note that the command keys can be overridden in users' gtkrc files, so implementing this correctly could get hairy.
It might also be worth asking in the #gtk+ IRC channel on irc.gnome.org.
Doing some short googling, I found the following documentation on Gtk.TextBuffer and GTK alternative to .net WndProc in Mono. It appears that you might want to add the [GLib.ConnectBefore] attribute to your code to access GTK's WndProc method. Beaner's code above would probably work with slight modification for the GTK framework.
This may not be a help to you, but I am catching the WM_PASTE message in a custom control that implements TextBox. I get the GetText from the clipboard into a string variable and if it matches what I am looking for I make my changes to the variable and set the .Text to my variable and swallow the event so the textbox neer gets it. If it is not what I am looking for, but is allowed I just pass the event on with base.WndProc(ref m).
Sample:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE)
{
string clipboardVin = Clipboard.GetText();
string newVin = "";
if (SelectionLength > 0)
{
newVin = Text.Replace(SelectedText, "");
}
else
{
newVin = Text;
}
newVin = newVin.Insert(SelectionStart, clipboardVin);
if (!vinRegEx.IsMatch(newVin))
{
m.Result = new IntPtr(Convert.ToInt32(true));
MessageBox.Show("The resulting text is not a valid VIN.", "Can Not Paste", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
base.WndProc(ref m);
}
}
else
{
base.WndProc(ref m);
}
}
Related
I want my program instead of selecting the whole sentence for a return, that a part of sentence is also possible if a copied that.
here's my code:
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
//check if current operation is a clipboard
if (m.Msg == WM_DRAWCLIPBOARD)
{
//then we use a try catch block so if
//anything wrong happens in Clipboard.GetText() our program wont crash
try
{
//with foreach we go through all our questions
foreach (string question in questionList)
{
//and we check if clapboarded text is matches with our question
if (Clipboard.GetText() == "When a computer is being assembled, which action can be taken to help eliminate cable clutter within a computer case?")
{
notifyIcon1.Icon = SystemIcons.Exclamation;
notifyIcon1.BalloonTipTitle = "When a computer is being assembled, which action can be taken to help eliminate cable clutter within a computer case?";
notifyIcon1.BalloonTipText = "Install a modular power supply.*";
notifyIcon2.BalloonTipIcon = ToolTipIcon.Error;
notifyIcon1.ShowBalloonTip(100);
return;
}
this is the question: "When a computer is being assembled, which action can be taken to help eliminate cable clutter within a computer case?"
i want for example if you copied this: When a computer is being assembled, which
You get the same match and the same notification
Thanks in advance
Use string method .Contains() instead of equality comparison.
if (Clipboard.GetText().Contains(yourString))
My goal is to disable all DoubleClick() events in my application. Just simply unsubscribing from those events is not possbile, because those are external custom controls. So I am aiming for disabling either the DoubleClick() for those controls or my whole application, it doesn't really matter.
What I am trying to do is to intervene once the window gets a WindowsMessage WM and the ID number Message.Msg is the code of e.g. a Button.Click() event.
private const int WM_COMMAND = // ???
if (m.Msg == WM_COMMAND)
...
But no matter which WindowsMessage notification code I use, I don't get the correct one which gets fired once a control gets clicked. But I was abel to intervene on a DoubeClick() on the Form.
private const int WM_NCLBUTTONDBLCLK = 0x00A3;
private const int WM_LBUTTONDBLCLK = 0x0203;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCLBUTTONDBLCLK || m.Msg == WM_LBUTTONDBLCLK)
{
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);
}
This works totally fine and disabels a DoubleClick on the client area and non client area of the Form. But in which area do I locate when I am hovering a control? Because those WindowsMessages referred to either the client area and non client area dont' get fired when I am on a control.
Sent when the user clicks a button.
The parent window of the button receives this notification code through the WM_COMMAND message.
MSDN doc about a button click notifaction message
The WM_COMMAND message has this notfication code:
private const int WM_COMMAND = 0x0111;
So when I try to react to this message being sent I can't, because this message doesn't get fired.
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COMMAND)
MessageBox.Show("foo"); // nothing happens
base.WndProc(ref m);
}
What do I miss or missunderstand about this WindowsMessage?
Since no one posted an answer yet and I found a well working solution here is my attempt to disable all DoubleClick()s or just for one/a few desired Control/s.
The problem is that WndProc() doesn't filter or respond to all WMs that are being sent. Therefore the WM for a default doubleClick on the non client area 0x0203 can't get detected. So I went deeper to already filter the WMs before they reach WndProc(). One way is to use a MessageFilter that is being assigned to my Application.
private MessageFilter msgFilter = new MessageFilter();
Application.AddMessageFilter(msgFilter);
The method Param is an object of my own class MessageFilter, which needs to implement the IMessageFilter Interface in order to use it's PreFilterMessage(). This method gets invoked for each single WM that gets send to your application.
class MessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x0203)
{
m.Result = IntPtr.Zero;
return true;
}
else
return false;
}
}
So basically once there is a WM with the desired Message.Msg ID, I set the Result to zero so the DoubleClick() is completely disabled for the whole application.
Later on it turned out it would be better to disable the DoubleClick() only from one Control. Since every Control in Windows has a unique Handle HWnd, which is part of the Message, I can use it to scan if the certain Message aims to my specific single Control.
When you create your Control either subscribe in the .Designer.cs to the event:
this.yourControl.HandleCreated += new System.EventHandler(this.yourControl_HandleCreated);
Or if it's a custom Control subscribe to the event after it's creation. In the event you assign the value of the created Handle to any instance your MessageFilter has access to, like a Property in this class.
private void yourControl_HandleCreated(object sender, EventArgs e)
{
msgFilter.OwnHandle = yourControl.Handle;
}
After that simply add a second condition to the if statement:
if (m.Msg == 0x0203 && OwnHandle == m.HWnd)
...
In Main Form i have Short Cut Keys(ctrl + S ) for saving the data in DataBase. For combobox (ctrl + Alphabets) is the default Operation. How can I disable shortcut keys for Combobox?
UPDATE:
On keyPress event we can Do this
if (ModifierKeys == Keys.Control)
{
e.Handled = true;
}
You can try overriding ProcessCmdKey method of the Main Form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
const int WM_KEYDOWN = 0x100;
if (keyData == (Keys.Control | Keys.S)) {
if (msg.Msg == WM_KEYDOWN)
MySaveDataToDatabase(); // <- Do your save command
return true; // <- Stop processing the WM_KeyDown message for Ctrl + S (and shortcut as well)
}
// All other key messages process as usual
return base.ProcessCmdKey(ref msg, keyData);
}
I get the feeling that your problem is actually that the combobox is getting keypresses before your form. Be sure to set the Form's KeyPreview property to true if you want to handle keypresses before your controls.
More information about the KeyPreview property:
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview(v=vs.100).aspx
If you are getting issues like overriding the F4 key (which in a combobox shows all options available by default), note the bit about setting the KeyPressEventArgs.Handled property in the form's KeyPress event handler to true.
For most hot keys you can override the PreviewKeyDown event specify what to allow or not, eg:
void comboBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
var keysToIgnore = new []{
Keys.S,
Keys.X,
Keys.F4,
Keys.Space,
}.ToList();
if (keysToIgnore.Contains(e.KeyCode)) {
if(e.Modifiers == Keys.Alt) ; // Do stuff (or don't) here
}
}
There's all sorts of ways you can structure your logic depending on what your actual use case is but hopefully you get the idea.
You might find some hot key combinations aren't possible to disable this way, in which case you'll need to use the Win32API: UnregisterHotKey. More info here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646327%28v=vs.85%29.aspx
The main advantage of using the PreviewKeyDown event is you can also easily replace behaviour instead of just disabling it. The main advantage of using UnregisterHotKey is it operates at a lower level and is a far more robust and reliable way of disabling hot keys.
EDIT:
If you need to get a contiguous range of values you can try something like:
int keyCode = (int) (e.KeyCode);
if(keyCode >= (int)(Keys.A) && keyCode <= (int)(Keys.Z)) { /* do stuff */ }
but again, an ideal solution really depends on the specifics of your use case. There's no generic 'right answer'.
Why does this never get called ?
propertyGrid.KeyDown += new KeyEventHandler(propertyGrid_KeyDown);
private void propertyGrid_KeyDown(object sender, KeyEventArgs e)
{
PoorLittleMethod(); //Never gets called
}
This seems to be the same for Mouse event
I'veread on some forums that PGrid is tricky on raising such events as it Inherits them from Control but does not really Raise them. is that true ? If yes, how to bypass that ?
EDIT 1:
As this seems to be "regular", I find it very light from MS not to specify this explicitely on the MSDN Reference of the propertyGrid class and leave events "as is" as if they were usable, whereas they are not. Tricky things like these are at least usually specified in "notes" inside the refs.
EDIT 2:
I am presently coding a workaround. I'll be posting it soon.
The PropertyGrid's KeyDown property is marked as Browsable(false) - presumably the conclusion we can take from this is that it is not supported in an of itself but is in fact present as a side-effect of its inheritance hierarchy.
Though, interestingly enough, its EditorBrowsable attribute (which is also a designer indicator, for Intellisense and the suchlike) is set as EditorBrowsableState.Advanced - where we would expect EditorBrowsableState.Never should the former presumption be true.
Some information from MSDN forums outlines the why of this situation:
From the tool UI Spy we can see the PropertyGrid is a just a panel and it consists of three Windows Controls. Our KeyDown event should be processed by the child control table.
The structure:
-"pane" "PropertyGrid"
--"pane" "Description Pane"
--"table" "Properties Window"
--"tool bar" "ToolBar"
The suggested solution (also provided in the MSDN link) to overcoming this is to use native system calls to retrieve window/control information, subclass NativeWindow and override the WndProc method to handle the events you like, KeyDown in this case.
You can override this from subclass of PropertyGrid to get some key info from windows message
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
CSharp PropertyGrid Events
// Property grid events can’t be easily subscribed to however there is way to get at the KeyUp event without impacting operation.
// Note: The KeyDown event can be subscribed to in the same manner but the propertygrid is NOT updated with the key presses.
// This code is added in hope it may help someone else solve the problem. It is not offered as a total solution.
// First define a class variable to indicate that events have been added.
private bool m_bPropertyGridEventsAdded = false;
public GlassInfoEntryPage(ViewBase view)
: base(view)
{
InitializeComponent();
// Subscribe to SelectedGridItemChanged
m_PropertyGrid.SelectedGridItemChanged += M_PropertyGrid_SelectedGridItemChanged;
}
// Now define a SelectedGridItemChanged Event Handler
private void M_PropertyGrid_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
{
int nXlocation;
int nYlocation;
PropertyGrid oPropertyGrid;
Control oControl;
if (m_bPropertyGridEventsAdded == false)
{
oPropertyGrid = (PropertyGrid)sender;
// Search the Property Grid for a PropertyGridView Control so events can be added to it
for (nXlocation = 0; nXlocation < oPropertyGrid.Width; nXlocation += 10)
{
for (nYlocation = 0; nYlocation < oPropertyGrid.Height; nYlocation += 10)
{
oControl = m_glassInfoPropertyGrid.GetChildAtPoint(new Point(nXlocation, nYlocation));
if (oControl != null)
{
if (oControl.GetType().ToString() == "System.Windows.Forms.PropertyGridInternal.PropertyGridView")
{
// Add Events here
oControl.Controls[1].KeyUp += MyCode_KeyUp;
m_bPropertyGridEventsAdded = true;
break;
}
}
}
if (m_bPropertyGridEventsAdded == true)
{
break;
}
}
}
}
// Handle the events
private void MyCode_KeyUp(object sender, KeyEventArgs e)
{
}
How can I get a specific message on a specific method?
I've seen some examples and people use "ref" ,but I dont understand it.
In delphi,for example,my function(method) must be declared in the Main Form class and next to the declaration I have to put the message
type
TForm1 = class(TForm)
...
protected
procedure MessageHandler(var Msg:Tmessage);Message WM_WINSOCK_ASYNC_MSG;
end;
I need this in C# so I can use WSAAsyncSelect in my application
Check >my other Question< with bounty 550 reputation to understand what I mean
You can override the WndProc method on a control (e.g. form).
WndProc takes a reference to a message object. A ref parameter in C# is akin to a var parameter in Delphi. The message object has a Msg property that contains the message type, e.g (from MSDN):
protected override void WndProc(ref Message m)
{
// Listen for operating system messages.
switch (m.Msg)
{
// The WM_ACTIVATEAPP message occurs when the application
// becomes the active application or becomes inactive.
case WM_ACTIVATEAPP:
// The WParam value identifies what is occurring.
appActive = (((int)m.WParam != 0));
// Invalidate to get new text painted.
this.Invalidate();
break;
}
base.WndProc(ref m);
}
In .NET winforms, all messages go to WndProc, so you can override that:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_WINSOCK_ASYNC_MSG)
{
// invoke your method
}
else
{
base.WndProc(ref m);
}
}
If I have misunderstood, please say - but I think you would do well to avoid this low-level approach, and describe what you want to achieve - i.e. it might be that .Invoke/.BeginInvoke are more appropriate.