[这个问题是关于WinAPI编程的核心]
在.NET术语中:
当WinForms中的Keydown事件触发时,您可以设置KeyEventArgs.SuppressKeypress = true
,然后不会将后续的Keypress / Character发送给控件。
我找到了以下SO答案,详细说明了Control如何做到: Using SuppressKeyPress event to block a KeyUp event
但现在我不明白,这怎么能正常工作?如果程序在其队列中构建了几个keydown消息会发生什么,并且您通过的前几个消息,但是使用上述方法抑制的最后一个消息,将不会RemovePendingMessages
函数删除队列中的所有字符,而不仅仅是最后一个字符?
在Windows API术语中:
考虑一个典型的消息循环,它调用TranslateMessage
从键盘输入中获取WM_CHAR
消息。在WM_KEYDOWN
检查密钥是否被识别为命令,在这种情况下它不应生成字符。如何去除可能发布到消息队列的WM_CHAR
消息以有效抑制按键? .NET中的现有解决方案似乎使用循环PeekMessage(.., WM_CHAR, WM_CHAR, PM_REMOVE)
来删除队列中的所有字符,但如果队列中有多个keydown消息,则不会删除太多字符?
答案 0 :(得分:3)
你的直觉是正确的,事实上它确实是你描述的行为不端。一些代码可以看到这个错误:
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);
}
}
}
单击表单以触发测试。请注意OnKeyDown如何仅抑制第3次击键。但只有前2个才能完成,其余的则被吞噬。
我从来没有真正看到有人抱怨过这个。