简体   繁体   English

使用ProcessCmdKey保持向下箭头按下事件

[英]Hold Arrow Key Down Event with ProcessCmdKey

I need to perform a certain method as long as an arrow key is being held down. 只要按住箭头键,我就需要执行某种方法。 Now, for regular arrow key presses in Visual studio 2012, using OnKeyDown did not work, so I needed to use ProcessCmdKey , which works like a charm. 现在,对于Visual Studio 2012中的常规箭头键按下操作,无法使用OnKeyDown ,因此我需要使用ProcessCmdKey ,它的工作原理像一个ProcessCmdKey按钮。 Is there a way to use ProcessCmdKey to detect when an arrow has been released / being held down? 有没有一种方法可以使用ProcessCmdKey来检测何时释放/按住了箭头?


I've taken both Markus' and Hans' advice, and combined the two ideas. 我接受了马库斯和汉斯的建议,并结合了这两种想法。 I used the ProcessKeyPreview method, but I am still having some issues. 我使用了ProcessKeyPreview方法,但是仍然遇到一些问题。 When I hold down any arrow key, this method will not detect that WM_KEYDOWN has happened... but as soon as I release my finger from the key, it actually DOES notice that WM_KEYUP has happened. 当我按住任意箭头键时,此方法将不会检测到WM_KEYDOWN发生了……但是,只要我松开手指,它实际上就会注意到WM_KEYUP发生了。

The interesting this is that when I hold down any other key (ie letter 'S'), it properly recognizes when it has been pressed and released. 有趣的是,当我按住其他任何键(即字母“ S”)时,它都能正确识别何时按下和释放它。 I've posted a fragment of my code below: 我在下面发布了一段代码:

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);
            }        

You cannot see the KeyUp event with ProcessCmdKey(), it was made to only handle KeyDown events. 您无法通过ProcessCmdKey()看到KeyUp事件,它只能处理KeyDown事件。 You'll need to tackle this at a much lower level if the form contains controls. 如果表单包含控件,则需要在更低的层次上解决此问题。 The trick is to intercept the message before Winforms sends it through the normal key-handling and WndProc chain. 诀窍是在Winforms通过普通的密钥处理和WndProc链发送消息之前拦截消息。 That requires implementing the IMessageFilter interface. 这需要实现IMessageFilter接口。 Like this: 像这样:

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..
    }
}

You can overload ProcessKeyPreview instead, which will let you see the WM_KEYDOWN message as well as the WM_KEYUP message. 您可以重载ProcessKeyPreview,这将使您看到WM_KEYDOWN消息以及WM_KEYUP消息。 Be sure to turn on KeyPreview for the form. 确保为表单打开KeyPreview。

WM_KEYDOWN:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646280(v=vs.85).aspx

WM_KEYUP:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646281(v=vs.85).aspx

Example: 例:

public partial class TestForm : Form
{
    public TestForm()
    {
        InitializeComponent();
        this.KeyPreview = true;
    }

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

    protected override bool ProcessKeyPreview(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_KEYDOWN:
                Console.WriteLine(m.LParam);
                break;

            case WM_KEYUP:
                Console.WriteLine(m.LParam);
                break;
        }
        return base.ProcessKeyPreview(ref m);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM