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

      

+1


source to share


3 answers


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.

+3


source


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.

0


source


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.

0


source







All Articles