【问题标题】:how not to allow multiple keystokes received at one key press?如何不允许一次按键收到多个按键?
【发布时间】:2011-01-30 06:02:20
【问题描述】:

当我们按下一个键并持续按下它时,keypress 和 keydown 事件会不断触发。 有没有办法让这些只在一个完整的循环后触发,例如按键然后按键。

我希望用户不能连续按键,而是希望用户必须按下然后释放键盘才能输入字符!

这样就不会发生以下情况,例如:当用户按下 'p' 1 秒时,pppppppppppppppppppppppp。

【问题讨论】:

    标签: c# keyboard keypress


    【解决方案1】:

    您可以通过使用 IMessageFilter 过滤按键消息来在应用程序范围内执行此操作。这是一个例子:

      public partial class Form1 : Form, IMessageFilter {
        public Form1() {
          InitializeComponent();
          Application.AddMessageFilter(this);
          this.FormClosed += (s, e) => Application.RemoveMessageFilter(this);
        }
    
        private Keys mLastKey = Keys.None;
    
        public bool PreFilterMessage(ref Message m) {
          if (m.Msg == 0x100 || m.Msg == 0x104) {
            // Detect WM_KEYDOWN, WM_SYSKEYDOWN
            Keys key = (Keys)m.WParam.ToInt32();
            if (key != Keys.Control && key != Keys.Shift && key != Keys.Alt) {
              if (key == mLastKey) return true;
              mLastKey = key;
            }
          }
          else if (m.Msg == 0x101 || m.Msg == 0x105) {
            // Detect WM_UP, WM_SYSKEYUP
            Keys key = (Keys)m.WParam.ToInt32();
            if (key == mLastKey) mLastKey = Keys.None;
          }
          return false;
        }
      }
    

    我追求的一件事是 WM_KEYDOWN 消息中的重复计数。奇怪的是,这在我的机器上不起作用,它是 1 用于重复键。不知道为什么。

    【讨论】:

    • @nobugz +1 我总是从你的回答中学到很多东西!上面发生了非常有趣的事情,删除了 Form Closed 上的 MessageFilter。我猜您在回答中“深入”以涵盖所有可能的控制输入情况?我认为没有办法在独立于任何表单的应用程序范围内处理此问题?
    • @BillW:谢谢!这是应用程序范围的,IMessageFilter 适用于所有表单。如果它只适用于一种形式,那么这不是正确的解决方案。我认为这是某种游戏应用,所以应该没问题。
    • 当然,我现在可以看到它的应用程序范围,想知道我是怎么错过看到它开始的:)
    • 6 年后......这个问题已经被问过很多次了,这是迄今为止我找到的最好的答案。在我的应用程序中,我需要使用 KeyPress,为了防止第一次重复,我确实需要修改代码以包括捕获 WM_CHAR 消息 (0x102)。所需的更改在两个检测行中:\nif (m.Msg == 0x100 || m.Msg == 0x104 || m.Msg == 0x102) ... 和:\nelse if (m.Msg == 0x101 || m.Msg == 0x105 || m.Msg == 0x102)
    【解决方案2】:

    为了防止按键在按住时多次触发:您必须像这样使用SuppressKeyPress 属性:

    bool isKeyRepeating = false;
    
    public void textBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
    {
        if (isKeyRepeating)
        {
            e.SuppressKeyPress = true;
        }
        else
        {
            isKeyRepeating = true;
        }
    
    }
    
    public void textBox1_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
    {
        isKeyRepeating = false;
    }
    

    请参阅:KeyEventArgs..::.Handled Property ... 和 ... KeyEventArgs..::.SuppressKeyPress Property .... 了解相关信息

    【讨论】:

    • 如果您将表单的 'KeyPreview 设置为 'true,并在表单的 KeyDown 和 KeyUp 处理程序中使用相同的代码(如上):该表单上的所有文本框都将抑制键重复。除了 TextBoxes,我还没有在其他控件上测试过它。 Nobugz(比我更聪明)在下面给出了答案的事实表明,即使在表单级别上,这段代码也不会阻止在我不知道的其他情况下重复键。
    【解决方案3】:

    声明一个布尔值isKeyDown,在KeyDown事件中,将该布尔值设置为true。在KeyUp 事件中,将布尔值设置为false。

    这是示例代码

    bool isKeyDown=false;
    public void control_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
    {
        if(isKeyDown)
          return;
        isKeyDown=true;
        // do what you want to do
    }
    
    public void control1_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
    {
       isKeyDown=false;
       // do you key up event, if any. 
    }
    

    【讨论】:

    • 如海报所述,两个事件都会触发(keyDown 后跟 keyUp),即使它是重复的键
    • @iAn:这不是真的。你得到重复的keydowns,但只有一个keyup。
    • @iAn:MSDN 另有说明:“KeyDown 事件在用户按下任意键时发生。KeyUp 事件在用户释放键时发生。每次按键重复时都会发生重复的 KeyDown 事件,如果按键被按住,但用户松开按键时只产生一个 KeyUp 事件。”
    • @Ngu 不幸的是,您上面的代码,甚至在 KeyEvent 处理程序中设置 e.Handled = true 都不会阻止输入多个字符,只要按住键(在 TextBox 中,对于示例)。
    • @Ngu 只需获取您的代码,将其连接到 WinForm 项目中的 TextBox 的 KeyDown 和 KeyUp 事件,然后运行代码:您会观察到按住键会导致在之后输入多个字符短暂的延迟。您的代码不会阻止多次重复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-27
    • 2023-04-04
    • 1970-01-01
    • 2014-07-02
    相关资源
    最近更新 更多