Pasting into multiple text boxes - c#

I have a .net application which includes search screen which has a panel with has three text boxes, each with a varying character lengths.
What I'd like to do is capture when the paste command when invoked from the first box and paste my clipboard into the three boxes.
This functionality is similar to many modern applications accepting input for serial keys and phone numbers.

As far as I can find there is no other sensible way of doing this than to capture the WM_PASTE event.
Derive a class from TexBox and implement this method:
using System.Windows.Forms;
using System.ComponentModel;
class TextBoxWithOnPaste : TextBox
{
public delegate void PastedEventHandler();
[Category("Action")]
[Description("Fires when text from the clipboard is pasted.")]
public event PastedEventHandler OnPaste;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x302 && OnPaste != null) // process WM_PASTE only if the event has been subscribed to
{
OnPaste();
}
else
{
base.WndProc(ref m);
}
}
}
Then put three of those custom controls on your form, and assign the OnPaste event on all three textboxes to the same method, in this case I called it textPasted():
private void textPasted()
{
String input = Clipboard.GetText();
int l1 = textBoxWithOnPaste1.MaxLength;
int l2 = textBoxWithOnPaste2.MaxLength;
int l3 = textBoxWithOnPaste3.MaxLength;
try
{
textBoxWithOnPaste1.Text = input.Substring(0, l1);
textBoxWithOnPaste2.Text = input.Substring(l1, l2);
textBoxWithOnPaste3.Text = input.Substring(l2, l3);
}
catch (Exception)
{ }
}
Since you implied "like a serial", I guessed you want the pasted string to be split among the textboxes. The code above is not perfect for that (try pasting a single space into the third text box after entering data manually in all three, so it would be nice if you knew in which textbox the text was pasted, for example by altering the event's parameters and that way sending the sender with it), but it basically works and I guess you can figure out the rest (you could use the Tag property to identify the textbox).

Capture the paste event:
protected override void WndProc(ref Message m) {
// Did paste occur?
if (m.Msg == 0x302) {
//Paste occurred, add your logic here
}
base.WndProc(ref m);
}
Then, access the Clipboard object to get the desired text.

you can get the captured text
String txt = Clipboard.GetText();
and place it in the "Text" property of the other textbox

You can bind key down event, and when you get Ctrl + V or Ctrl + v, you update the value of the three textbox with value in the clipboad. You can do this on TextChanged event off first text box.

You could increase the character limit of the boxes and register for TextChanged and if the pasted (or typed) text is longer jump/cut to the next TextBox.

Related

How to paste a serial key automatically [duplicate]

I have a .net application which includes search screen which has a panel with has three text boxes, each with a varying character lengths.
What I'd like to do is capture when the paste command when invoked from the first box and paste my clipboard into the three boxes.
This functionality is similar to many modern applications accepting input for serial keys and phone numbers.
As far as I can find there is no other sensible way of doing this than to capture the WM_PASTE event.
Derive a class from TexBox and implement this method:
using System.Windows.Forms;
using System.ComponentModel;
class TextBoxWithOnPaste : TextBox
{
public delegate void PastedEventHandler();
[Category("Action")]
[Description("Fires when text from the clipboard is pasted.")]
public event PastedEventHandler OnPaste;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x302 && OnPaste != null) // process WM_PASTE only if the event has been subscribed to
{
OnPaste();
}
else
{
base.WndProc(ref m);
}
}
}
Then put three of those custom controls on your form, and assign the OnPaste event on all three textboxes to the same method, in this case I called it textPasted():
private void textPasted()
{
String input = Clipboard.GetText();
int l1 = textBoxWithOnPaste1.MaxLength;
int l2 = textBoxWithOnPaste2.MaxLength;
int l3 = textBoxWithOnPaste3.MaxLength;
try
{
textBoxWithOnPaste1.Text = input.Substring(0, l1);
textBoxWithOnPaste2.Text = input.Substring(l1, l2);
textBoxWithOnPaste3.Text = input.Substring(l2, l3);
}
catch (Exception)
{ }
}
Since you implied "like a serial", I guessed you want the pasted string to be split among the textboxes. The code above is not perfect for that (try pasting a single space into the third text box after entering data manually in all three, so it would be nice if you knew in which textbox the text was pasted, for example by altering the event's parameters and that way sending the sender with it), but it basically works and I guess you can figure out the rest (you could use the Tag property to identify the textbox).
Capture the paste event:
protected override void WndProc(ref Message m) {
// Did paste occur?
if (m.Msg == 0x302) {
//Paste occurred, add your logic here
}
base.WndProc(ref m);
}
Then, access the Clipboard object to get the desired text.
you can get the captured text
String txt = Clipboard.GetText();
and place it in the "Text" property of the other textbox
You can bind key down event, and when you get Ctrl + V or Ctrl + v, you update the value of the three textbox with value in the clipboad. You can do this on TextChanged event off first text box.
You could increase the character limit of the boxes and register for TextChanged and if the pasted (or typed) text is longer jump/cut to the next TextBox.

Make only 1 instance of a character allowed to be entered C#

I would like to allow only one instance of a character to appear in sequence in a textbox. In other words, I would like to prevent the user from entering sequential duplicate characters in my textbox. For example, if I were to make a calculator program, I would like to prevent the user from entering (( by accident instead of (.
You can detect the textbox's keydown event. And in the event, you check the last and second last character to see if it's the same. If it's the same, you can just remove the last character of the string.
But keep in mind that the above method has problem when your user pastes the entire string to the textbox.
The function will look the same for any textbox-like object, but of course the event to attach to will differ. Assuming Winforms TextBox, you will attach to the TextChanged event (i.e. mytextbox.TextChanged = mytextbox_TextChanged), and the function will look similar to the one below:
private void mytextbox_TextChanged(object sender, EventArgs e)
{
if (mytextbox.Text.Length < 2) { return; }
var stringToCheck = mytextbox.Text;
for (var i = 1; i <= stringToCheck.Length-1; i += 1)
{
if (stringToCheck[i].Equals(stringToCheck[i-1])
{
mytextbox.Text = stringToCheck.Remove(i, 1);
// Next two lines put cursor at end of textbox instead of beginning
mytextbox.SelectionStart = mytextbox.Text.Length;
mytextbox.SelectionLength = 0;
}
}
}

Winforms MaskedTextBox - Reformatting pasted text to match mask

I have a MaskedTextBox control that, in our case, is collecting social insurance (tax) numbers (without a ValidatingType though since the string representation including the mask literals). A social insurance number is 3 groups of 3 digits separated by dashes. Sometimes spaces may be typed or entered instead of the dashes.
The configuration of the textbox is:
Mask: 999-999-999
ValidationType: null / not required
SkipLiterals: true
CutCopyMaskFormat: IncludeLiterals (only relevant when cut/copy FROM textbox)
TextMaskFormat: IncludeLiterals
-- Let me know if there other properties that you think could be important!
Problem
When pasting the following tax number "450 622 097" because of the spaces it doesn't match the mask. So I end up with "450- 62-2 9" in the text box. Pasting "450-622-097" will successfully paste into the box.
I want to be able to intercept the paste event in order to possibly fix it up to replace the spaces with dashes.
Alternatively, could we make the mask accept dashes OR spaces (but always output dashes)?
Non-solutions
MaskInputRejected event - I can't seem to get a handle on what was originally input (i.e. what's being rejected) so as to compare it with what's sitting at the top of the Clipboard. It merely returns how it was rejected
Validating event - Already occurs after the mask has been applied. I.e. the value of "450- 62-2 9" is in the textbox now.
Use custom ValidatingType with static Parse function - Again, occurs after the mask has been applied.
Detecting Key-Down event - Then if key series is Ctrl-V then manually handle and pass in a cleaned up version of the clipboard text. Could work, but then what about paste via the right click context menu?
Any other ideas?
While this is a hammer solution, there are limitations to the mask string and i don't see another way around it. What you need is to capture the paste event and process the text before it gets in the textbox. See below a simplistic example
class MyMaskedTextbox : MaskedTextBox
{
const int WM_PASTE = 0x0302;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_PASTE:
if (Clipboard.ContainsText())
{
string text = Clipboard.GetText();
text = text.Replace(' ', '-');
//put your processing here
Clipboard.SetText(text);
}
break;
}
base.WndProc(ref m);
}
}
As per #anchandra's response and subsequent comments here is the class to enable processing of the text on a per-control basis.
public class MyMaskedTextBox : MaskedTextBox
{
private const int WM_PASTE = 0x0302;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_PASTE:
if (Clipboard.ContainsText())
{
string text = Clipboard.GetText();
var args = OnPasting(text);
if (args.Cancel)
{
// Swallow it up!
return;
}
// If value changed, then change what we'll paste from the top of the clipboard
if (!args.Value.Equals(text, StringComparison.CurrentCulture))
{
Clipboard.SetText(args.Value);
}
}
break;
}
base.WndProc(ref m);
}
public event EventHandler<PastingEventArgs> Pasting;
protected virtual PastingEventArgs OnPasting(string value)
{
var handler = Pasting;
var args = new PastingEventArgs(value);
if (handler != null)
{
handler(this, args);
}
return args;
}
}
public class PastingEventArgs : CancelEventArgs
{
public string Value { get; set; }
public PastingEventArgs(string value)
{
Value = value;
}
}
And simple usage of the Pasting event to strip out spaces as per:
private void sinTextBox_Pasting(object sender, PastingEventArgs e)
{
e.Value = e.Value.Replace(" ", String.Empty);
}

