XNA Game Engine Tutorial Series #6 – Input
In this tutorial we are going to be building an input system for our engine. This system will support the Xbox 360 game pad, keyboard, and mouse, but could be extended to support most if not all other types of devices (assuming you know how to interface with the device, as XNA doesn’t provide support for any other devices directly).
The structure will be as follows:
InputDevice: The InputDevice class is the base class for input devices. An input device is the interface between the engine/game and the device itself. It keeps track of a state object and provides functions for getting data from the device.
The input devices we will be building are MouseDevice, KeyboardDevice, and GamePadDevice.
First, however, I want to discuss what are called “Generics”. A generic is a way for us to tell C# that our class or function can handle multiple types. A Type is a class that contains info about a class. You can get an object’s Type using MyObject.GetType(). You can get the Type of a class using typeof(ClassName). An example of a function that uses generics is XNA’s “Content.Load()” function. Since it can load multiple data types, it uses a generic to tell what kind of Type it returns. This is why we load textures using
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class ExampleClass <T, R> { public T ReturnVariableT() { T object = new T(); return T; } public R ReturnVariableR() { R object = new R(); return T; } } |
Here is the code for the InputDevice class. It’s not very complex, since all the base class does is maintain a state object.
1 2 3 4 5 6 7 8 | // The base input device class. Other input device types will // inherit from it. The <T> generic allows us to specify what // type of input device state it manages. (MouseState, etc.) public abstract class InputDevice <T> : Component { // The State object of type T specified above public abstract T State { get; } } |
We will also need to create two classes: an event argument class and event handler class, which will be used for events relating to input (like button pressed, button up, etc).
Before we get to that, however, I want to quicly discuss events. An event is exactly what it sounds like, we can define events that other classes can “hook”, by specifying a method for C# to call when the event is triggered by the owner of the event.
We create an event like this:
1 | public event EventHandler ExampleEvent; |
The “EventHandler” part of the declaration tells C# what kind of method is allowed to hook an event. EventHandler is just a delegate that accepts a few specific arguments. A delegate, in this case, is just a way of defining the type of method we want. For example, an event that specifies the EventHandler event handler will only be hooked by methods of the following format:
1 2 3 | void FunctionToCallWhenEventIsFired(object sender, EventArgs e) { } |
We would then hook it like this:
1 | EventOwner.ExampleEvent += new EventHandler(FunctionToCallWhenEventIsFired); |
Now, if EventOwner fires ExampleEvent, FunctionToCallWhenEventIsFired would be called and passed the object that called it as “object sender” and the data about the event in “EventArgs e”.
We can create our own class that inherits from “EventArgs” to pass our own data to the event handler. We would then need to create our own EventHandler delegate that accepts the custom event arguments class. For example, our event arguments class and event handler class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // An input device event argument class that can handle events // for several types of input device. "O" specified what type // of object the event was triggered by (Key, Button, // MouseButton, etc). "S" specifies the type of state the // event provides (MouseState, KeyboardState, etc.) public class InputDeviceEventArgs<O, S> : EventArgs { // The object of type O that triggered the event public O Object; // The input device that manages the state of type S that // owns the triggered object public InputDevice<S> Device; // The state of the input device of type S that was triggered public S State; // Constructor takes the triggered object and input device public InputDeviceEventArgs(O Object, InputDevice<S> Device) { this.Object = Object; this.Device = Device; this.State = ((InputDevice<S>)Device).State; } } // An input device event handler delegate. This defines what type // of method may handle an event. In this case, it is a void that // accepts the specified input device arguments public delegate void InputEventHandler<O, S>(object sender, InputDeviceEventArgs<O, S> e); |
So, lets start with KeyboardDevice. Here’s the class definition, as you can see we specify that KeyboardDevice keeps track of a KeyboardState object.
1 2 3 4 5 6 7 8 9 10 | using Microsoft.Xna.Framework.Input; using System; namespace Innovation { // An input device that manages the Keyboard and KeyboardState public class KeyboardDevice : InputDevice<KeyboardState> { } } |
Now we are going to add several members, properties, and events. They should be self explanatory:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // The last and current KeyboardStates KeyboardState last; KeyboardState current; // The keys that were pressed in the current state Keys[] currentKeys; // Public properties for the above members public override KeyboardState State { get { return current; } } public Keys[] PressedKeys { get { return currentKeys; } } // Events for when a key is pressed, released, and held. This // event can be handled by our InputEventHandler class. public event InputEventHandler<Keys, KeyboardState> KeyPressed; public event InputEventHandler<Keys, KeyboardState> KeyReleased; public event InputEventHandler<Keys, KeyboardState> KeyHeld; |
Now the constructor:
1 2 3 4 5 6 7 | // Constructor sets up the current state and updates for the // first time public KeyboardDevice() { current = Keyboard.GetState(); Update(); } |
Now the Update() method. We start by updating the keyboard states:
1 2 3 4 5 6 7 8 9 10 11 | public override void Update() { // Set the last state to the current one and update the // current state last = current; current = Keyboard.GetState(); // Set the currently pressed keys to the keys defined in // the current state currentKeys = current.GetPressedKeys(); } |
Now we will check if our events need to be fired, then fire them if neccessary. We will write the functions that check for the various cases (button up, down, etc.).
First we need to create a class that will allow us to enumerate over the values of an enum, in a foreach loop. We can do this on Windows using Enum.GetValues(), but this isn’t provided in the .Net Compact Framework on Xbox and Zune, so we need to create our own. Add a new static class called Util, and add the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | using System; using System.Collections.Generic; using System.Reflection; namespace Innovation { public static class Util { public static List<T> GetEnumValues<T>() { Type currentEnum = typeof(T); List<T> resultSet = new List<T>(); if (currentEnum.IsEnum) { FieldInfo[] fields = currentEnum.GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo field in fields) resultSet.Add((T)field.GetValue(null)); } else throw new ArgumentException("The argument must of type Enum or of a type derived from Enum", "T"); return resultSet; } } } |
Now we can go through the values of an enum like this:
1 2 3 4 5 | Enum ExampleEnum { One, Two, Three }; foreach(ExampleEnum value in Util.GetEnumValues<ExampleEnum>() { } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // For every key on the keyboard... foreach (Keys key in Util.GetEnumValues<Keys>()) { // If it is a new key press (this is the first frame // it is down), trigger the corresponding event if (WasKeyPressed(key)) if (KeyPressed != null) KeyPressed(this, new InputDeviceEventArgs <Keys, KeyboardState>(key, this)); // If it was just released (this is the first frame // it is up), trigger the corresponding event if (WasKeyReleased(key)) if (KeyReleased != null) KeyReleased(this, new InputDeviceEventArgs <Keys, KeyboardState>(key, this)); // If it has been held (it has been down for more // than one frame), trigger the corresponding event if (WasKeyHeld(key)) if (KeyHeld != null) KeyHeld(this, new InputDeviceEventArgs <Keys, KeyboardState>(key, this)); } |
Now we will write the functions that check for various states (button up, down, held, released, and pressed):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // Whether the specified key is currently down public bool IsKeyDown(Keys Key) { return current.IsKeyDown(Key); } // Whether the specified key is currently up public bool IsKeyUp(Keys Key) { return current.IsKeyUp(Key); } // Whether the specified key is down for the first time // this frame public bool WasKeyPressed(Keys Key) { if (last.IsKeyUp(Key) && current.IsKeyDown(Key)) return true; return false; } // Whether the specified key is up for the first time // this frame public bool WasKeyReleased(Keys Key) { if (last.IsKeyDown(Key) && current.IsKeyUp(Key)) return true; return false; } // Whether the specified key has been down for more than // one frame public bool WasKeyHeld(Keys Key) { if (last.IsKeyDown(Key) && current.IsKeyDown(Key)) return true; return false; } |
The MouseDevice and GamepadDevice classes work similarly, so I will link to the files instead of posting the whole thing:
MouseDevice.cs
GamepadDevice.cs
And thats all there is to it! So, for example, if you wanted to monitor the keyboard and mouse, you would create instances of KeyboardDevice and MouseDevice in your game:
1 2 | MouseDevice mouse = new MouseDevice(); KeyboardDevice keyboard = new KeyboardDevice(); |
Then to monitor them, add them add services so you can access them elsewhere:
1 2 | Engine.Services.AddService(typeof(MouseDevice), mouse); Engine.Services.AddService(typeof(KeyboardDevice), keyboard); |
For example, to spawn the box to tip the others over when the mouse button is pressed, change the box spawn code in the update method to the following:
1 2 3 4 5 6 7 8 9 10 | if (Engine.Services.GetService<MouseDevice>().WasButtonPressed(MouseButtons.Left)) { PhysicsActor act = new PhysicsActor( Engine.Content.Load<Model>("Content/ig_box"), new BoxObject(new Vector3(1), new Vector3(0, .5f, 1), Vector3.Zero)); act.Scale = new Vector3(1); act.PhysicsObject.Mass = 1000; act.PhysicsObject.Velocity = new Vector3(0, 2, -6); } |
We now have a full input system. Other devices could be built to monitor other device types, such as the guitar, or zune input panel, or an input type that XNA doesn’t support at all.
Download the Code for this Chapter
Back to Game Engine Tutorial Series

Tags:
Sean
24 Responses to “XNA Game Engine Tutorial Series #6 – Input”
November 16, 2008 at 2:27 am
[...] Independent game development blog by Sean James. About · Forums · XNA Game Engine Tutorial Series. Recent Posts Read more [...]
November 16, 2008 at 7:51 am
Sean, Thanks for the new addition. I’ve been programming XNA for the past couple months and have learned the most from your series. Keep up the great work!!
November 16, 2008 at 2:45 pm
im having trouble (possibly my own fault), im targetting the 360 and Enum.GetValues doesn’t seem to exist
November 16, 2008 at 2:50 pm
Looks like the source code file is messed up.. Thanks for the great series!
November 16, 2008 at 3:12 pm
The Enum class is part of the System namespace and is not in source form…
may be that its not part of the compact framework the 360 uses
November 16, 2008 at 7:28 pm
Correct, the compact framework does not support this. I’ll be posting a work-around for this shortly.
November 17, 2008 at 7:22 pm
I can’t download the Code for this Chapter. it may just be me but I think you just uploaded and empty zip file. it doesn’t have anything inside the folder.
November 17, 2008 at 7:57 pm
[...] XNA Game Engine Tutorial Series #6 – Input | Innovative Games [...]
November 17, 2008 at 9:18 pm
Source code is fixed
November 19, 2008 at 11:00 am
It seems the source code has some stuff from the next tutorial on cameras mixed with it.
Thanks for your great tutorials btw
November 21, 2008 at 11:55 pm
[...] how to interface with the device, as XNA doesn’t provide support for any other devices directly). XNA Game Engine Tutorial Series #6 – Input Quick Update XNA Game Engine Tutorial Series #5 – [...]
November 24, 2008 at 1:13 pm
Hey,
Another great tutorial – hope the next one is soon out! Sorry to be pointing out another error but I think you might have copied in some wrong info just after your edit (or is it supposed to use the MouseButtons in the Keyboard device?)
Can you drop any clues on what the next tutorial is gonna be on?
Thanks for great stuff so far!
December 1, 2008 at 7:40 am
Yeah it appears it should be
foreach(Keys key in Util.GetEnumValues())
December 1, 2008 at 7:41 am
crap.. I got owned..
foreach (Keys keys in Util.GetEnumValues[Keys]())
(replace ‘[' and ']‘ with < and >
December 1, 2008 at 7:42 am
lol, got owned again…
foreach (Keys key in Util.GetEnumValues<Keys>())
(3rd time’s the charm)
December 16, 2008 at 2:05 pm
I have a question…
How would you create a text box input with this input system?
December 16, 2008 at 2:31 pm
You would need to have a texture for the box and a spritefont for the text. Then you would have a string to represent the text that has been entered. In the draw function, you would draw the textbox texture, then draw the entered text with the spritefont on top of the box. Then hook the KeyDown event of a KeyboardDevice, and in the event handler add the pressed key to the entered text string. Of course, you would only want to do this when the box is ‘active’, ie when it is clicked on or tabbed into. Then when you are ready to use the text, just use the string of entered text.
December 16, 2008 at 5:36 pm
alright, thanks i understand the basic concept behind it i was wondering more a long the lines of hooking the event to an event handler.
would that look somthing like this?
Engine.Services.GetService().IsPressed += new InputEventHandler(EnterText);
void EnterText(object sender, InputDeviceEventArgs e)
{
stringToOutput += e.State.GetPressedKeys().ToString();
}
thanks
December 16, 2008 at 5:55 pm
Yes, thats how it would look. Also, the activated object (whether it be a Key, GamePadButtons, etc) is available from the property called ‘Object’ which, in this case, is a ‘Key’, in the event args. So you could just do stringToOutput += e.Object.ToString();.
January 19, 2009 at 11:43 pm
Hi there and thanks for the great article! I have a question regarding this snippet from the InputDeviceEventArgs class:
this.State = ((InputDevice)Device).State;
why do we have to cast Device.State into InputDevice when it is already declared as of type InputDevice in the function arguments? Thanks in advance~
January 20, 2009 at 7:31 am
You don’t have to, I did just to make it clearer what we are doing.
June 23, 2009 at 2:15 pm
Hi there. Thanks for the articles, they are a great help.
I have a question about the getservice call. How fast is it? I see you are using it in your update functions a lot.
June 23, 2009 at 3:14 pm
It’s fast enough that you don’t have to worry about how fast it is
It’s pretty much just calling the retrieve function in a dictionary contained in Engine.Services.
June 24, 2009 at 11:43 pm
I am running up to this chapter on the 360. Works like a charm. Except that when I “fire” it adds the last of the 9 boxes and knocks them over.
Also when I “fire” alot of boxes I get a performance drop really fast.
Is this caused by the physics?
boxes spawn inside eachother so I guess it causes quite some collisions?