Stopping keys from repeating (C #)
In this application, I need to be able to stop the response from the key being held in order to prevent invalid input. The problem I am facing is that using the methods in my code below prevents keys from being repeated, but also prevents them from being responsive enough - since users are quickly pressing keys.
I'm not sure if this is my hardware, api limitation, or a problem with my code, but the subroutines I have below are not just quick to work without making the program impossible to use. A way of determining if a key is being actively held (and for how long) will also help another feature for that program and fix this problem.
Any ideas?
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = isKeyDown;
isKeyDown = true;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
isKeyDown = false;
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!isStreamPlaying) return;
if (e.KeyChar.Equals('d') || e.KeyChar.Equals('j'))
{
//red hit
SoundPlayer hitSounds = new SoundPlayer(taikoLiveMapper.Properties.Resources.normal_hitnormal);
hitSounds.Play();
outputlist.Add(string.Format("320,240,{0},1,{1}", ms, 0));
lastms = ms;
}
else if (e.KeyChar.Equals('s') || e.KeyChar.Equals('k'))
{
//blue hit
SoundPlayer hitSounds = new SoundPlayer(taikoLiveMapper.Properties.Resources.normal_hitclap);
hitSounds.Play();
outputlist.Add(string.Format("320,240,{0},1,{1}", ms, 8));
lastms = ms;
}
}
You can use GetKeyState to find out if a key is off and use it to keep track of the keys:
[DllImport("user32.dll")]
static extern short GetKeyState(int key);
static bool IsKeyPressed(Keys key)
{
short state = GetKeyState((int)key);
return ((state & 128) != 0);
}
int i = 0;
Dictionary<Keys, DateTime> downSince = new Dictionary<Keys, DateTime>();
private void UpdateKeyStates()
{
foreach (var entry in downSince.ToArray())
{
if (!IsKeyPressed(entry.Key))
downSince.Remove(entry.Key);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
UpdateKeyStates();
if (!downSince.ContainsKey(e.KeyCode))
{
downSince.Add(e.KeyCode, DateTime.UtcNow);
i++;
}
Text = i.ToString() + " " +(int)(DateTime.UtcNow - downSince[e.KeyCode]).TotalMilliseconds;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
UpdateKeyStates();
}
This example counts i
each time a key is pressed and shows how long it was pressed. It uses GetKeyState instead of keeping track of KeyDown / KeyUp as you can skip these messages if something else has focus.
Use timers instead: initialize the timers, one for each "action" (for example by pressing d / j or s / k) move the red / blue beat code inside the timer and do the following instead of the current code:
if (e.KeyChar.Equals('d') || e.KeyChar.Equals('j'))
{
//red hit
if (!tmrRedHit.Enabled)
tmrRedHit.Enabled = true;
}
else if (e.KeyChar.Equals('s') || e.KeyChar.Equals('k'))
{
//blue hit
if (!tmrBlueHit.Enabled)
tmrBlueHit.Enabled = true;
}
And in timers Elpased event will also set Enabled to false
after code execution.
According to the documentation , "[d] KeyDown up events occur every time a key is repeated if a key is held down, but only one KeyUp event is generated when the user releases the key."
Thus, the simplest solution is to ignore the repeated KeyDown event if its corresponding KeyUp event was not noticed.
Just worked for me.