Is it possible to capture any unspecific input event in C#?

I want my application to be able to display certain information when no user input has been detected for some time (like a Welcome/Instruction layer). Is there anyway to have the application register any form of user input (keyboard, mousedown/move etc) without having to write handlers for each of those events?
Is there a generic input window message that gets sent before it is interpreted as being mouse or keyboard or other device? The behaviour I want is similar to Windows waking up from screen saver / sleep on keyboard or mouse input.
I want to avoid something like:
void SomeHandler(object sender, EventArgs e) { WakeUp(); }
...
this.KeyDown += SomeHandler;
this.MouseMove += SomeHandler;
this.SomeInputInteraction += SomeHandler;
The GetLastInputInfo Function is probably what you're looking for. It retrieves the time of the last input event.
I don't know if this works in WPF but this may help:
public class DetectInput : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if ( m.Msg == (int)WindowsMessages.WM_KEYDOWN
|| m.Msg == (int)WindowsMessages.WM_MOUSEDOWN
// add more input types if you want
)
{
// Do your stuff here
}
return false;
}
}
and in Program:
Application.AddMessageFilter(new DetectInput ()); // Must come before Run
Application.Run(YourForm);
Maybe this article on CodeProject will help you. It is about automatically logging off after a period of inactivity using WPF.
Hope this helps.

Capture Keystrokes

I need to capture keystokes from a wedge device and prevent any controls or the form from receiving them. I also need to be able to know the value (char). I have tried overriding the ProcessCmdKey(Keys) and ProcessDialogChar(char) events. In the ProcessCmd event I can suppress the keystroke if it's one I want, but I the character isn't a parameter of the event. In the ProcessDialogChar event the character is there, but I cannot prevent the form or control with the focus from receiving the key. Suggestions?
You'll want to add this during Form load:
Application.AddMessageFilter(this);
Add this constant:
private const int WM_KEYDOWN = 0x100;
And this method:
public bool PreFilterMessage(ref Message m)
{
Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode;
bool retVal = false;
if (m.Msg == WM_KEYDOWN)
{
// Handle the keypress
retVal = true;
}
return retVal;
}
By returning true, your form and control(s) will never see the key press.
It was not how I wanted to do it, but because I needed to fix this and move on I put a hidden textbox on the form and as soon as I see the character that signals the possible start of the string of data I want to capture I set focus to that text box and respond to the TextChanged event. If I haven't seen the ending character before I timer expires I clear the textbox and start again. Kludge, but it works and got me to the next task.

Categories