开发者

Stopping keys from repeating (C#)

In this application, I need to be able to stop the response from a key which is held down in order to prevent unnessecary data from entering the output. The problem I'm having is, using the methods in my code below does prevent the keys from repeating, but it also stops them from being responsive enough - as the users are hitting the keys very quickly.

I'm not sure if it's my hardware, api restriction or a problem with my code, but the routines I have below do not simply come round fast enough to work without making the program impossible to use. A way of identifying if a key is being actively held down (and for how lon开发者_Go百科g) would also help another feature for the program and solve this current issue.

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 down and use that to track 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 up every time a key is pressed, and shows for how long it has been pressed. It uses GetKeyState instead of tracking KeyDown/KeyUp since you might miss those messages if something else has focus.


According to the documentation, "[d]uplicate 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."

So the simplest solution is to ignore a repeated KeyDown event unless its corresponding KeyUp event has been seen.

Just worked for me.


Use Timers instead: initialize timers, one for each "action" (e.g. pressing d/j or s/k) move the red hit/blue hit code inside the timer and instead of your current code, have this:

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 the timers Elpased event also set their Enabled to false after the code is executed.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