5

我在 WinForms 应用程序中遇到以下问题。我正在尝试实现热键,并且无论何时控件处于活动状态,无论焦点是否位于该控件内的文本框等上,我都需要处理键消息。

覆盖 ProcessCmdKey 可以很好地解决这个问题,并且完全符合我的要求,但有一个例外:

如果用户按下一个键并保持按下状态,ProcessCmdKey 会不断触发 WM_KEYDOWN 事件。

但是,我想要实现的是用户必须在触发另一个热键操作之前再次释放按钮(因此,如果有人坐在键盘上,它不会导致连续的热键事件)。
但是,我找不到在哪里捕获 WM_KEYUP 事件,所以如果它应该再次处理 ProcessCmdKey 消息,我可以设置一个标志?

任何人都可以在这里帮忙吗?

谢谢,

汤姆

4

2 回答 2

9

我认为这很容易,只需查看密钥的重复次数即可。如果使用修饰符,则不起作用。您还需要看到密钥上升,这需要实现 IMessageFilter。这有效:

public partial class Form1 : Form, IMessageFilter {
    public Form1()  {
        InitializeComponent();
        Application.AddMessageFilter(this);
        this.FormClosed += (s, e) => Application.RemoveMessageFilter(this);
    }
    bool mRepeating;
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
        if (keyData == (Keys.Control | Keys.F) && !mRepeating) {
            mRepeating = true;
            Console.WriteLine("What the Ctrl+F?");
            return true;
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }
    public bool PreFilterMessage(ref Message m) {
        if (m.Msg == 0x101) mRepeating = false;
        return false;
    }
}
于 2010-03-12T19:20:10.037 回答
3
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;

protected override bool ProcessKeyPreview(ref Message m)
{
    if (m.Msg == WM_KEYDOWN && (Keys)m.WParam == Keys.NumPad6)
    {
        //Do something
    }
    else if (m.Msg == WM_KEYUP && (Keys)m.WParam == Keys.NumPad6)
    {
        //Do something
    }

    return base.ProcessKeyPreview(ref m);
}
于 2011-05-18T19:52:34.820 回答