Reputation: 5477
[This question is at its core about WinAPI programming]
In .NET terms:
When the Keydown event fires in WinForms, you can set the KeyEventArgs.SuppressKeypress = true
and then the subsequent Keypress/Character is not sent to the control.
I found the following SO answer that details how the Control does it: Using SuppressKeyPress event to block a KeyUp event
But now I don't understand, how can this work properly? What happens if the program builds up a couple of keydown messages in its queue, and the first few you let through, but the last you suppress using the method above, wouldn't the RemovePendingMessages
function remove all characters from the queue, rather than just the last one?
In Windows API terms:
Consider a typical message loop that calls TranslateMessage
to get WM_CHAR
messages from keyboard input. On a WM_KEYDOWN
check if the key is recognised as a command, in which case it should not generate a character. How could one go about removing the WM_CHAR
message that was potentially posted to the message queue to effectively suppress the keypress? An existing solution in .NET seems to use a looped PeekMessage(.., WM_CHAR, WM_CHAR, PM_REMOVE)
to remove all characters from the queue, but wouldn't that remove too many characters if multiple keydown-messages are in the queue?
Upvotes: 4
Views: 441
Reputation: 941307
Your intuition is correct, it does in fact misbehave as you describe. Some code to play with to see this going wrong:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
int keycnt = 0;
protected override void OnKeyDown(KeyEventArgs e) {
keycnt++;
if (keycnt == 3) e.SuppressKeyPress = true;
base.OnKeyDown(e);
}
protected override void OnKeyPress(KeyPressEventArgs e) {
Debug.Print("Press {0}", e.KeyChar);
base.OnKeyPress(e);
}
protected override void WndProc(ref Message m) {
if (m.Msg >= 0x100 && m.Msg <= 0x109) Debug.WriteLine(m);
base.WndProc(ref m);
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr PostMessage(IntPtr hwnd, int msg, IntPtr wp, IntPtr lp);
protected override void OnMouseClick(MouseEventArgs e) {
for (int ix = 0; ix < 5; ++ix) {
PostMessage(this.Handle, 0x100, (IntPtr)Keys.A, IntPtr.Zero);
}
}
}
Click the form to trigger the test. Note how OnKeyDown only suppresses the 3rd keystroke. But only the first 2 make it through, the rest are swallowed.
I've never actually seen anybody complain about this.
Upvotes: 3