【问题标题】:WinForms - Capturing the combination of key presses using ProcessCmdKey VS KeyDownWinForms - 使用 ProcessCmdKey VS KeyDown 捕获按键组合
【发布时间】:2021-09-04 15:20:36
【问题描述】:

我的目标是实现自定义 Control + S 按键处理程序,以连接到 winforms 应用程序中的自定义保存方法。

根据我的研发,有几种方法可以做到这一点。首先,我尝试了明显的 KeyPress 事件处理程序。这还不够强大,无法捕获我需要的按键(它没有在编辑器级别调用,而这正是我所需要的)。

第二个看起来更好的选项是受保护的覆盖 bool ProcessCmdKey(ref Message msg, Keys keyData) 覆盖。这有效 - 它拦截了 CTRL 键单击,但显然我需要编写额外的代码来坚持按下 CTRL 键的事实并拦截下一个按键(在我的情况下是 S),然后执行自定义操作。

 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if (keyData == (Keys.S | Keys.Control))
        {
            // This is never called
        }
        else if (keyData == (Keys.Menu | Keys.Alt))
        {
           // this is called each time I hit CTRL
        }
        return true;
    }

ProcessCmdKey 似乎在我按下 CTRL 键后立即被调用。

这篇文章建议创建一个 KeyTracker 类,该类将持续按下的键并执行它需要执行的操作:

Capture Key Sequence via ProcessCmdKey

这似乎是一个不错的选择,但在我深入研究实现一个纪念品跟踪模式之前,是否有人对如何完成这个看似常见的功能提出意见?

另一种模式使用 GetKeyboardState API 函数:

Capture multiple key downs in C#

这看起来很有趣,但我不确定它是否适合我的需求。

[DllImport ("user32.dll")]

public static extern int GetKeyboardState(byte[] keystate);

private void Form1_KeyDown( object sender, KeyEventArgs e )
{
  byte[] keys = new byte[255];

  GetKeyboardState (keys);

  if( keys[(int)Keys.Up] == 129 && keys[(int)Keys.Right] == 129 )
  {
      Console.WriteLine ("Up Arrow key and Right Arrow key down.");
  }
}

感谢您查看我的问题。

更新

我已向我的 DataPanel 添加了三个用于密钥处理的事件。当我在事件中设置断点时,VS 不会拾取这些事件,所以这让我相信 ProcessCmdKey 是我的最佳选择。

如果我能让这些事件发挥作用,那也很好:

        // Ctrl + S: Save Support
        this.ParentForm.KeyPreview = true;
        this.KeyPress             += new KeyPressEventHandler(DataPanel_KeyPress);
        this.KeyDown              += new KeyEventHandler(DataPanel_KeyDown);
        this.PreviewKeyDown       += new PreviewKeyDownEventHandler(DataPanel_PreviewKeyDown);

按下任何键时似乎都没有捕捉到这些事件:

void DataPanel_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        if (e.KeyCode == (Keys.S | Keys.Control))
        {
            SessionManager.Trace.AddTrace("You Hit Save!!");
        }
    }

    void DataPanel_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == (Keys.S | Keys.Control))
        {
            SessionManager.Trace.AddTrace("You Hit Save!!");
        }
    }

    void DataPanel_KeyPress(object sender, KeyPressEventArgs e)
    {
        var key = e.KeyChar;
    }

更新

我通过使用一个简单的 KeyUp 事件和 KeyPreview 标志解决了这个问题:

 void ShipmentDataPanel_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.S)
        {
            MessageBox.Show("Control + S Key Hit!");
        }
    }

谢谢。

【问题讨论】:

标签: winforms keyboard


【解决方案1】:

将表单的KeyPreview 属性设置为true。此属性的摘要说:“获取或设置一个值,该值指示在将事件传递给具有焦点的控件之前表单是否将接收键事件。”。然后使用KeyUp 事件。除非KeyPressed,否则它还会提供有关特殊键(如控制键)的信息。

【讨论】:

  • 谢谢 - 我现在就试试。您是否知道 KeyPreview 是否可以与 ProcessCmdKey() 覆盖一起使用?
  • 顺便说一句,我正在处理 DataPanel 级别,所以我假设我会将 KeyPreview 属性添加到我的 ParentForm?示例:this.ParentForm.KeyPreview = true;
  • 我已为我的问题添加了更新。我添加了您建议的 KeyPress 事件,但我的 DataPanel 似乎不想订阅它们。 KeyPreview 似乎也不会影响 ProcessCmdKey 事件(它仍然会在 CTRL 键按下时启动)。
  • 感谢您的帮助 Olivier - 您帮助我解决了我的问题。
【解决方案2】:

我通过这样做解决了这个问题,

if(e.KeyData==(Keys.S | Keys.Control))

【讨论】:

  • 但不在 ProcessCmdKey 事件中。
  • 这在 ProcessCmdKey 事件中也很完美,谢谢
【解决方案3】:

虽然这是一个非常古老的问题,但我仍然想添加我的答案。
OP 写道他不能使用ProcessCmdKey,因为它会在他按下Control 键时立即触发,并且不会等到他也按下S 键。
我没有这个问题,我下面的代码运行良好,只有在我第一次点击Ctrl 然后S 时才会调用 Delete() 方法

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    bool bHandled = false;
    // switch case is the easy way, a hash or map would be better, but more work to get set up.
    switch (keyData)
    {
        case Keys.F5:
            RefreshList("", "", false); // call my refresh method
            bHandled = true;
            break;
        case Keys.S | Keys.Control: // call my delete method
            Delete(false);
            bHandled = true;
            break;
        default:
            base.ProcessCmdKey(ref msg, keyData);
            break;
    }
    return bHandled;
}

protected virtual void Delete(bool handled)
{
    if (handled == false)
    {
        MessageBox.Show("delete");
    }
}


【讨论】:

    猜你喜欢
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    相关资源
    最近更新 更多