I want to check clipboard string before paste happens into the TEdit control (using both Ctrl+V and context menu 'Paste'). If clipboard contains a specific string in it, then TEdit control should not paste that string. Clipboard text should remain as is, should not get cleared.
For CTRL-V
you could create an OnKeyPress
event handler to validate the text in the clipboard before it's pasted.
I made a combination of checking one single character against a table of valid characters and also checking the complete paste against invalid strings.
Note: The invalid strings may still be typed in manually since this is checking for invalid strings in the pasted text only. If you need to check so that a user doesn't type in bad strings one character at a time, call valid_string()
in the OnChange
event handler.
#include <Clipbrd.hpp>
#include <algorithm>
#include <vector>
// A function to validate a pasted string against a number of blacklisted strings
bool valid_string(const UnicodeString& InStr) {
static const std::vector<UnicodeString> BadStrings{" ", "--"};
return std::find_if(BadStrings.begin(), BadStrings.end(), [&](const auto& badstr) {
// return true if the current badstr was found
return
std::search(InStr.begin(),
InStr.end(),
badstr.begin(),
badstr.end()) != InStr.end();
}) == BadStrings.end(); // true if a bad string was NOT found
}
// OnKeyPress event handler
void __fastcall TForm1::Edit1KeyPress(TObject *Sender, System::WideChar &Key)
{
TEdit& se = *static_cast<TEdit*>(Sender);
using StrType = decltype(se.Text);
// A lambda to validate a single character:
static const auto validkey = [](auto Ch) {
// example of valid characters:
static const StrType Accepted = "0123456789 -()";
return std::find(Accepted.begin(), Accepted.end(), Ch) != Accepted.end();
};
if(Key >= ' ') { // don't validate control characters
// Single key validation
if(not validkey(Key)) Key = 0;
} else if(Key == 22) { // CTRL-V - check that the whole clipboard buffer is ok
auto& c = *Clipboard();
if(c.HasFormat(CF_UNICODETEXT)) {
// Extract the pasted string
StrType paste = StrType(c.AsText.c_str());
// Use the lambda on all characters
bool all_chars_ok = std::all_of(paste.begin(), paste.end(), validkey);
if(not (all_chars_ok && valid_string(paste))) { // reject the whole paste
Key = 0;
}
}
}
}
Here's an example of doing it all in the OnChange
handler instead. This should catch bad pastes from the context menu as well as if the user types in any illegal combinations (even if it consists of valid characters).
#include <utility>
void __fastcall TForm1::Edit1Change(TObject *Sender)
{
TEdit& se = *static_cast<TEdit*>(Sender);
using StrType = decltype(se.Text);
static StrType old_text;
// A lambda to validate a single character:
static const auto validkey = [](auto Ch) {
// example of valid characters:
static const StrType Accepted = "0123456789 -()";
return std::find(Accepted.begin(), Accepted.end(), Ch) != Accepted.end();
};
// Making an unnecessary copy of the text.
// Using se.Text's iterators directly fails for some reason.
auto txt = se.Text;
// Use the lambda on all characters
bool all_chars_ok = std::all_of(txt.begin(), txt.end(), validkey);
if(all_chars_ok && valid_string(txt)) {
// All is ok, save this text
old_text = std::move(txt);
} else {
// Revert back to the old text
se.Text = old_text;
se.SelStart = old_text.Length();
// se.Undo(); // May be a better idea to use instead.
}
}