Saturday, August 14, 2010

Handling single keyboard strokes in XNA

In a game, there are times where you need to handle single key strokes, rather than repeating ones. Examples are of a Pause key or a 'Press any key to start' scenario.

Unfortunately, XNA does not directly offer this functionality.

Therefore I wrote this very simple event-driven class that does exactly that:

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace XNASingleStroke
{
    public class SingleKeyStroke : GameComponent
    {
        public event EventHandler<KeyDownEventArgs> KeyDown = delegate { };

        private int pressedKeys;
        public SingleKeyStroke(Game game) : base(game) { }

        public override void Update(GameTime gameTime)
        {
            var pressed = Keyboard.GetState().GetPressedKeys();
            var keys = 0;
            foreach (var key in pressed)
            {
                var num = 1 << (int)key;
                keys |= num;
                if ((pressedKeys & num) != num)
                {
                    KeyDown(this, new KeyDownEventArgs(key));
                }
            }
            pressedKeys = keys;
            base.Update(gameTime);
        }
    }
}

And this is KeyDownEventArgs that's used in the event handler:

using System;
using Microsoft.Xna.Framework.Input;

namespace XNASingleStroke
{
    public class KeyDownEventArgs:EventArgs
    {
        public Keys Key { get; set; }
        public KeyDownEventArgs(Keys key)
        {
            Key = key;
        }
    }
}

Usage is also very simple:

protected override void Initialize()
{
    // ...
    SingleKeyStroke singleStroke = new SingleKeyStroke(this); //where 'this' is your Game
    singleStroke.KeyDown += (o, e) => {
        switch (e.Key)
        {
            case Keys.Space:Console.WriteLine("Space was pressed"); break;
            case Keys.Enter:Console.WriteLine("Enter was pressed"); break;
        }
   };
   Components.Add(singleStroke);
}