使用 ProcessCmdKey 按住箭头键按下事件

ita*_*i42 2 c# keyboard events key

只要按住箭头键,我就需要执行某种方法。现在,对于 Visual Studio 2012 中的常规箭头键按下,使用OnKeyDown不起作用,因此我需要使用ProcessCmdKey,这就像一个魅力。有没有一种方法可以用来ProcessCmdKey检测箭头何时被释放/被按住?


我采纳了马库斯和汉斯的建议,并将这两种想法结合起来。我使用了该ProcessKeyPreview方法,但仍然遇到一些问题。当我按住任何箭头键时,此方法不会检测到WM_KEYDOWN发生了这种情况......但是一旦我将手指从按键上松开,它实际上就会注意到WM_KEYUP发生了这种情况。

有趣的是,当我按住任何其他键(即字母“S”)时,它会正确识别何时按下并释放。我在下面发布了我的代码片段:

const int WM_KEYUP = 0x0101;
const int WM_KEYDOWN = 0x0100;

    protected override bool ProcessKeyPreview(ref Message m)
            {
                int msgVal = m.WParam.ToInt32();            
                if (m.Msg == WM_KEYDOWN)
                {
                    switch ((Keys)msgVal) {
                        case Keys.Down:
                            Console.WriteLine("down pressed"); //not detected
                            break;
                        case Keys.S:
                            Console.WriteLine("S pressed!"); //detected
                            break;
                    }
                }
                if (m.Msg == WM_KEYUP)
                {
                    switch ((Keys)msgVal)
                    {
                        case Keys.Down:
                            Console.WriteLine("down released"); //detected
                            break;
                        case Keys.S:
                            Console.WriteLine("s released!"); //detected
                            break;
                    }
                }
                return base.ProcessKeyPreview(ref m);
            }        
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 5

您无法使用 ProcessCmdKey() 查看 KeyUp 事件,它只能处理 KeyDown 事件。如果表单包含控件,您将需要在低得多的级别上解决这个问题。诀窍是在 Winforms 通过正常的键处理和 WndProc 链发送消息之前拦截该消息。这需要实现 IMessageFilter 接口。像这样:

public partial class Form1 : Form, IMessageFilter {  // NOTE: added IMessageFilter
    public Form1() {
        InitializeComponent();
        Application.AddMessageFilter(this);
    }
    protected override void OnFormClosed(FormClosedEventArgs e) {
        Application.RemoveMessageFilter(this);
        base.OnFormClosed(e);
    }

    bool IMessageFilter.PreFilterMessage(ref Message m) {
        // Trap WM_KEYUP/DOWN for Keys.Down key
        if ((m.Msg == 0x100 || m.Msg == 0x101) && (Keys)m.WParam.ToInt32() == Keys.Down) {
            bool repeat = (m.LParam.ToInt32() & (1 << 30)) != 0;
            bool down = m.Msg == 0x100;
            // But only for this form
            Form form = null;
            var ctl = Control.FromHandle(m.HWnd);
            if (ctl != null) form = ctl.FindForm();
            if (form == this) {
                OnCursorDown(down, repeat & down);
                return true;
            }
        }
        return false;
    }
    private void OnCursorDown(bool pressed, bool repeat) {
        // etc..
    }
}
Run Code Online (Sandbox Code Playgroud)