views:

232

answers:

3

when we press a key and keep pressing it the keypress and keydown event continuously fires. Is there a way to let these fire only after a complete cycle ,eg keydown and then key up.

I would like the user not to be able press the key continuously rather would like the user have to press then release the key board to type a character !

so that following case do not occur eg : pppppppppppppppppppppppp when user presses 'p' for 1 sec.

+5  A: 

Declare a boolean isKeyDown, in theKeyDown Event, set the boolean to true. In the KeyUp event, set the boolean to false.

This is sample code

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. 
}
Ngu Soon Hui
As the poster stated, both events fire (keyDown followed by keyUp) even when it's a key that's repeating
iAn
@iAn: that's not true. you get repeated keydowns, but only one keyup.
John Knoeller
@iAn: MSDN says otherwise: "The KeyDown event occurs when the user presses any key. The KeyUp event occurs when the user releases the key. Duplicate KeyDown events occur each time the key repeats, if the key is held down, but only one KeyUp event is generated when the user releases the key."
nikie
@Ngu Unfortunately, neither your code above, or even setting e.Handled = true in a KeyEvent Handler will prevent multiple characters from being entered as long as the key as held down (in a TextBox, for example).
BillW
@BillW, what do you mean? You could have do the data entry code after the `isKeyDown=true` statement.
Ngu Soon Hui
@Ngu Just take your code, wire it up to a TextBox's KeyDown and KeyUp events in a WinForm project, then run the code : you will observe that holding the key down results in multiple characters being entered after a short delay. Your code does not prevent multiple repeats.
BillW
+1  A: 

To prevent a key from firing multiple-times when held down : you must use the SuppressKeyPress property like so :

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

See : KeyEventArgs..::.Handled Property ... and ... KeyEventArgs..::.SuppressKeyPress Property .... for relevant information

BillW
Sounds about right.
If you set a Form's 'KeyPreview to 'true, and use the same code (above) in the Form's KeyDown and KeyUp handlers: all TextBoxes on that Form will have key-repeat suppressed. I have not tested it on other controls than TextBoxes. The fact that Nobugz (who's damn smarter than I am) gave an answer below suggests this code, even on a Form level would not prevent key-repeat in some other condition I am not aware of.
BillW
+1  A: 

You can do it application-wide by filtering the key down messages with IMessageFilter. Here's an example:

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

One thing I pursued is the repeat count in the WM_KEYDOWN message. Oddly this didn't work on my machine, it was 1 for repeating keys. Not sure why.

Hans Passant
@nobugz +1 I always learn a lot from your answers ! Very interesting stuff going on above with removing the MessageFilter on Form Closed. I'm guessing that you go "this deep" in your answer to cover every possible case of control input ? I assume there is no way to handle this on an Application-wide basis that would be independent of any Form(s) ?
BillW
@BillW: Thanks! This is application-wide, IMessageFilter operates for all forms. If it should only operate for one form then this is not the right solution. I assume this is some kind of gaming app so it should be okay.
Hans Passant
@nobugz Of course, I can now see it's Application wide and wonder how I missed seeing that to begin with :)
BillW