MartyIX
MartyIX

Reputation: 28648

How can I get rid of character repeat delay in C#?

http://www.microsoft.com/windowsxp/using/accessibility/characterrepeatrate.mspx - There's an option in Windows for setting repeat delay. It means the delay between first keystroke and the other ones if one keeps pressing the key. I'm creating a sort of game and I need to get rid of this "feature".

So far I've managed to find this method:



[DllImport("user32.dll")]
static extern ushort GetAsyncKeyState(int vKey);

public static bool IsKeyPushedDown(Keys keyData)
{
   return 0 != (GetAsyncKeyState((int)keyData) & 0x8000);
}

But the method IsKeyPushedDown finds out if the key is pressed AT THE MOMENT of calling the function - so I need a loop to test if key is down. Problem is that still it doesn't catches all keystrokes - I have too slow loop I guess.

Second choice is overriding of ProcessCmdKey:


protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
  // processing keys
            if (keyData == Keys.Left || keyData == Keys.Right || keyData == Keys.Up || keyData == Keys.Down)
            {
                return true;
            }
            else
            {
                return base.ProcessCmdKey(ref msg, keyData);
            }

}

this works really good but it's affected with repeat delay and therefore movement of my monster in my game is like:

Is there a solution for my problem? Thanks

EDIT: I solved the problem by combining both procedures. But it's very ugly solution. I still hope there's better solution.

Upvotes: 1

Views: 5923

Answers (2)

Goodies
Goodies

Reputation: 2069

I don't like timers and pInvoke.

In a WinForms program I solved unwanted key repeat as follows

    List<Keys> cKeys = new List<Keys>() { Keys.Q, Keys.W, Keys.E, Keys.R,
       Keys.T, Keys.Y, Keys.U, Keys.I, Keys.O, Keys.P, 
       Keys.OemOpenBrackets, Keys.OemCloseBrackets };  // define relevant keys
  
    Keys keepc = Keys.IMENonconvert; // some key which is not relevant

    private void Form2_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode!=keepc) // repeater detect
        {
            keepc = e.KeyCode;
            if (cKeys.IndexOf(e.KeyCode) >= 0) // if relevant key..
            {
                // do press key action
            }
        }         
    }

    private void Form2_KeyUp(object sender, KeyEventArgs e)
    { 
        keepc = Keys.IMENonconvert; // reset the repeater detect
        if (cKeys.IndexOf(e.KeyCode) >= 0) // if relevant key..
        {
            // do release key action
        }
    }

Upvotes: 0

Adam Robinson
Adam Robinson

Reputation: 185613

You should be handling KeyDown and KeyUp rather than ProcessCmdKey if you want greater control over what happens between the time a key is pressed and released.

The absolute easiest thing to do in your scenario would be to have a timer on your form that moves the monster. Enable the timer (and set some sort of variable or deltaX and deltaY that indicates how to move the monster) when KeyDown is fired, then stop the timer when KeyUp is fired.

Edit

As an example (very barebones)

public class MyForm : Form
{
    private int deltaX;
    private int deltaY;

    private const int movementAmount = 10;

    private Timer movementTimer = new Timer();

    public MyForm()
    {
        movementTimer.Interval = 100; // make this whatever interval you'd like there to be in between movements

        movementTimer.Tick += new EventHandler(movementTimer_Tick);
    }

    void movementTimer_Tick(object sender, EventArgs e)
    {
        myMonster.Location = new Point(myMonster.X + deltaX, myMonster.Y + deltaY);
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);

        switch (e.KeyCode)
        {
            case Keys.Left:
                {
                    deltaX -=movementAmount;
                } break;
            case Keys.Right:
                {
                    deltaX += movementAmount;
                } break;
            case Keys.Up:
                {
                    deltaY -= movementAmount;
                } break;
            case Keys.Down:
                {
                    deltaY += movementAmount;
                } break;
        }

        UpdateTimer();
    }

    protected override void OnKeyUp(KeyEventArgs e)
    {
        base.OnKeyUp(e);

        switch (e.KeyCode)
        {
            case Keys.Left:
                {
                    deltaX += movementAmount;
                } break;
            case Keys.Right:
                {
                    deltaX -= movementAmount;
                } break;
            case Keys.Up:
                {
                    deltaY += movementAmount;
                } break;
            case Keys.Down:
                {
                    deltaY -= movementAmount;
                } break;
        }

        UpdateTimer();
    }

    private void UpdateTimer()
    {
        movementTimer.Enabled = deltaX != 0 || deltaY != 0;
    }
}

Upvotes: 5

Related Questions